将大量数据存入numpy数组

13

我有一个数据集,想要应用一些算术方法。问题是,当我用numpy计算时,相对较大的数字会被存储为0。

奇怪的是,当我单独计算这些数字时,它们有一个整数值,只有当我使用numpy计算时它们才变成0。

x = np.array([18,30,31,31,15])
10*150**x[0]/x[0]
Out[1]:36298069767006890

vector = 10*150**x/x
vector
Out[2]: array([0, 0, 0, 0, 0])

我当然已经检查过它们的类型:

type(10*150**x[0]/x[0]) == type(vector[0])
Out[3]:True

如何在numpy中计算这些大数字而不看到它们变成零?

请注意,如果我们移除开头的10这个因子,问题会略有改变(但我认为原因可能是相似的):

x = np.array([18,30,31,31,15])
150**x[0]/x[0]
Out[4]:311075541538526549

vector = 150**x/x
vector
Out[5]: array([-329406144173384851, -230584300921369396, 224960293581823801,
   -224960293581823801, -368934881474191033])

负数表示Python中int64类型的最大数值已经被超过了,不是吗?


你能否使用浮点数 np.array([18.0, 30, 31, 31, 15]) 代替整数? - kennytm
1
不要使用浮点数值。它们可能看起来可以工作,但在那些值范围内它们的精度会非常糟糕。你的计算是正确的,但结果是错误的(而你没有注意到)。 - Nils Werner
2个回答

22

正如Nils Werner所提到的,numpy的原生ctypes无法保存那么大的数字,但是Python本身可以,因为int对象使用任意长度的实现。

因此,您可以告诉numpy不要将数字转换为ctypes,而是使用Python对象。这样会慢一些,但它会工作。

In [14]: x = np.array([18,30,31,31,15], dtype=object)

In [15]: 150**x
Out[15]: 
array([1477891880035400390625000000000000000000L,
       191751059232884086668491363525390625000000000000000000000000000000L,
       28762658884932613000273704528808593750000000000000000000000000000000L,
       28762658884932613000273704528808593750000000000000000000000000000000L,
       437893890380859375000000000000000L], dtype=object)
在此情况下,NumPy数组将不存储数字本身,而是引用对应的整数对象。当您执行算术运算时,它们不会在NumPy数组上执行,而是在引用背后的对象上执行。
我认为您仍然可以使用大多数NumPy函数来解决这个问题,但它们肯定比通常慢得多。

但是,当您处理如此大的数字时,就会出现这种情况:D
也许在某个地方有一个库可以更好地处理这个问题。

仅出于完整性考虑,如果精度不是问题,您还可以使用浮点数:

In [19]: x = np.array([18,30,31,31,15], dtype=np.float64)

In [20]: 150**x
Out[20]: 
array([  1.47789188e+39,   1.91751059e+65,   2.87626589e+67,
         2.87626589e+67,   4.37893890e+32])

1
有趣的方法是使用numpy.array(dtype=object)。会记在心里的。 - Nils Werner
dtype=object选项在一般情况下似乎是一个不错的解决方案。但在我的情况下可能会更加困难,因为我需要应用scipy.special函数,例如psi(digamma函数),它可以在numpy.array上工作,但不能与dtype=object选项一起使用。 - ysearka
通常情况下,您不能指望numpy数学运算能够处理dtype=object。快速操作使用编译代码 - 与各种标准数字数据类型一起工作的代码。但是对于object,数组实际上包含指针 - 指向内存中其他位置的对象。实际上,这样的数组是一个被吹嘘的列表(或者是贬低的列表?)。 - hpaulj

3

150 ** 28 远远超出了 int64 变量可以表示的范围(大约在 8e60 左右,而无符号 int64 的最大可能值大约为 18e18)。

Python 可能正在使用一个任意长度的整数实现,但 NumPy 并不是。

正如你正确推断的那样,负数是 int 溢出的症状。


那么是否有一种方法可以为numpy提供另一种长度的整数实现?我可以使用原始的Python一个接一个地计算数字,但那太长了,我真的很想避免这种情况。 - ysearka
似乎很奇怪的是,如果普通的Python没有使用相同长度的整数实现,那么150 ** x [0] / x [0]的类型显示为numpy.int64。这是否意味着它在某种类型中进行计算,然后将其存储在另一个类型中? - ysearka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接