python - 如何在 numpy 中使基于序列的函数更快?
问题描述
考虑以下函数:
import numpy as np
a = np.ones(16).reshape(4,4)
def fn(a):
b = np.array(a)
for i in range(b.shape[0]):
for j in range(b.shape[1] - 1):
b[i][j+1] += b[i][j]
return b
print(fn(a))
也就是说,对于一个t+1
基于t
数组计算的通用函数,我可以让它更快吗?我知道有一个np.vectorize
但似乎不适合这种情况。
解决方案
可以将两个for
循环减少为一个for
循环,另外只需少量复制开销。
In [86]: a
Out[86]:
array([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])
In [87]: b = a.copy()
In [88]: for col in range(b.shape[1]-1):
...: b[:, col+1] = np.sum(a[:, :col+2], axis=1)
In [89]: b
Out[89]:
array([[1., 2., 3., 4.],
[1., 2., 3., 4.],
[1., 2., 3., 4.],
[1., 2., 3., 4.]])
为了使这个函数适用于通用函数,您可以在 numpy 中寻找等效函数或使用 numpy 操作(矢量化操作)实现一个。对于您提供的示例,我只是使用numpy.sum()
它为我们完成了这项工作。
for
在性能方面,这种方法比在索引级别使用两个循环操作要好得多,特别是对于较大的数组。在我上面使用的方法中,我们使用列切片。
以下是表明比原生 python 实现速度提高 3 倍以上的时间安排。
原生 Python:
def fn(a):
b = np.array(a)
for i in range(b.shape[0]):
for j in range(b.shape[1] - 1):
b[i][j+1] += b[i][j]
return b
稍微矢量化:
In [104]: def slightly_vectorized(b):
...: for col in range(b.shape[1]-1):
...: b[:, col+1] = np.sum(a[:, :col+2], axis=1)
...: return b
In [100]: a = np.ones(625).reshape(25, 25)
In [101]: %timeit fn(a)
303 µs ± 2.05 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [102]: b = a.copy()
In [103]: %timeit slightly_vectorized(b)
99.8 µs ± 501 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
推荐阅读
- laravel - 如何响应 message() 请求
- java - 如何仅延迟特定方法?
- angular - angular-bootstrap-datetimepicker 可以与 bootstrap3 一起使用吗?
- ruby-on-rails - Symbol 对象上的 Ruby 文档具有误导性
- nuget - 无法下载工件时的通知
- algorithm - 三胞胎数
- label - TextCategorizer.predict 如何与 spaCy 一起使用?
- javascript - Leaflet 从 geojson 获取 id 并将其绑定到弹出窗口
- typescript - “CustomEnum.Case”可分配给“T”类型的约束,但“T”可以用约束“CustomEnum”的不同子类型实例化
- javascript - 使用 post 方法单击搜索按钮后 URL 不会更改