Преобразование RPY2 ListVector в словарь Python

Естественный эквивалент Python для именованного списка в R является dict, но RPy2 дает вам ListVector.

import rpy2.robjects as robjects

a = robjects.r('list(foo="barbat", fizz=123)')

На этом этапе a является объектом ListVector.

<ListVector - Python:0x108f92a28 / R:0x7febcba86ff0>
[StrVector, FloatVector]
  foo: <class 'rpy2.robjects.vectors.StrVector'>
  <StrVector - Python:0x108f92638 / R:0x7febce0ae0d8>
[str]
  fizz: <class 'rpy2.robjects.vectors.FloatVector'>
  <FloatVector - Python:0x10ac38fc8 / R:0x7febce0ae108>
[123.000000]

То, что я хотел бы иметь, - это то, что я могу рассматривать как обычный словарь Python. Мой временный взлом - это:

def as_dict(vector):
    """Convert an RPy2 ListVector to a Python dict"""
    result = {}
    for i, name in enumerate(vector.names):
        if isinstance(vector[i], robjects.ListVector):
            result[name] = as_dict(vector[i])
        elif len(vector[i]) == 1:
            result[name] = vector[i][0]
        else:
            result[name] = vector[i]
    return result

as_dict(a)
{'foo': 'barbat', 'fizz': 123.0}

b = robjects.r('list(foo=list(bar=1, bat=c("one","two")), fizz=c(123,345))')
as_dict(b)
{'fizz': <FloatVector - Python:0x108f7e950 / R:0x7febcba86b90>
 [123.000000, 345.000000],
 'foo': {'bar': 1.0, 'bat': <StrVector - Python:0x108f7edd0 / R:0x7febcba86ea0>
  [str, str]}}

Итак, вопрос в том... Есть ли лучший способ или что-то встроенное в RPy2, которое я должен использовать?

Ответ 1

Я думаю, что получить вектор r в dictionary не обязательно должен быть таким, как об этом:

In [290]:

dict(zip(a.names, list(a)))
Out[290]:
{'fizz': <FloatVector - Python:0x08AD50A8 / R:0x10A67DE8>
[123.000000],
 'foo': <StrVector - Python:0x08AD5030 / R:0x10B72458>
['barbat']}
In [291]:

dict(zip(a.names, map(list,list(a))))
Out[291]:
{'fizz': [123.0], 'foo': ['barbat']}

И, конечно, если вы не против использования pandas, это еще проще. Результат будет numpy.array вместо list, но в большинстве случаев это будет нормально:

In [294]:

import pandas.rpy.common as com
com.convert_robj(a)
Out[294]:
{'fizz': [123.0], 'foo': array(['barbat'], dtype=object)}

Ответ 2

Простой список R в словарь Python:

>>> import rpy2.robjects as robjects
>>> a = robjects.r('list(foo="barbat", fizz=123)')
>>> d = { key : a.rx2(key)[0] for key in a.names }
>>> d
{'foo': 'barbat', 'fizz': 123.0}

Арбитражный объект R для объекта Python с использованием сериализации/десериализации R RJSONIO JSON

На сервере R: install.packages( "RJSONIO", dependencies = TRUE)

>>> ro.r("library(RJSONIO)")
<StrVector - Python:0x300b8c0 / R:0x3fbccb0>
[str, str, str, ..., str, str, str]
>>> import rpy2.robjects as robjects
>>> rjson = robjects.r(' toJSON( list(foo="barbat", fizz=123, lst=list(33,"bb")) )  ')
>>> pyobj = json.loads( rjson[0] )
>>> pyobj
{u'lst': [33, u'bb'], u'foo': u'barbat', u'fizz': 123}
>>> pyobj['lst']
[33, u'bb']
>>> pyobj['lst'][0]
33
>>> pyobj['lst'][1]
u'bb'
>>> rjson = robjects.r(' toJSON( list(foo="barbat", fizz=123, lst=list( key1=33,key2="bb")) )  ')
>>> pyobj = json.loads( rjson[0] )
>>> pyobj
{u'lst': {u'key2': u'bb', u'key1': 33}, u'foo': u'barbat', u'fizz': 123}

Ответ 3

У меня была та же проблема с глубоко вложенной структурой разных типов векторов rpy2. Я не мог найти прямой ответ в любом месте stackoverflow, так что вот мое решение. Используя CT Zhu answer, я придумал следующий код для рекурсивного преобразования полной структуры в типы python.

from rpy2.robjects.vectors import DataFrame, FloatVector, IntVector, StrVector, ListVector
import numpy
from collections import OrderedDict

def recurList(data):
    rDictTypes = [ DataFrame,ListVector]
    rArrayTypes = [FloatVector,IntVector]
    rListTypes=[StrVector]
    if type(data) in rDictTypes:
        return OrderedDict(zip(data.names, [recurList(elt) for elt in data]))
    elif type(data) in rListTypes:
        return [recurList(elt) for elt in data]
    elif type(data) in rArrayTypes:
        return numpy.array(data)
    else:
        if hasattr(data, "rclass"): # An unsupported r class
            raise KeyError('Could not proceed, type {} is not defined'.format(type(data)))
        else:
            return data # We reached the end of recursion

Ответ 4

С новой версией pandas можно было бы сделать,

import rpy2.robjects as robjects
a = robjects.r('list(foo="barbat", fizz=123)')

from rpy2.robjects import pandas2ri
print(pandas2ri.ri2py(a.names))
temp = pandas2ri.ri2py(a)
print(temp[0])
print(temp[1])

Ответ 5

Ниже приведена моя функция для преобразования из rpy2 ListVector в python dict, способного обрабатывать вложенные списки:

import rpy2.robjects as ro
from rpy2.robjects import pandas2ri

def r_list_to_py_dict(r_list):
    converted = {}
    for name in r_list.names:
        val = r_list.rx(name)[0]
        if isinstance(val, ro.vectors.DataFrame):
            converted[name] = pandas2ri.ri2py_dataframe(val)
        elif isinstance(val, ro.vectors.ListVector):
            converted[name] = r_list_to_py_dict(val)
        elif isinstance(val, ro.vectors.FloatVector) or isinstance(val, ro.vectors.StrVector):
            if len(val) == 1:
                converted[name] = val[0]
            else:
                converted[name] = list(val)
        else: # single value
            converted[name] = val
    return converted

Ответ 6

Простая функция для преобразования вложенных списков имен R во вложенный словарь Python:

def rext(r):
    """
    Returns a R named list as a Python dictionary
    """
    # In case `r` is not a named list
    try:
        # No more names, just return the value!
        if r.names == NULL:
            # If more than one value, return numpy array (or list)
            if len(list(r)) > 1:
                return np.array(r)
            # Just one value, return the value
            else:
                return list(r)[0]
        # Create dictionary to hold named list as key-value
        dic = {}
        for n in list(r.names):
            dic[n] = rext(r[r.names.index(n)])
        return dic
    # Uh-oh `r` is not a named list, just return `r` as is
    except:
        return r