obtener celdas promedio (fila, col) dados valores de matriz como ponderaciones?

Estoy tratando de obtener la posición promedio de fila/col usando los valores de matriz como los pesos. Esto parece funcionar, pero simplemente se siente mal:

a = numpy.random.ranf(size=(5,5))
normalized_a = a/numpy.nansum(a)

row_values = []
col_values = []
for row, col in numpy.ndindex(normalized_a.shape):
    weight = int(normalized_a[row, col] * 100)
    row_values.extend([row] * weight)
    col_values.extend([col] * weight)

print "average row:", sum(row_values)/float(len(row_values))
print "average col:", sum(col_values)/float(len(col_values))

¿Hay una manera más eficiente de hacer esto en numpy?

0

2 Respuestas

Estos parecen ser un poco mejores:

import numpy

a = numpy.random.ranf(size=(5,6))
normalized_a = a/numpy.nansum(a)

def original(a, normalized_a):
  row_values = []
  col_values = []
  for row, col in numpy.ndindex(normalized_a.shape):
    weight = int(normalized_a[row, col] * 100)
    row_values.extend([row] * weight)
    col_values.extend([col] * weight)

  return sum(row_values)/float(len(row_values)), sum(col_values)/float(len(col_values))


def new(a, normalized_a):
  weights = numpy.floor(normalized_a * 100)
  nx, ny = a.shape
  rows, columns = numpy.mgrid[:nx, :ny]
  row_values = numpy.sum(rows * weights)/numpy.sum(weights)
  col_values = numpy.sum(columns * weights)/numpy.sum(weights)
  return row_values, col_values


def new2(a, normalized_a):
  weights = numpy.floor(normalized_a * 100)
  nx, ny = a.shape
  rows, columns = numpy.ogrid[:nx, :ny]
  row_values = numpy.sum(rows * weights)/numpy.sum(weights)
  col_values = numpy.sum(columns * weights)/numpy.sum(weights)
  return row_values, col_values


print original(a, normalized_a)
print new(a, normalized_a)
print new2(a, normalized_a)


print "timing!!!"

import timeit
print timeit.timeit('original(a, normalized_a)', 'from __main__ import original, a, normalized_a', number=10000)
print timeit.timeit('new(a, normalized_a)', 'from __main__ import new, a, normalized_a', number=10000)
print timeit.timeit('new2(a, normalized_a)', 'from __main__ import new2, a, normalized_a', number=10000)

Los resultados en mi computadora:

(1.8928571428571428, 2.630952380952381)
(1.8928571428571428, 2.6309523809523809)
(1.8928571428571428, 2.6309523809523809)
timing!!!
1.05751299858
0.64871096611
0.497050046921

Usé algunos de los trucos de índice de numpy para vectorizar el cálculo. De hecho, estoy un poco sorprendido de que no hayamos mejorado. np.ogrid es solo aproximadamente el doble de rápido que el original en su matriz de prueba. np.mgrid se encuentra en algún punto intermedio.

0
agregado

Una idea básica para acelerar su cálculo es que, al hacer cálculos de filas (columna), todos los elementos en una misma columna (fila) se multiplican por el mismo valor, será más rápido agregarlos juntos, luego multiplicar el resultado por el número de fila (columna). Si su matriz es m x n , eso reduce el número de multiplicaciones que tiene que hacer desde 2 * m * n a m + n . Y como está haciendo multiplicaciones y adiciones, puede usar np.dot para tratar de borrar el último bit de rendimiento. Basándose en las pruebas de @ mgilson:

def new3(normlized_a):
    weights  = numpy.floor(normalized_a * 100)
    total_wt = np.sum(weights)
    rows, cols = weights.shape
    row_values = np.dot(weights.sum(axis=1), np.arange(rows))/total_wt
    col_values = np.dot(weights.sum(axis=0), np.arange(cols))/total_wt
    return row_values, col_values

Y estos son mis resultados y tiempos:

(1.8352941176470587, 2.388235294117647)
(1.8352941176470587, 2.388235294117647)
(1.8352941176470587, 2.388235294117647)
(1.8352941176470587, 2.388235294117647)
timing!!!
2.59478258085
1.33357909978
1.0771122333
0.487124971828 #new3
0
agregado
Bien hecho. +1 de mí - Aunque, debo decir, estoy un poco decepcionado. Pensé que mi respuesta era bastante buena hasta que vi esta ...
agregado el autor mgilson, fuente
La mía es una máquina linux cortesía de mi empleador :)
agregado el autor mgilson, fuente
Parece que esta pregunta solo trae dolor a los encuestados, porque tampoco estoy muy feliz: "Querido Santa, este año he sido un muy buen muchacho, por favor tráeme una PC como la de @ mgilson, que corre dos veces más rápido que la mía ... . ";-)
agregado el autor Jaime, fuente