为什么NumPy而不是Python列表?

值得我学习NumPy吗?

我有大约100个金融市场系列,我将创建一个100x100x100 = 100万个单元格的立方阵列。 我将使用y和z对每个x进行回归(3变量),以填充标准错误的数组。

我听说,对于“大型矩阵”,我应该使用NumPy,而不是Python列表,出于性能和可扩展性的原因。 事情是,我知道Python列表,他们似乎为我工作。

上述问题的规模是否值得转移到NumPy?

如果我有1000个系列(即,立方体中有10亿个浮点单元),该怎么办?

NumPy的数组比Python列表更紧凑 – 在Python中,列表的描述列表至少需要20 MB左右,而在单元中使用单精度浮点数的NumPy 3D数组将适合4 MB。 用NumPy读取和写入物品的速度也更快。

也许你不会太在乎那么多的一百万个单元,但是你肯定会有十亿个单元 – 这两种方法都不适合32位体系结构,但是在64位构建中,NumPy将会获得4 GB左右,Python本身至少需要大约12 GB(大量指针的两倍大小) – 一个更昂贵的硬件!

差异主要是由于“间接性” – 一个Python列表是指向Python对象的指针数组,每个指针至少4个字节,即使是最小的Python对象也加上16个字节(4个用于类型指针,4个用于引用计数,4个对于价值 – 内存分配器四舍五入到16)。 NumPy数组是一个统一值的数组 – 单精度数字每个4字节,双精度8字节。 不够灵活,但是您为标准Python列表的灵活性付出了实质性的代价!

NumPy不仅更有效率, 这也比较方便。 您可以免费获得大量的矢量和矩阵操作,有时可以避免不必要的工作。 而且他们也有效地实施。

例如,您可以直接从文件读取您的多维数据集到一个数组:

 x = numpy.fromfile(file=open("data"), dtype=float).reshape((100, 100, 100)) 

总结第二个维度:

 s = x.sum(axis=1) 

查找哪些单元格高于阈值:

 (x > 0.5).nonzero() 

删除沿着第三维的每个偶数索引片:

 x[:, :, ::2] 

此外,许多有用的库与NumPy数组一起工作。 例如统计分析和可视化库。

即使你没有性能问题,学习NumPy也是值得的。

亚历克斯提到了记忆效率,罗伯托提到了方便,这些都是好的。 对于更多的想法,我会提到速度功能

功能:你可以用NumPy,FFT,卷积,快速搜索,基本统计,线性代数,直方图等获得很多内容。真的,没有FFT的人可以生活吗?

速度:这是一个在列表和NumPy数组上进行求和的测试,显示了NumPy数组的和为10倍(在这个测试中,里程可能会有所不同)。

 from numpy import arange from timeit import Timer Nelements = 10000 Ntimeits = 10000 x = arange(Nelements) y = range(Nelements) t_numpy = Timer("x.sum()", "from __main__ import x") t_list = Timer("sum(y)", "from __main__ import y") print("numpy: %.3e" % (t_numpy.timeit(Ntimeits)/Ntimeits,)) print("list: %.3e" % (t_list.timeit(Ntimeits)/Ntimeits,)) 

在我的系统上(当我正在运行备份时)给出:

 numpy: 3.004e-05 list: 5.363e-04 

以下是scipy.org网站上FAQ的一个很好的答案:

NumPy数组提供的(嵌套的)Python列表有什么优势?

Python的列表是高效的通用容器。 它们支持(相当)有效的插入,删除,追加和连接,Python的列表解析使得它们易于构建和操作。 但是,它们有一定的局限性:它们不支持像元素相加和乘法这样的“向量化”操作,而且它们可以包含不同类型的对象,这意味着Python必须为每个元素存储类型信息,并且必须执行类型分派代码当在每个元素上操作时。 这也意味着很少的列表操作可以通过有效的C循环来执行 – 每次迭代都需要类型检查和其他Python API簿记。

还要注意,时间序列分析中支持基于NumPy的时间序列:

http://pytseries.sourceforge.net

对于回归,我很肯定NumPy比列表更快,更方便,即使是100 ^ 3的问题。

速度方面,我不太确定。 下面是一个简单的例子:我创建了一个函数(x),返回2到x之间的素数列表:

  • 使用列表的常规Python函数:

     def findprimeupto(x): primes = [] n_primes = [] for i in range(2, x): if not (i in n_primes): primes.append(i) n_primes.append(i) for j in range(len(primes)): if i > n_primes[j]: n_primes[j] += primes[j] return primes import time start_time = time.time() findprimeupto(10000) print("--- %s seconds ---" % str(time.time() - start_time)) 
  • 和使用NumPy数组的C类Python函数:

     import numpy def findprimeupto(x): primes = numpy.array(numpy.zeros(x), dtype=numpy.int32) n_primes = numpy.array(numpy.zeros(x), dtype=numpy.int32) primeslen = 0 for i in range(2, x): flag = 1 for j in range(primeslen): if n_primes[j] == i: flag = 0 break if flag: primes[primeslen] = i n_primes[primeslen] = i primeslen += 1 for j in range(primeslen): if i > n_primes[j]: n_primes[j] += primes[j] return [primeslen, primes] import time start_time = time.time() result = findprimeupto(10000) #for i in range(result[0]): # print('{:d} '.format(result[1][i]), end="") print() print("--- %s seconds ---" % str(time.time() - start_time)) 

前者,据说使用列表执行缓慢,在0.6秒内执行,而后来的NumPy快速实现需要50秒。 如果有人能指出为什么我会非常感激。

顺便说一句,纯粹的C程序,或多或少是NumPy版本的函数的副本执行时间小于0.04秒。 C的速度在x大时更为明显:

  #include <stdio.h> #include <stdlib.h> #include <time.h> void findprimesupto(int n, int *primeslen, int *primes, int *n_primes) { int i, j, flag; *primeslen = 0; for (i=2; i <= n; i++) { for (j=0, flag=1; j < *primeslen; j++) if (n_primes[j] == i) { flag = 0; break; } if (flag) { primes[*primeslen] = i; n_primes[*primeslen] = i; (*primeslen)++; } for (j=0; j < *primeslen; j++) if (i > n_primes[j]) n_primes[j] += primes[j]; } } int main() { int n = 10000, primeslen = 0, i; int *primes, *n_primes; clock_t start, diff; start = clock(); primes = malloc(n * sizeof(int)); n_primes = malloc(n * sizeof(int)); findprimesupto(n, &primeslen, primes, n_primes); /* for (i=0; i < primeslen; i++) printf("%d ", primes[i]); printf("\n"); */ diff = clock() - start; printf("Time: %fs\n", (float) diff / (float) CLOCKS_PER_SEC); free(primes); free(n_primes); return 0; }