Search code examples
pythonrpy2

Converting an RPy2 ListVector to a Python dictionary


The natural Python equivalent to a named list in R is a dict, but RPy2 gives you a ListVector object.

import rpy2.robjects as robjects

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

At this point, a is a ListVector object.

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

What I'd like to have is something I can treat like a normal Python dictionary. My temporary hack-around is this:

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

So, the question is... Is there a better way or something built into RPy2 that I should be using?


Solution

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