[英]Converting an RPy2 ListVector to a Python dictionary
與 R 中的命名列表等價的自然 Python 是一個 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 內置的東西?
我認為將 ar 向量放入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)}
>>> 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 服務器上: 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}
我對不同 rpy2 向量類型的深度嵌套結構有同樣的問題。 我在 stackoverflow 上的任何地方都找不到直接的答案,所以這是我的解決方案。 使用 CT Zhu 的回答,我想出了以下代碼,以遞歸方式將完整結構轉換為 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
您還可以執行以下操作:
在
dict(a.items())
出去
{'foo': R object with classes: ('character',) mapped to:
['barbat'], 'fizz': R object with classes: ('numeric',) mapped to:
[123.000000]}
有了新版的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])
以下是我將 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
將嵌套的 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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.