为啥 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.int32numpy.int64int

>>> 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

所以你可以尝试将索引类型更改为int32int64 或只是简单的 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 位之间给出不同的结果,相同的输入,相同的硬件

32位和64位有啥区别 32位和64位区别都有哪些

qt5.2版本开发环境在win7(64位)上能否同时安装32位和64位两种版本。

电脑32位和64位有啥区别 电脑32位和64位的区别

32位和64位系统的区别

64位和32位是啥?