如何用Python读取Parquet元数据中R存储的data.table?
在Python中解析R写入Parquet的元数据(data.table属性)
问题背景
我用R的data.table和arrow包创建了一个Parquet文件,其中主数据是一个data.table,同时给它附加了另一个作为元数据的data.table。R环境下可以轻松读取这份元数据,但在Python中用pyarrow读取时,拿到的是无法直接识别的二进制数据,想知道如何解析这份元数据并转为DataFrame。
R中创建带元数据的Parquet文件
library(data.table) library(arrow) dt = data.table(x = c(1, 2, 3), y = c("a", "b", "c")) dt2 = data.table(a = 22222, b = 45555) attr(dt, "dt_meta") = dt2 tb = arrow_table(dt) tb$metadata write_parquet(tb, "file.parquet")
R中读取元数据的方式
# 方式1:通过open_dataset读取 dt = open_dataset("file.parquet") dt$metadata$r$attributes$dt_meta # 方式2:直接读取文件 dt2 = read_parquet("file.parquet") attributes(dt2)$dt_meta
Python中遇到的问题
用pyarrow读取Parquet元数据时,r字段返回的是二进制数据,无法直接解析:
import pyarrow.parquet as pq mt = pq.read_metadata("file.parquet") metadata = mt.metadata[b'r'] metadata
输出的二进制内容:
b'A\n3\n263169\n197888\n5\nUTF-8\n531\n2\n531\n3\n16\n2\n262153\n10\ndata.table\n262153\n10\ndata.frame\n22\n22\n254\n254\n16\n2\n262153\n1\nx\n262153\n1\ny\n787\n2\n14\n1\n22222\n14\n1\n45555\n1026\n1\n262153\n5\nnames\n16\n2\n262153\n1\na\n262153\n1\nb\n1026\n1\n262153\n9\nrow.names\n13\n2\nNA\n-1\n1026\n1\n262153\n5\nclass\n16\n2\n262153\n10\ndata.table\n262153\n10\ndata.frame\n1026\n1\n262153\n17\n.internal.selfref\n22\n22\n254\n254\n16\n2\n262153\n1\na\n262153\n1\nb\n254\n1026\n1023\n16\n3\n262153\n5\nclass\n262153\n17\n.internal.selfref\n262153\n7\ndt_meta\n254\n531\n2\n254\n254\n1026\n1023\n16\n2\n262153\n1\nx\n262153\n1\ny\n254\n1026\n1023\n16\n2\n262153\n10\nattributes\n262153\n7\ncolumns\n254\n'
解析方案
这份二进制数据是R用serialize()函数生成的序列化对象,不是普通文本编码,必须用支持R反序列化的工具处理,以下是两种可行方法:
方法1:用rpy2直接解析
rpy2可以在Python中调用R的反序列化逻辑,无需临时文件:
- 先安装依赖:
pip install rpy2 - 执行代码:
import pyarrow.parquet as pq from rpy2.robjects import r, pandas2ri # 读取Parquet元数据 mt = pq.read_metadata("file.parquet") r_serialized = mt.metadata[b'r'] # 开启R与pandas的数据转换支持 pandas2ri.activate() # 调用R的unserialize解析二进制,再转为DataFrame r_obj = r['unserialize'](r_serialized) dt_meta_df = pandas2ri.rpy2py(r_obj.rx2('attributes').rx2('dt_meta')) print(dt_meta_df)
输出结果:
a b 0 22222 45555
方法2:用pyreadr解析
pyreadr专门处理R相关文件,需要通过临时文件中转:
- 安装依赖:
pip install pyreadr - 执行代码:
import pyarrow.parquet as pq import pyreadr import tempfile import os # 读取元数据二进制 mt = pq.read_metadata("file.parquet") r_serialized = mt.metadata[b'r'] # 将二进制写入临时RDS文件 with tempfile.NamedTemporaryFile(delete=False, suffix='.rds') as tmp: tmp.write(r_serialized) tmp_path = tmp.name # 读取并解析临时文件 result = pyreadr.read_r(tmp_path) # 提取dt_meta属性 dt_meta_df = result[None].attrs['dt_meta'] # 清理临时文件 os.unlink(tmp_path) print(dt_meta_df)
同样能得到目标DataFrame。
关键说明
- R的arrow包写入Parquet时,会把R对象的属性用
serialize()序列化后存入元数据的r字段,所以Python无法直接解码,必须借助R的反序列化逻辑。 - rpy2需要本地有R环境支持,操作更直接;pyreadr对环境依赖稍弱,但需要临时文件中转。
内容的提问来源于stack exchange,提问作者julien.leroux5
相关产品推荐
相关产品推荐

