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