Python Numpy массив медленнее, чем список - PullRequest
0 голосов
/ 24 марта 2020

Я работаю с 2d массивом. По сути, просто пытаюсь сделать поэлементное добавление постоянного значения. Необходимо ускорить код, поэтому попытался использовать массив numpy вместо списка, но обнаружил, что numpy медленнее. Есть идеи, что я делаю не так? Спасибо.

Например:

import time
import numpy as np

my_array_list = [[1,2,3],[4,5,6],[7,8,9]]
my_array_np = np.array(my_array_list)

n = 100000

s_np = time.time()
for a in range(n):
    for i in range(3):
        for j in range(3):
            my_array_np[i,j] = my_array_np[i,j] + 5
end_np = time.time() - s_np  

s_list = time.time()
for a in range(n):
    for i in range(3):
        for j in range(3):
            my_array_list[i][j] = my_array_list[i][j] + 5
end_list = time.time() - s_list 

print('my_array_np:', '\n', my_array_np, '\n')
print('my_array_list:', '\n',my_array_list, '\n')

print('time to complete with numpy:', end_np)
print('time to complete with list:', end_list)

Вывод:

my_array_np: 
 [[500001 500002 500003]
 [500004 500005 500006]
 [500007 500008 500009]] 

my_array_list: 
 [[500001, 500002, 500003], [500004, 500005, 500006], [500007, 500008, 500009]] 

time to complete with numpy: 0.7831366062164307
time to complete with list: 0.45527076721191406

С помощью этого теста можно увидеть списки, время для завершения значительно быстрее, ie 0,45 против 0,78 секунды. Разве numpy не должен быть здесь значительно быстрее?

Ответы [ 2 ]

2 голосов
/ 24 марта 2020

Допустим, вы хотите добавить что-то ко всем элементам, кратным 3. Вместо итерации по всем элементам массива, мы обычно используем mask

In [355]: x = np.arange(12).reshape(3,4)                                                       
In [356]: mask = (x%3)==0                                                                      
In [357]: mask                                                                                 
Out[357]: 
array([[ True, False, False,  True],
       [False, False,  True, False],
       [False,  True, False, False]])
In [358]: x[mask] += 100                                                                       
In [359]: x                                                                                    
Out[359]: 
array([[100,   1,   2, 103],
       [  4,   5, 106,   7],
       [  8, 109,  10,  11]])

Многие операции ufunc, который имеет where параметр

In [360]: x = np.arange(12).reshape(3,4)                                                       
In [361]: np.add(x,100, where=mask, out=x)                                                     
Out[361]: 
array([[100,   1,   2, 103],
       [  4,   5, 106,   7],
       [  8, 109,  10,  11]])

Fast numpy, требует, чтобы мы мыслили в терминах целого массива. Быстрый скомпилированный код работает с массивами или блоками массивов. Python Уровень итерации на массивах медленный, медленнее, как вы узнали, что итерация на списках. Доступ к отдельным значениям массива обходится дороже.

В этом небольшом примере эти методы для всего массива быстрее, чем итерация массива, хотя они все еще медленнее, чем итерация списка. Но методы массива скалярные гораздо лучше.

0 голосов
/ 24 марта 2020

ммммм ... Похоже, что вывод списка происходит быстрее в текущем случае. Но np быстрее, когда я добавляю numba.

import dis
import time
import numpy as np
from numba import jit


my_array_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
my_array_np = np.array(my_array_list)

n = 1000000


# @jit
def fun1(my_array_np):
    # it is inplace option
    for a in range(n):
        my_array_np += 5


s_np = time.time()
fun1(my_array_np)
end_np = time.time() - s_np


def fuc2(my_array_list):
    for a in range(n):
        my_array_list = [[i + 5 for i in j] for j in my_array_list]
    return my_array_list


s_list = time.time()
my_array_list = fuc2(my_array_list)
end_list = time.time() - s_list

print('my_array_np:', '\n', my_array_np, '\n')
print('my_array_list:', '\n', my_array_list, '\n')

print('time to complete with numpy:', end_np)
print('time to complete with list:', end_list)

my_array_np: 
 [[500001 500002 500003]
 [500004 500005 500006]
 [500007 500008 500009]] 

my_array_list: 
 [[500001, 500002, 500003], [500004, 500005, 500006], [500007, 500008, 500009]] 


# use numba
time to complete with numpy: 0.27802205085754395
time to complete with list: 1.9161949157714844

# not use numba
time to complete with numpy: 3.4962515830993652
time to complete with list: 1.9761543273925781
[Finished in 3.4s]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...