Converting an RPy2 ListVector to a Python dictionary

I had the same problem with a deeply nested structure of different rpy2 vector types. I couldn't find a direct answer anywhere on stackoverflow, so here's my solution. Using CT Zhu's answer, I came up with the following code to convert the complete structure to python types recursively.

from collections import OrderedDict

import numpy as np

from rpy2.robjects.vectors import DataFrame, FloatVector, IntVector, StrVector, ListVector, Matrix


def recurse_r_tree(data):
    """
    step through an R object recursively and convert the types to python types as appropriate. 
    Leaves will be converted to e.g. numpy arrays or lists as appropriate and the whole tree to a dictionary.
    """
    r_dict_types = [DataFrame, ListVector]
    r_array_types = [FloatVector, IntVector, Matrix]
    r_list_types = [StrVector]
    if type(data) in r_dict_types:
        return OrderedDict(zip(data.names, [recurse_r_tree(elt) for elt in data]))
    elif type(data) in r_list_types:
        return [recurse_r_tree(elt) for elt in data]
    elif type(data) in r_array_types:
        return np.array(data)
    else:
        if hasattr(data, "rclass"):  # An unsupported r class
            raise KeyError('Could not proceed, type {} is not defined'
                           'to add support for this type, just add it to the imports '
                           'and to the appropriate type list above'.format(type(data)))
        else:
            return data  # We reached the end of recursion

Simple R list to Python dictionary:

>>> 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}

Arbitrary R object to Python object using R RJSONIO JSON serialization/deserialization

On R server: 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}

I think to get a r vector into a dictionary does not have to be so involving, how about this:

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']}

And of course, if you don't mind using pandas, it is even easier. The result will have numpy.array instead of list, but that will be OK in most cases:

In [294]:

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

Tags:

Python

Rpy2