2013-12-17 4 views
1

Я пытаюсь получить среднее положение строки/столбца, используя значения массива как веса. Это похоже на работу, но просто чувствует себя неправильно:получать средние значения (строки, столбца) заданных значений массива как веса?

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

Есть ли более эффективный способ сделать это в NumPy?

ответ

2

Основой для ускорения вашего расчета является то, что при выполнении вычислений строк (столбцов) все элементы в одном столбце (строке) умножаются на одно и то же значение, они будут быстрее добавлять их вместе, затем умножьте результат на число строк (столбцов). Если ваш массив равен m x n, это уменьшает количество умножений, которое вы должны сделать от 2 * m * n до m + n. И поскольку вы делаете умножения и дополнения, вы можете использовать np.dot, чтобы попытаться поцарапать последний бит производительности. Основываясь на тестах @ 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 

И вот мои результаты и тайминги:

(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 
+1

Молодцы. +1 от меня. Хотя, я должен сказать, я немного разочарован. Я думал, что мой ответ был довольно хорош, пока я не увидел этот ... – mgilson

+1

Кажется, этот вопрос только приносит горе тоже респондентам, потому что я тоже не очень доволен: «Дорогой Санта, я был очень хорошим мальчиком в этом году, пожалуйста, принесите мне такой ПК, как @ mgilson's, который работает в два раза быстрее, чем у меня ... »;-) – Jaime

+0

Mine - это Linux-машина, любезно предоставленная моим работодателем :) – mgilson

1

Это, кажется, немного лучше:

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) 

Результатов на моем компьютере:

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

я использовал некоторые трюки индекса Numpy для векторизации вычисления. Я на самом деле немного удивлен, что мы не сделали лучше. np.ogrid примерно в два раза быстрее, чем оригинал на тестовой матрице. np.mgrid находится где-то посередине.

Смежные вопросы