【问题标题】:Pandas convert_to_r_dataframe function KeyErrorPandas convert_to_r_dataframe 函数 KeyError
【发布时间】:2015-04-07 12:31:50
【问题描述】:

我创建了一个熊猫数据框:

import pandas as pd

df = pd.DataFrame(x.toarray(), columns = colnames)

然后我将其转换为 R 数据框:

import pandas.rpy.common as com

rdf = com.convert_to_r_dataframe(df)

在 Windows 下使用此配置没有问题:

>>> pd.show_versions()

INSTALLED VERSIONS
------------------
commit: None
python: 2.7.7.final.0
python-bits: 32
OS: Windows
OS-release: 7
machine: AMD64
processor: AMD64 Family 16 Model 4
byteorder: little
LC_ALL: None
LANG: None

pandas: 0.14.1
numpy: 1.8.2
rpy2: 2.4.4
...

但是当我用这个配置在 Linux 上执行它时:

>>> pd.show_versions()

INSTALLED VERSIONS
------------------
commit: None
python: 2.7.3.final.0
python-bits: 64
OS: Linux
OS-release: 3.2.0-29-generic
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8

pandas: 0.14.1
numpy: 1.8.2
rpy2: 2.4.4
...

我明白了:

Traceback (most recent call last):
  File "app.py", line 232, in <module>
    clf.global_cl(df, df2)
  File "/home/uzer/app/util/clftool.py", line 202, in global_cl
    rdf = com.convert_to_r_dataframe(df)
  File "/home/uzer/app/venv/local/lib/python2.7/site-packages/pandas/rpy/common.py", line 324, in convert_to_r_dataframe
    value = VECTOR_TYPES[value_type](value)
KeyError: <type 'numpy.int64'>

似乎 VECTOR_TYPES 没有 &lt;type 'numpy.int64'&gt; 作为键。但事实并非如此:

VECTOR_TYPES = {np.float64: robj.FloatVector,
            np.float32: robj.FloatVector,
            np.float: robj.FloatVector,
            np.int: robj.IntVector,
            np.int32: robj.IntVector,
            np.int64: robj.IntVector,
            np.object_: robj.StrVector,
            np.str: robj.StrVector,
            np.bool: robj.BoolVector}

所以我在convert_to_r_dataframe../pandas/rpy/common.py)中打印了变量类型:

for column in df:
    value = df[column]
    value_type = value.dtype.type
    print("value_type: %s") % value_type
    if value_type == np.datetime64:
        value = convert_to_r_posixct(value)
    else:
        value = [item if pd.notnull(item) else NA_TYPES[value_type]
                 for item in value]
        print("Is value_type == np.int64: %s") % (value_type is np.int64)
        value = VECTOR_TYPES[value_type](value)
        ...

结果就是这样:

value_type: <type 'numpy.int64'>
Is value_type == np.int64: False

这怎么可能??既然 32 位 Windows 版本没有问题,那么 64 位 Linux Python 版本会不会有问题?

编辑:由@lgautier建议,我修改了这个:

rdf = com.convert_to_r_dataframe(df)

到:

from rpy2.robjects import pandas2ri
rdf = pandas2ri.pandas2ri(df)

这很有效。

注意:我的数据帧包含 utf-8 特殊字符,作为列名,以 unicode 解码。当DataFrame 构造函数被调用(包含在rpy2/robjects/vectors.py 中)时,这一行尝试将unicode 字符串(包含特殊字符)编码为ascii 字符串:

kv = [(str(k), conversion.py2ri(obj[k])) for k in obj]

这会产生错误:

UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)

为了解决这个问题,我不得不更改该行:

kv = [(k.encode('UTF-8'), conversion.py2ri(obj[k])) for k in obj]

Rpy2 应该引入一种允许更改编码的方法。

【问题讨论】:

  • 仔细看代码,str(k)的使用也不是完全一致。一个快速的解决方法是将其作为参数添加到DataFrame 构造函数,但这并不能完全解决问题。可能这正是 Python 3 中字符串处理的巨大变化正在解决的那种令人头疼的问题。

标签: python numpy pandas rpy2


【解决方案1】:

考虑使用 rpy2 自己的转换(在 Linux 上似乎与 int64 一起使用):

# create a test DataFrame
import numpy
import pandas

i2d = numpy.array([[1, 2, 3], [4, 5, 6]], dtype="int64")
colnames = ('a', 'b', 'c')
dataf = pandas.DataFrame(i2d, 
                         columns = colnames)

# rpy2's conversion of pandas objects
from rpy2.robjects import pandas2ri
pandas2ri.activate()

现在 pandas DataFrame 对象会自动转换 在每次调用时使用嵌入式 R 到 rpy2/R DataFrame 对象。 例如:

from rpy2.robjects.packages import importr
# R's "base" package
base = importr('base')
# call the R function "summary"
print(base.summary(dataf))

也可以显式调用转换:

from rpy2.robjects import conversion
rpy2_dataf = conversion.py2ro(dataf)

编辑:(添加自定义以解决str(k) 问题)

如果与转换相关的任何事情都需要本地定制,这可以相对容易地实现。单程 改变 R DataFrame 的构建方式是:

import pandas.DataFrame as PandasDataFrame
import rpy2.robjects.vectors.DataFrame as RDataFrame
from rpy2 import rinterface
@conversion.py2ro.register(PandasDataFrame)
def py2ro_pandasdataframe(obj):
    ri_dataf = conversion.py2ri(obj)
    # cast down to an R list (goes through a different code path
    # in the DataFrame constructor, avoiding `str(k)`) 
    ri_list = rinterface.SexpVector(ri_dataf)
    return RDataFrame(ri_list)

从现在开始,上面的转换函数将在 pandas 时使用 DataFrame 存在:

rpy2_dataf = conversion.py2ro(dataf)

【讨论】:

  • 我需要显式调用转换,所以我尝试了:conversion.py2ro(df)pandas2ri.pandas2ri(df),但结果为:UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)。这可能是由于列/行名称需要在 'UTF-8' 而不是在 'ascii' 中编码。有办法强制 UTF-8 编码吗?
  • @MrMoog - 如果没有完整的示例,很难重现。最近有一份关于出现特定于 Windows 的编码问题的报告 (stackoverflow.com/questions/28247851/…)。看看这是否是一个相关问题会很有趣。
  • 我忘了rpy2有缺。在DataFrame 构造函数中(在rpy2/robjects/vectors.py 中),字符串会自动转换为ascii。在我的数据框中,有带有特殊字符(源自 UTF-8 编码)的 unicode 字符串作为列名。我不得不将kv = [(str(k), conversion.py2ri(obj[k])) for k in obj] 更改为kv = [(k.encode('UTF-8'), conversion.py2ri(obj[k])) for k in obj]
  • 字符串不会转换为 ASCII。如您引用的代码所示,使用了 Python 运行中定义的字符串表示(方法str)。碰巧在 Python 2 中字符串是字节。可能有一种方法可以制作特定于 Python 2 的补丁,但我宁愿建议更改默认编码(请参阅stackoverflow.com/questions/2276200/…),或者移至 Python 3。
猜你喜欢
  • 2014-08-16
  • 1970-01-01
  • 2020-09-16
  • 2018-08-19
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多