为啥 Pandas 将我的 numpy float32 强制转换为 float64?

Posted

技术标签:

【中文标题】为啥 Pandas 将我的 numpy float32 强制转换为 float64?【英文标题】:Why does Pandas coerce my numpy float32 to float64?为什么 Pandas 将我的 numpy float32 强制转换为 float64? 【发布时间】:2016-05-15 19:09:47 【问题描述】:

为什么 Pandas 在这段代码中将我的 numpy float32 强制转换为 float64:

>>> import pandas as pd
>>> import numpy as np
>>> df = pd.DataFrame([[1, 2, 'a'], [3, 4, 'b']], dtype=np.float32)
>>> A = df.ix[:, 0:1].values
>>> df.ix[:, 0:1] = A
>>> df[0].dtype
dtype('float64')

这种行为对我来说似乎很奇怪,以至于想知道它是否是一个错误。我使用的是 Pandas 版本 0.17.1(更新的 PyPI 版本),我注意到最近解决了强制错误,请参阅https://github.com/pydata/pandas/issues/11847。我没有用更新的 GitHub master 尝试过这段代码。

这是一个错误还是我误解了 Pandas 中的某些“功能”?如果它是一个功能,那么我该如何绕过它?

(强制问题与我最近询问的关于 Pandas 作业性能的问题有关:Assignment of Pandas DataFrame with float32 and float64 slow)

【问题讨论】:

可能有点奇怪,但和numpy一致。 Numpy 自动将偶数整数转换为 numpy.float64 类型。由于 Pandas 以 numpy 为核心,因此 IMO 需要此功能(尽管在您的情况下肯定不理想)。 但是'pandas' 比普通的numpy 更倾向于使用'dtype=object'。它在处理混合类型时提供了更大的灵活性 - 字符串可以是任意长度,列可以混合类型等。但灵活性伴随着计算和内存成本。 【参考方案1】:

我认为值得将此作为 GitHub 问题发布。行为肯定不一致。

代码根据 DataFrame 是否为混合类型(source)采用不同的分支。

在混合类型的情况下,ndarray 被转换为 float64 数字的 Python 列表,然后在不考虑 DataFrame 的 dtypes 信息的情况下转换回 float64 ndarray (function maybe_convert_objects())。

在非混合类型的情况下,DataFrame 内容几乎直接更新 (source),DataFrame 保持其 float32 dtypes。

【讨论】:

【参考方案2】:

不是答案,而是我对这个问题的再现:

In [2]: df = pd.DataFrame([[1, 2, 'a'], [3, 4, 'b']], dtype=np.float32)
In [3]: df.dtypes
Out[3]: 
0    float32
1    float32
2     object
dtype: object
In [4]: A=df.ix[:,:1].values
In [5]: A
Out[5]: 
array([[ 1.,  2.],
       [ 3.,  4.]], dtype=float32)
In [6]: df.ix[:,:1] = A
In [7]: df.dtypes
Out[7]: 
0    float64
1    float64
2     object
dtype: object
In [8]: pd.__version__
Out[8]: '0.15.0'

我对@9​​87654322@ 不像numpy 那样熟悉,但我很困惑为什么ix[:,:1] 给我一个2 列的结果。在 numpy 中,这种索引只提供 1 列。

如果我分配单个列 dtype 不会改变

In [47]: df.ix[:,[0]]=A[:,0]
In [48]: df.dtypes
Out[48]: 
0    float32
1    float32
2     object

没有混合数据类型的相同操作不会改变dtypes

In [100]: df1 = pd.DataFrame([[1, 2, 1.23], [3, 4, 3.32]], dtype=np.float32)
In [101]: A1=df1.ix[:,:1].values
In [102]: df1.ix[:,:1]=A1
In [103]: df1.dtypes
Out[103]: 
0    float32
1    float32
2    float32
dtype: object

关键必须是,对于混合值,数据帧在某种意义上是一个dtype=object 数组,无论是其内部数据存储还是它的numpy 接口。

In [104]: df1.as_matrix()
Out[104]: 
array([[ 1.        ,  2.        ,  1.23000002],
       [ 3.        ,  4.        ,  3.31999993]], dtype=float32)
In [105]: df.as_matrix()
Out[105]: 
array([[1.0, 2.0, 'a'],
       [3.0, 4.0, 'b']], dtype=object)

【讨论】:

单列赋值和列名上的for循环似乎为“类型内”(非强制转换)赋值提供了合理的性能,并产生了正确的类型。但是,如果在 float32 和 float64 之间进行转换,则该方法的速度会慢两倍以上。我想多次重新分配可以解释后一个问题。

以上是关于为啥 Pandas 将我的 numpy float32 强制转换为 float64?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用numpy和pandas来进行数据处理?

使用 Pandas 创建 NumPy 数组

为啥 32 位和 64 位 numpy/pandas 之间存在差异

为啥 numpy 函数在 pandas 系列/数据帧上这么慢?

为啥 pandas.Series.std() 与 numpy.std() 不同?

为啥numpy的float128只有63位尾数? [复制]