python - 混合内置 Python 数值类型和 Numpy 标量数值数据类型的计算性能
问题描述
我正在为存储在大型文本文件(1Gb+)中的一些数据编写解析器
输出是一个 numpy 复数数组,所以我很自然地使用了类似的语句
vals[...] = real_part + 1j*imag_part
从哪里real_part
获得imag_part
numpy.fromstring(...)
我注意到,如果我简单地替换vals[...] = real_part + 1j*imag_part
为
vals[...] = 1j*imag_part + real_part
我几乎获得了 x2 的性能提升,这对于大型数据集来说意义重大。
我做了一些测试,得到了令人困惑的结果:
代码:
import timeit
import numpy as np
a = np.float64(1.0)
print('type of 1j*a+a is',type(1j*a+a))
print('type of a+1j*a is',type(a+1j*a))
print('type of a+a*1j is',type(a+a*1j))
setup_line = 'import numpy as np; b = np.zeros(1,dtype=complex)'
N = 1000000
t1 = timeit.timeit("a=np.fromstring('1.1 2.2',sep=' ',dtype=float); b[0]=1j*a[1]+a[0]", setup=setup_line, number=N)
t2 = timeit.timeit("a=np.fromstring('1.1 2.2',sep=' ',dtype=float); b[0]=a[0]+1j*a[1]", setup=setup_line, number=N)
t3 = timeit.timeit("a=np.fromstring('1.1 2.2',sep=' ',dtype=float); b[0]=a[0]+a[1]*1j", setup=setup_line, number=N)
print(f't2/t1 = {t2/t1}')
print(f't3/t1 = {t3/t1}')
print(f'type of 1.0*a is {type(1.0*a)}')
print(f'type of 1.0.__mul__(a) is {type((1.0).__mul__(a))}')
print(f'type of a.__rmul__(1.0) is {type(a.__rmul__(1.0))}')
print(f'type of a*1.0 is {type(a*1.0)}')
print(f'type of 1j*a is {type(1j*a)}')
print(f'type of a*1j is {type(a*1j)}')
输出:
type of 1j*a+a is <class 'complex'>
type of a+1j*a is <class 'numpy.complex128'>
type of a+a*1j is <class 'numpy.complex128'>
t2/t1 = 2.720535618997823
t3/t1 = 3.9634173211365487
type of 1.0*a is <class 'numpy.float64'>
type of 1.0.__mul__(a) is <class 'float'>
type of a.__rmul__(1.0) is <class 'numpy.float64'>
type of a*1.0 is <class 'numpy.float64'>
type of 1j*a is <class 'complex'>
type of a*1j is <class 'numpy.complex128'>
所以在第一种情况下性能更好,因为所有计算都在 Python 内置complex
类中执行。性能提升也接近于逐行解析的实际情况。
更令人困惑的是为什么 type of1.0*a
不等于(1.0).__mul__(a)
但等于a.__rmul__(1.0)
?是应该的样子吗?
1.0*a
和有什么区别1j*a
?
解决方案
我怀疑“原始”时间会告诉我们比比率更多的信息:
In [182]: timeit 1j*a+a
209 ns ± 12.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [183]: timeit a+1j*a
5.26 µs ± 11.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [184]: timeit a+a*1j
10 µs ± 9.28 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
通过像这样的单值计算,函数调用和与 numpy 的转换可以主导时代。我们没有看到“纯”计算时间。为此,我们需要使用更大的数组。
例如,众所周知,这math.sin
比np.sin
单个值要好。np.sin
具有 100 个值的速度更快。我怀疑这里正在发生这样的事情,但现在没有时间去探索它。
推荐阅读
- java - 通过 Class.forName() 方法调用进行动态注入总是有害的吗?
- rasa-nlu - Rasa 服务器的最低系统要求和并行客户端请求数量的限制?
- xml - 将注释xml转换为Python中的文本
- python - 使用 Tkinter 和 Speech to Text 进行线程化
- android - 如何处理 Glide V4 中未找到图像的错误
- c# - 进行 Http 调用时出现套接字异常
- list - 需要收集列表中每个字符串的第一个字母,并将它们全部放在一起作为一个新字符串
- asp.net-mvc - 网页未找到。没有 umbraco 文档与 url '/' 匹配
- asp.net-mvc-4 - 如何在 asp.net MVC 中隐藏自定义路由的控制器?
- c# - 如何通过代理连接到 WCF 服务