2015-02-05 3 views
2

Я использую библиотеку randomForest в R по адресу RPy2. Я хотел бы вернуть значения, рассчитанные с использованием метода caretpredict, и объединить их с исходным pandas. См. Пример ниже.Rpy2 и Pandas: объединить выходные данные от pandas dataframe

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 dataframe или сравнить с исходными значениями?

Я попытался это:

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

Но это возвращает словарь, где ключи являются строками. Я думаю, что есть работа вокруг withheld.reset_index(), а затем преобразование ключей dict в целые числа, а затем объединение двух, но должен быть более простой способ!

ответ

3

Факс: a pull-request that adds R factor to Pandas Categorical functionality Пандас. Он еще не слит в ветви мастера Панды. Когда он,

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

преобразует pr в панды категоричен. До тех пор, вы можете использовать в качестве временного решения:

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

R объект pr возвращенное функцией predict является "вектор", который вы можете думать как 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):

Примечание: Версия 2.6.0 от rpy2 будет включать в себя обработку панд 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 будет возвращать панд Categorical всякий раз, когда есть фактор R:

robjects.conversion.ri2py(pr) 

Вы можете решить, чтобы добавить результат это последнее преобразование в таблицу данных.

Обратите внимание, что преобразование в объекты, не относящиеся к rpy2, должно быть явным (один вызывает преобразователь). Если вы используете ipython, есть способ сделать это неявным: https://gist.github.com/lgautier/e2e8709776e0e0e93b8d (и исходящая нить https://bitbucket.org/rpy2/rpy2/issue/230/rmagic-specific-conversion).

Смежные вопросы