Python numpy数组vs列表

bmp9r5qi  于 2023-08-05  发布在  Python
关注(0)|答案(7)|浏览(98)

我需要做一些计算一大堆数字.
array或numpy.array是否比典型阵列提供了显著的性能提升?
我不需要对数组进行复杂的操作,我只需要能够访问和修改值,
例如,在

import numpy
x = numpy.array([0] * 1000000)
for i in range(1,len(x)):
  x[i] = x[i-1] + i

字符串
所以我真的不需要连接,切片等。
而且,如果我尝试赋值不适合C long的值,数组看起来会抛出一个错误:

import numpy
a = numpy.array([0])
a[0] += 1232234234234324353453453
print(a)


在控制台上,我得到:

a[0] += 1232234234234324353453453
OverflowError: Python int too large to convert to C long


有没有一种数组的变体可以让我放入无限的Python整数?或者这样做会从一开始就失去使用数组的意义吗?

rryofs0p

rryofs0p1#

首先需要了解数组和列表之间的区别。
数组是一个连续的内存块,由某种类型的元素组成(例如:整数)。
数组一旦创建就不能更改其大小。
因此,**数组中的每个整数元素都有 * 固定大小 ,例如4个字节。
另一方面,list 仅仅是 * address * 的“数组”(也有固定的大小)。
但是,每个 element 都保存内存中 else 的地址,这是您想要使用的实际 integer。当然,
这个整数的大小与数组的大小无关 *。因此,你总是可以创建一个新的(更大的)整数并“替换”旧的整数,而不会影响数组的大小,数组只保存整数的 * 地址 *。
当然,列表的这种便利性是有代价的:对整数执行算术运算现在需要对数组的内存访问,加上对整数本身的内存访问,加上分配更多内存所需的时间(如果需要),加上删除旧整数所需的时间(如果需要)。所以是的,它可能会更慢,所以你必须小心你在数组中对每个整数所做的事情。

3phpmpom

3phpmpom2#

你的第一个例子可能是加速。Python循环和访问numpy数组中的单个项都很慢。改为使用向量化操作:

import numpy as np
x = np.arange(1000000).cumsum()

字符串
你可以将无界Python整数放入numpy数组:

a = np.array([0], dtype=object)
a[0] += 1232234234234324353453453


在这种情况下,算术运算与固定大小的C整数相比会慢一些。

db2dz4w8

db2dz4w83#

对于大多数用途,列表是有用的。例如,有时使用numpy数组可能更方便。

a=[1,2,3,4,5,6,7,8,9,10]

b=[5,8,9]

字符串
考虑一个列表'a',如果你想访问列表中的元素在列表'B'中给出的离散索引

a[b]


不会工作。
但是当你把它们作为数组使用时,你可以简单地写

a[b]


以数组([6,9,10])的形式获得输出。

vfh0ocws

vfh0ocws4#

array或numpy.array是否比典型阵列提供了显著的性能提升?
我试着用下面的代码测试一下:

import timeit, math, array
from functools import partial
import numpy as np

# from the question
def calc1(x):
    for i in range(1,len(x)):
        x[i] = x[i-1] + 1

# a floating point operation
def calc2(x):
    for i in range(0,len(x)):
        x[i] = math.sin(i)

L = int(1e5)

# np
print('np 1: {:.5f} s'.format(timeit.timeit(partial(calc1, np.array([0] * L)), number=20)))
print('np 2: {:.5f} s'.format(timeit.timeit(partial(calc2, np.array([0] * L)), number=20)))

# np but with vectorized form
vfunc = np.vectorize(math.sin)
print('np 2 vectorized: {:.5f} s'.format(timeit.timeit(partial(vfunc, np.arange(0, L)), number=20)))

# with list
print('list 1: {:.5f} s'.format(timeit.timeit(partial(calc1, [0] * L), number=20)))
print('list 2: {:.5f} s'.format(timeit.timeit(partial(calc2, [0] * L), number=20)))

# with array
print('array 1: {:.5f} s'.format(timeit.timeit(partial(calc1, array.array("f", [0] * L)), number=20)))
print('array 2: {:.5f} s'.format(timeit.timeit(partial(calc2, array.array("f", [0] * L)), number=20)))

字符串
结果是list在这里执行得最快(Python 3.3,NumPy 1.8):

np 1: 2.14277 s
np 2: 0.77008 s
np 2 vectorized: 0.44117 s
list 1: 0.29795 s
list 2: 0.66529 s
array 1: 0.66134 s
array 2: 0.88299 s


这似乎是违反直觉。对于这些简单的示例,使用numpyarray相对于list似乎没有任何优势。

uwopmtnx

uwopmtnx5#

To OP:对于您的用例使用列表。
考虑到鲁棒性和速度,我的规则是:

list:(最健壮,对于可变情况最快)当你的列表像在物理模拟中一样不断变化时。当您从头开始“创建”本质上可能无法预测的数据时。
np.arrary:(不太稳健,对于线性代数和数据后处理最快)当你“后处理”一个数据集,你已经通过传感器或模拟收集;执行可以矢量化的操作。

zujrkrfu

zujrkrfu6#

使用a=numpy.array(number_of_elements, dtype=numpy.int64),它应该给予你一个64位整数的数组。这些可以存储-2^63和(2^63)-1之间的任何整数(大约在-10^19和10^19之间),这通常是绰绰有余的。

bbmckpt7

bbmckpt77#

向量化numpy的应用似乎受到timeit或partial的影响。试试这个:

`# not using time it
total_time=0
for i in range(20):
    t0=time.process_time()
    np.sin(np.arange(0,L))
    total_time+=time.process_time()-t0
    print('np 2 vectorized - no timeit or partial: {:.5f} s'.format(total_time/20))`

字符串
结果如下:

np 1: 0.67521 s
np 2: 0.39538 s
np 2 vectorized: 0.26964 s
list 1: 0.19755 s
list 2: 0.26914 s
array 1: 0.27625 s
array 2: 0.35779 s
np 2 vectorized - no timeit or partial: 0.00077 s

相关问题