Rpy2 和 Pandas:将预测的输出连接到 pandas 数据帧

Posted

技术标签:

【中文标题】Rpy2 和 Pandas:将预测的输出连接到 pandas 数据帧【英文标题】:Rpy2 and Pandas: join output from predict to pandas dataframe 【发布时间】:2015-04-05 21:31:27 【问题描述】:

我通过 RPy2 在 R 中使用 randomForest 库。我想传回使用caretpredict 方法计算的值并将它们加入原始pandas 数据帧。请参见下面的示例。

import pandas as pd
import numpy as np
import rpy2.robjects as robjects
from rpy2.robjects import pandas2ri
pandas2ri.activate()
r = robjects.r
r.library("randomForest")
r.library("caret")

df = pd.DataFrame(data=np.random.rand(100, 10), columns=["a".format(i) for i in range(10)])
df["b"] = ['a' if x < 0.5 else 'b' for x in np.random.sample(size=100)]
train = df.ix[df.a0 < .75]
withheld = df.ix[df.a0 >= .75]

rf = r.randomForest(robjects.Formula('b ~ .'), data=train)
pr = r.predict(rf, withheld)
print pr.rx()

返回

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 
 a  a  b  b  b  a  a  a  a  b  a  a  a  a  a  b  a  a  a  a 
Levels: a b

但是join 这个如何与withheld 数据框比较或与原始值进行比较?

我试过这个:

import pandas.rpy.common as com
com.convert_robj(pr)

但这会返回一个字典,其中键是字符串。我想有一个解决方法 withheld.reset_index() 然后将 dict 键转换为整数,然后将两者连接起来,但必须有一个更简单的方法!

【问题讨论】:

【参考方案1】:

函数predict返回的R对象pr是一个“向量”,你可以把它看成一个Python的array.array,或者numpy的一维数组。

“加入”不是必需的,因为pr 中元素的顺序对应于表withheld 中的行。只需将pr 作为附加列添加到withheld (见Adding new column to existing DataFrame in Python pandas):

withheld['predictions'] = pd.Series(pr,
                                    index=withheld.index)

默认情况下,这将添加一列整数(因为 R 因子被编码为整数)。可以很简单地自定义 rpy2 的转换 (见http://rpy.sourceforge.net/rpy2/doc-2.5/html/robjects_convert.html):

注意: rpy2 的 2.6.0 版本将包括处理 pandas Categorical 向量,因此无需对下面描述的转换器进行自定义。

@robjects.conversion.ri2py.register(robjects.rinterface.SexpVector)
def ri2py_vector(vector):
    # based on
    # https://bitbucket.org/rpy2/rpy2/src/a75413b09852991869332da615fa754923c32039/rpy/robjects/pandas2ri.py?at=default#cl-73

    # special case for factors
    if 'factor' in vector.rclass:
        res = pd.Categorical.from_codes(np.asarray(vector) - 1,
                                        categories = vector.do_slot('levels'),
                                        ordered = 'ordered' in vector.rclass)
    else:
        # use the numpy converter first
        res = numpy2ri.ri2py(obj)
    if isinstance(res, recarray):
        res = PandasDataFrame.from_records(res)
    return res

有了这个,任何 rpy2 对象到非 rpy2 对象的转换都将返回一个 pandas Categorical,只要有一个 R 因子:

robjects.conversion.ri2py(pr)

您可以决定将最后一次转换的结果添加到您的数据表中。

请注意,到非 rpy2 对象的转换必须是显式的(调用转换器)。如果您使用的是 ipython,有一种方法可以使其隐含: https://gist.github.com/lgautier/e2e8709776e0e0e93b8d (以及原始线程https://bitbucket.org/rpy2/rpy2/issue/230/rmagic-specific-conversion)。

【讨论】:

【参考方案2】:

有a pull-request that adds R factor to Pandas Categorical functionality 给熊猫。它尚未合并到 Pandas 主分支中。到时候,

import pandas.rpy.common as rcom
rcom.convert_robj(pr)

pr 转换为 Pandas 分类。 在此之前,您可以使用以下解决方法:

def convert_factor(obj):
    """
    Taken from jseabold's PR: https://github.com/pydata/pandas/pull/9187
    """
    ordered = r["is.ordered"](obj)[0]
    categories = list(obj.levels)
    codes = np.asarray(obj) - 1  # zero-based indexing
    values = pd.Categorical.from_codes(codes, categories=categories,
                                       ordered=ordered)
    return values

例如,

import pandas as pd
import numpy as np
import rpy2.robjects as robjects
from rpy2.robjects import pandas2ri
pandas2ri.activate()
r = robjects.r
r.library("randomForest")
r.library("caret")

def convert_factor(obj):
    """
    Taken from jseabold's PR: https://github.com/pydata/pandas/pull/9187
    """
    ordered = r["is.ordered"](obj)[0]
    categories = list(obj.levels)
    codes = np.asarray(obj) - 1  # zero-based indexing
    values = pd.Categorical.from_codes(codes, categories=categories,
                                       ordered=ordered)
    return values


df = pd.DataFrame(data=np.random.rand(100, 10), 
                  columns=["a".format(i) for i in range(10)])
df["b"] = ['a' if x < 0.5 else 'b' for x in np.random.sample(size=100)]
train = df.ix[df.a0 < .75]
withheld = df.ix[df.a0 >= .75]

rf = r.randomForest(robjects.Formula('b ~ .'), data=train)
pr = convert_factor(r.predict(rf, withheld))

withheld['pr'] = pr
print(withheld)

【讨论】:

以上是关于Rpy2 和 Pandas:将预测的输出连接到 pandas 数据帧的主要内容,如果未能解决你的问题,请参考以下文章

rpy2

使用 Scikit-learn 和 Pandas 将编码列连接到原始数据帧

如何将多个列值连接到 Pandas 数据框中的单个列中

需要 SSL 时将 Python/pandas 连接到 Redshift

Pandas TypeError:只能将str(不是“int”)连接到str

如何将多个 csv 文件连接到 pandas 数据框中,文件名作为行名?