2015-02-05 3 views
0

Я совершенно новый для numpy и не могу найти решение. У меня есть 2d список чисел с плавающей запятой в Python, как:Numpy: 2d list min max is slow

list1[0..8][0..2] 

Где например:

print(list1[0][0]) 
> 0.1122233784 

Теперь я хочу, чтобы найти минимальное и максимальное значения:

b1 = numpy.array(list1) 
list1MinX, list1MinY, list1MinZ = b1.min(axis=0) 
list1MaxX, list1MaxY, list1MaxZ = b1.max(axis=0) 

мне нужно сделать это примерно миллион раз в цикле.

Он работает правильно, но это примерно в 3 раза медленнее, чем мой предыдущий подход на основе python.

(1:15 мин [NumPy] против 0:25 мин [родной])

Что я делаю неправильно? Я читал, что преобразование списка может быть проблемой, но я не знаю, как это сделать лучше.

EDIT

По просьбе некоторых не-псевдо-код, хотя в моем сценарии список создается по-другому.

import numpy 
import random 

def moonPositionNow(): 
    #assume we read like from a file, line by line 
    #nextChunk = readNextLine() 
    #the file is build like this 
    #x-coord 
    #y-coord 
    #z-coord 
    #x-coord 
    #... 
    #but we don't have that data here, so as a **placeholder** we return a random number 
    nextChunk = random.random() 
    return nextChunk 

for w in range(1000000):   
    list1 = [[moonPositionNow() for i in range(3)] for j in range(9)] 
    b1 = numpy.array(list1) 
    list1MinX, list1MinY, list1MinZ = b1.min(axis=0) 
    list1MaxX, list1MaxY, list1MaxZ = b1.max(axis=0)   

#Print out results 

Хотя создание списка может быть шеей бутылки здесь, я гарантирую исходный код, это не проблема.

EDIT2:

Обновлен пример кода для уточнения, я не нужен Numpy массив случайных чисел.

+1

Почему бы не использовать нативный подход? И могли бы вы предоставить какой-нибудь гибкий тестовый код для нас? – Gullydwarf

+0

Целью использования numpy было ускорение кода. Нативный код довольно оптимизирован, но я думал, что numpy может выжать немного больше. – bortran

ответ

1

Поскольку ваши данные доступны в виде списка Python кажется разумным мне, что родная реализация (который, вероятно, вызывает некоторый оптимизированный код C) может быть быстрее, чем преобразование в Numpy первыми и последующего вызов оптимизированного кода C.

Вы в основном перебираете свои данные дважды: один раз для преобразования объектов python в массивы numpy и один раз для вычисления максимального или минимального значения. Натуральная реализация (я предполагаю, что это что-то вроде вызова min/max в списке Python) нужно только перебирать данные один раз.

Кроме того, кажется, мин/макс функции, Numpy на удивление медленно: https://stackoverflow.com/a/12200671/3005167

+0

Думаю, ты прав. Я имею в виду, что это даже не вызов кода C, я просто вычисляю min и max фактически 2 списков (извините, не упоминал) и все 3 измерения в одном цикле, которые я также могу свести к n-1, назначив первое значение список мин/макс. Это против 2x преобразования + 2x np.min/np.max для 3-х измерений. – bortran

1

Проблема возникает из-за того, что вы передаете список python в функцию numpy. Функция numpy значительно быстрее, если вы передаете массив numpy в качестве аргумента.

#Create numpy numbers 
nptest = np.random.uniform(size=(10000, 10)) 
#Create a native python list 
listtest = list(nptest) 
#Compare performance 
%timeit np.min(nptest, axis=0) 
%timeit np.min(listtest, axis=0) 

Выход

1000 loops, best of 3: 394 µs per loop 
100 loops, best of 3: 20 ms per loop 

EDIT: Добавлен пример того, как оценить функцию стоимости над сеткой.

Нижеследующее оценивает квадратичную функцию стоимости по сетке и затем берет минимум вдоль первой оси. В частности, np.meshgrid - твой друг.

def cost_function(x, y): 
    return x ** 2 + y ** 2 

x = linspace(-1, 1) 
y = linspace(-1, 1) 

def eval_python(x, y): 
    matrix = [cost_function(_x, _y) for _x in x for _y in y] 
    return np.min(matrix, axis=0) 

def eval_numpy(x, y): 
    xx, yy = np.meshgrid(x, y) 
    matrix = cost_function(xx, yy) 
    return np.min(matrix, axis=0) 

%timeit eval_python(x, y) 
%timeit eval_numpy(x, y) 

Выходные 100 петель, лучшие из 3: 13.9 мс на петле 10000 петель, лучше всего 3: 136 мкс на петле

Наконец, если вы не можете бросить вашу проблему в этой форме, вы можете preallocated память и затем заполнить каждый элемент.

matrix = np.empty((num_x, num_y)) 
for i in range(num_x): 
    for j in range(num_y): 
     matrix[i, j] = cost_function(i, j) 
+0

Спасибо, но проблема в том, что у меня есть собственный список python и вам нужно сначала работать с этим. Так может ли быть сделано более эффективное преобразование? – bortran

+0

Можете ли вы построить массив numpy прямо сейчас, вместо того чтобы сначала создать список python? –

+0

Если вы возьмете это как пример, как мне это сделать? list1 = [[random.random() для i в диапазоне (3)] для j в диапазоне (9)] EDIT: но не со случайным, вместо этого, скажем, myCustomFunction(). – bortran