为什么Pandas会将我的numpy float32强制转换成float64?

7
为什么在这段代码中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')

这种行为对我来说非常奇怪,我不确定它是否是一个 bug。我的 Pandas 版本是 0.17.1(已更新的 PyPI 版本),我注意到最近有一些强制转换的 bug 已经得到解决,请参见 https://github.com/pydata/pandas/issues/11847 。我还没有尝试过使用更新的 GitHub 主版本中的代码片段。

这是一个 bug 还是我误解了 Pandas 的某个 "功能"?如果这是一个功能,那么我该如何避免它呢?

(强制转换问题涉及我最近提出的有关 Pandas 赋值性能的问题:Assignment of Pandas DataFrame with float32 and float64 slow


这可能有点奇怪,但它与numpy一致。Numpy会自动将偶数整数转换为numpy.float64类型。由于Pandas的核心是numpy,我认为这种功能是可以预期的(尽管在您的情况下肯定不理想)。 - Benji
但是“pandas”更倾向于使用“dtype=object”,而不是普通的numpy。这使得它在处理混合类型时具有更大的灵活性-字符串可以是任意长度,列可以混合类型等。但是这种灵活性伴随着计算和内存成本。 - hpaulj
2个回答

3
我认为将此作为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'

我对 pandas 不如对 numpy 熟悉,但是我很困惑为什么 ix[:,:1] 会给我返回两列结果。在 numpy 中这种索引只会返回一列。

如果我分配单列 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)

使用单列赋值和循环遍历列名似乎对于“同类型”(非转换)赋值具有合理的性能,并且产生正确的类型。然而,如果存在从float32到float64的转换,则该方法慢了两倍以上。我想多次重新分配可能会解释后一个问题。 - Finn Årup Nielsen

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