python file not - Converting an RPy2 ListVector to a Python dictionary




3 Answers

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

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?




I had the same problem with a deeply nested structure of different rpy2 vector types. I couldn't find a direct answer anywhere on , 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 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



A simple function to convert nested R named lists into a nested Python dictionary :

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



Related


Tags

python   rpy2