importrpy2.robjectsasroimportrpy2.robjects.conversionasconversionimportrpy2.rinterfaceasrinterfacefromrpy2.rinterfaceimportSexpVector,INTSXPfrompandas.core.frameimportDataFrameasPandasDataFramefrompandas.core.seriesimportSeriesasPandasSeriesfrompandas.core.indeximportIndexasPandasIndeximportpandasfromnumpyimportrecarrayimportnumpyfromcollectionsimportOrderedDictfromrpy2.robjects.vectorsimport(DataFrame,Vector,ListVector,StrVector,IntVector,POSIXct)fromrpy2.rinterfaceimport(IntSexpVector,ListSexpVector)original_converter=None# pandas is requiring numpy. We add the numpy conversion will be# activate in the function activate() belowimportrpy2.robjects.numpy2riasnumpy2riISOdatetime=rinterface.baseenv['ISOdatetime']converter=conversion.Converter('original pandas conversion')py2ri=converter.py2ripy2ro=converter.py2rori2py=converter.ri2pyri2ro=converter.ri2ro@py2ri.register(PandasDataFrame)defpy2ri_pandasdataframe(obj):od=OrderedDict()forname,valuesinobj.iteritems():ifvalues.dtype.kind=='O':od[name]=StrVector(values)else:od[name]=conversion.py2ri(values)returnDataFrame(od)@py2ri.register(PandasIndex)defpy2ri_pandasindex(obj):ifobj.dtype.kind=='O':returnStrVector(obj)else:# pandas2ri should definitely not have to know which paths remain to be# converted by numpy2ri# Answer: the thing is that pandas2ri builds on the conversion# rules defined by numpy2ri - deferring to numpy2ri is allowing# us to reuse that code.returnnumpy2ri.numpy2ri(obj)@py2ri.register(PandasSeries)defpy2ri_pandasseries(obj):ifobj.dtype=='<M8[ns]':# time seriesd=[IntVector([x.yearforxinobj]),IntVector([x.monthforxinobj]),IntVector([x.dayforxinobj]),IntVector([x.hourforxinobj]),IntVector([x.minuteforxinobj]),IntVector([x.secondforxinobj])]res=ISOdatetime(*d)#FIXME: can the POSIXct be created from the POSIXct constructor ?# (is '<M8[ns]' mapping to Python datetime.datetime ?)res=POSIXct(res)else:# converted as a numpy arrayres=numpy2ri.numpy2ri(obj.values)# "index" is equivalent to "names" in Rifobj.ndim==1:res.do_slot_assign('names',StrVector(tuple(str(x)forxinobj.index)))else:res.do_slot_assign('dimnames',SexpVector(conversion.py2ri(obj.index)))returnres@ri2py.register(SexpVector)defri2py_vector(obj):res=numpy2ri.ri2py(obj)returnres@ri2py.register(IntSexpVector)defri2py_intvector(obj):# special case for factorsif'factor'inobj.rclass:res=pandas.Categorical.from_codes(numpy.asarray(obj)-1,categories=obj.do_slot('levels'),ordered='ordered'inobj.rclass)else:res=numpy2ri.ri2py(obj)returnres@ri2py.register(ListSexpVector)defri2py_listvector(obj):if'data.frame'inobj.rclass:res=ri2py.registry[DataFrame](obj)else:res=numpy2ri.ri2py(obj)returnres@ri2py.register(DataFrame)defri2py_dataframe(obj):# use the numpy converterrecarray=numpy2ri.ri2py(obj)try:idx=numpy2ri.ri2py(obj.do_slot('row.names'))exceptLookupErrorasle:idx=Noneres=PandasDataFrame.from_records(recarray,index=idx)returnresdefactivate():globaloriginal_converter# If module is already activated, there is nothing to doiforiginal_converterisnotNone:returnoriginal_converter=conversion.Converter('snapshot before pandas conversion',template=conversion.converter)numpy2ri.activate()new_converter=conversion.Converter('snapshot before pandas conversion',template=conversion.converter)numpy2ri.deactivate()fork,vinpy2ri.registry.items():ifkisobject:continuenew_converter.py2ri.register(k,v)fork,vinri2ro.registry.items():ifkisobject:continuenew_converter.ri2ro.register(k,v)fork,vinpy2ro.registry.items():ifkisobject:continuenew_converter.py2ro.register(k,v)fork,vinri2py.registry.items():ifkisobject:continuenew_converter.ri2py.register(k,v)conversion.set_conversion(new_converter)defdeactivate():globaloriginal_converter# If module has never been activated or already deactivated,# there is nothing to doiforiginal_converterisNone:returnconversion.set_conversion(original_converter)original_converter=None