为啥 32 位和 64 位 numpy/pandas 之间存在差异
Posted
技术标签:
【中文标题】为啥 32 位和 64 位 numpy/pandas 之间存在差异【英文标题】:Why there is a difference between 32 bit and 64 bit numpy/pandas为什么 32 位和 64 位 numpy/pandas 之间存在差异 【发布时间】:2016-12-25 22:22:56 【问题描述】:我在 64 位 Fedora 机器上使用 numpy/pandas,在生产中他们推送到 32 位 Centos 机器并遇到json.dumps
错误。它正在抛出repr(0) is not Serializable
。
我尝试在 64 位 Centos 上进行测试,它运行得非常好。但是在 32 位(准确地说是 Centos 6.8)上它会引发错误。我想知道是否有人以前遇到过这个问题。
下面是64位Fedora,
Python 2.6.6 (r266:84292, Jun 30 2016, 09:54:10)
[GCC 5.3.1 20160406 (Red Hat 5.3.1-6)] on linux4
Type "help", "copyright", "credits" or "license" for more information.
>>> import pandas as pd
>>> >>> a = pd.DataFrame(['a':1])
>>>
>>> a
a
0 1
>>> a.to_dict()
'a': 0: 1
>>> import json
>>> json.dumps(a.to_dict())
'"a": "0": 1'
以下是 32 位 Centos
import json
import pandas as pd
a = pd.DataFrame( [ 'a': 1 ] )
json.dumps(a.to_dict())
Traceback (most recent call last):
File "sample.py", line 5, in <module>
json.dumps(a.to_dict())
File "/usr/lib/python2.6/json/__init__.py", line 230, in dumps
return _default_encoder.encode(obj)
File "/usr/lib/python2.6/json/encoder.py", line 367, in encode
chunks = list(self.iterencode(o))
File "/usr/lib/python2.6/json/encoder.py", line 309, in _iterencode
for chunk in self._iterencode_dict(o, markers):
File "/usr/lib/python2.6/json/encoder.py", line 275, in _iterencode_dict
for chunk in self._iterencode(value, markers):
File "/usr/lib/python2.6/json/encoder.py", line 309, in _iterencode
for chunk in self._iterencode_dict(o, markers):
File "/usr/lib/python2.6/json/encoder.py", line 268, in _iterencode_dict
raise TypeError("key 0!r is not a string".format(key))
TypeError: key 0 is not a string
解决此问题的常用方法是什么?我不能为 json 使用自定义编码器,因为我用来推送此数据的库需要一个字典,并且它在内部使用 json
模块对其进行序列化并将其推送到网络上。
更新: Python 版本为 2.6.6,pandas 均为 0.16.1
【问题讨论】:
这看起来不应该适用于任何一个版本。我猜系统运行的是不同的 Pandas 版本,其中一个版本有一个奇怪的 hack,使0
表现得像某种整数字符串混合体。
@user2357112 它应该在两个版本上都可以工作。
OP 你忘了添加最重要的东西:32 位 centos 上的 Python 版本和它们两者上的 pandas 版本。
@AnttiHaapala Python 2.6.6 和 pandas 0.16.1 32 位和 64 位
@AnttiHaapala:嗯,你说得对。 json
模块将 dict 键强制转换为字符串,而不是引发 TypeError,至少在 2.7 上。 2.6 文档没有 2.7 文档对此的注释;不知道是不是json
模块版本差异。
【参考方案1】:
我相信会发生这种情况是因为索引是一个大小与 Python int
不同的 numpy.intNN
,并且这些索引本身并不是从一个转换到另一个。
比如,在我的 64 位 Python 2.7 和 Numpy 上:
>>> isinstance(numpy.int64(5), int)
True
>>> isinstance(numpy.int32(5), int)
False
然后:
>>> json.dumps(numpy.int64(5): '5')
'"5": "5"'
>>> json.dumps(numpy.int32(5): '5')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/json/__init__.py", line 243, in dumps
return _default_encoder.encode(obj)
File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
return _iterencode(o, 0)
TypeError: keys must be a string
您可以尝试将索引更改为numpy.int32
、numpy.int64
或int
:
>>> df = pd.DataFrame( [ 'a': 1, 'a': 2 ] )
>>> df.index = df.index.astype(numpy.int32) # perhaps your index was of these?
>>> json.dumps(df.to_dict())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/json/__init__.py", line 243, in dumps
return _default_encoder.encode(obj)
File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
return _iterencode(o, 0)
TypeError: keys must be a string
所以你可以尝试将索引类型更改为int32
、int64
或只是简单的 Python int
:
>>> df.index = df.index.astype(numpy.int64)
>>> json.dumps(df.to_dict())
'"a": "0": 1, "1": 2'
>>> df.index = df.index.astype(int)
>>> json.dumps(df.to_dict())
'"a": "0": 1, "1": 2'
【讨论】:
以上是关于为啥 32 位和 64 位 numpy/pandas 之间存在差异的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Math.Exp 在 32 位和 64 位之间给出不同的结果,相同的输入,相同的硬件