我是Python的新手,所以我决定解决一些常见的挑战,以提高我的语言知识。我了解了numpy及其有效的ndarrays,因此尝试了以下实验:
考虑2和问题(例如here),让我们以幼稚的方式解决它(此问题的目的无关紧要)。 这是使用python列表的解决方案:
from itertools import combinations
def twosum1(n_lst):
pairs=list(combinations(n_lst,2))
solutions=[]
for pair in pairs:
if sum(pair)==7: solutions.append(pair)
return(solutions)
然后我使用np.arrays创建了一个版本,希望它可以大大加快计算速度:
from itertools import combinations
import numpy as np
def twosum2(n_lst):
pairs=np.array(list(combinations(n_lst,2)),dtype=int)
return pairs[pairs[:,1]+pairs[:,0]==7]
但是,在对两个函数进行计时之后,twosum2的速度比twosum1慢2倍。所以我认为问题可能出在元素的动态选择上,所以我用ndarrays替换了列表,从而编写了twosum1的精确副本...
def twosum3(n_lst):
pairs=np.array(list(combinations(n_lst,2)))
solutions=np.empty((0,2))
for pair in pairs:
if np.sum(pair)==7:
solutions=np.append(solutions,[pair],axis=0)
return(solutions)
...并且生成的功能比原始功能慢10倍!
这怎么可能?我在这里做错了什么?显然,删除循环并使用ndarrays替换列表不足以提高速度(与我从this中学到的相反)。
编辑:
答案 0 :(得分:3)
代价昂贵的操作是np.array(list(combinations(n_lst,2)),dtype=int)
,因为python必须扫描列表中的每个成员,检查成员是否“兼容”,将其转换为整数并将其存储在数组中。
要达到numpy性能,必须在numpy中构思所有算法。例如:
In [63]: n_lst=list(range(100))
In [64]: %timeit twosum1(n_lst)
11.2 ms ± 1.64 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [65]: np.vstack(np.where(np.add.outer(n_lst,n_lst)==7)).T
Out[65]:
array([[0, 7],
[1, 6],
[2, 5],
[3, 4],
[4, 3],
[5, 2],
[6, 1],
[7, 0]], dtype=int64)
In [66]: %timeit np.vstack(np.where(np.add.outer(n_lst,n_lst)==7)).T
306 µs ± 19 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
这样,根据问题,您将赢得30到100的系数。