Durchschnittswerte (row, col) cell gegebene Array-Werte als Gewichte erhalten?

Ich versuche, die durchschnittliche Zeile/Spalte Position mit den Array-Werten als Gewichte zu erhalten. Das scheint zu funktionieren, fühlt sich aber einfach falsch an:

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))

Gibt es einen effizienteren Weg, um dies in numpiger Weise zu tun?

0

2 Antworten

Diese scheinen ein bisschen besser zu sein:

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)

Die Ergebnisse auf meinem Computer:

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

Ich habe einige der Indextricks von numpy benutzt, um die Berechnung zu vektorisieren. Ich bin eigentlich etwas überrascht, dass wir es nicht besser gemacht haben. np.ogrid ist nur etwa doppelt so schnell wie das Original auf Ihrer Testmatrix. np.mgrid liegt irgendwo dazwischen.

0
hinzugefügt

Eine grundlegende Erkenntnis zur Beschleunigung Ihrer Berechnung besteht darin, dass bei der Berechnung von Zeilen (Spalten) alle Elemente in derselben Spalte (Zeile) mit dem gleichen Wert multipliziert werden, sodass sie schneller addiert werden und das Ergebnis dann mit multipliziert wird die Zeilen- (Spalten-) Nummer. Wenn Ihr Array m x n ist, reduziert dies die Anzahl der Multiplikationen, die Sie von 2 * m * n zu m + n durchführen müssen. Und da Sie Multiplikationen und Additionen durchführen, können Sie np.dot verwenden, um zu versuchen, das letzte bisschen Leistung zu scratchen. Aufbauend auf den @ mgilson-Tests:

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

Und das sind meine Ergebnisse und Timings:

(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
hinzugefügt
Gut gemacht. +1 von mir - Obwohl, ich muss sagen, ich bin ein bisschen enttäuscht. Ich dachte, meine Antwort war ziemlich gut, bis ich das hier sah ...
hinzugefügt der Autor mgilson, Quelle
Mine ist eine Linux-Maschine mit freundlicher Genehmigung meines Arbeitgebers :)
hinzugefügt der Autor mgilson, Quelle
Scheint, diese Frage bringt nur Trauer zu den Befragten, denn ich bin auch nicht sehr glücklich: "Lieber Weihnachtsmann, ich war dieses Jahr ein sehr guter Junge, bring mir bitte einen PC wie @mgilson, der doppelt so schnell läuft wie meiner. . ";-)
hinzugefügt der Autor Jaime, Quelle