如何在R中读取包含字符串列的Pandas生成的HDF5文件?
如何在R中读取包含字符串列的Pandas生成的HDF5文件?
我完全理解你遇到的麻烦——用Pandas生成带字符串列的HDF5文件,到R里读要么字符串列变NA,要么直接丢列,确实挺头疼的。这本质上是因为Pandas的HDF table格式(你用append时默认用的就是这个格式)在存储字符串时的内部结构,和R的HDF5解析包(比如rhdf5、hdf5r)的兼容性不太好。下面给你几个可行的解决思路:
方法一:用reticulate在R里直接调用Pandas读取
这个方法最直接,相当于让Pandas自己来解析它生成的HDF5文件,再转成R的数据框,完美避免格式兼容问题。步骤如下:
- 先安装并加载reticulate包:
install.packages("reticulate") library(reticulate)
- 确保你的R能找到装有Pandas的Python环境(如果没装Pandas,可以用
py_install("pandas")来安装),然后执行读取代码:
# 导入Pandas库 pd <- import("pandas") # 读取HDF5文件里的df1 df1_py <- pd$read_hdf("test.h5", key = "df1") # 转换成R的dataframe df1_r <- as.data.frame(df1_py) # 查看结果 str(df1_r)
这样就能完整获取所有列,包括你之前丢失的字符串列和float列,完全和Pandas里的内容一致。
方法二:改用Parquet格式存储(更推荐的跨语言方案)
如果可以调整存储格式的话,Parquet是比HDF5更好的跨语言选择——它本身就是为跨语言数据共享设计的,Pandas和R都有完善的支持,而且支持追加写入,性能也很不错。
Pandas侧存储代码调整:
import pandas as pd import numpy as np import pyarrow as pa import pyarrow.parquet as pq letter_list = ['a', 'b', 'c', 'd'] word_list = ['apple', 'banana', 'cherry', 'date'] # 初始化Parquet写入器(针对df1) writer_df1 = None for i in range(3): df1 = pd.DataFrame({'integer': np.random.randint(1, 10, 2), 'float': np.random.rand(2), 'string': np.random.choice(word_list, 2), 'letter': np.random.choice(letter_list, 2), 'run': [i]*2}) df2 = pd.DataFrame({'integer': np.random.randint(1, 10, 2), 'float': np.random.rand(2), 'string': np.random.choice(word_list, 2), 'letter': np.random.choice(letter_list, 2), 'run': [i]*2}) # 写入df1到Parquet文件(支持追加) table_df1 = pa.Table.from_pandas(df1) if writer_df1 is None: writer_df1 = pq.ParquetWriter('df1.parquet', table_df1.schema) writer_df1.write_table(table_df1) # 同理写入df2到另一个Parquet文件 table_df2 = pa.Table.from_pandas(df2) # 这里可以单独初始化df2的writer,逻辑和上面一致 # 关闭写入器 writer_df1.close()
R侧读取代码:
install.packages("arrow") library(arrow) # 读取Parquet文件 df1 <- read_parquet("df1.parquet") str(df1)
这样读取出来的数据完全完整,没有任何列丢失或NA的问题,而且Parquet的压缩率和读取速度都很出色,适合长期存储和跨语言共享。
方法三:调整Pandas的HDF存储参数(尝试兼容R的解析)
如果你一定要用HDF5格式,可以试试在Pandas存储时把字符串列转成分类类型,这样存储的结构可能更被R的HDF5包接受:
Pandas侧修改:
for i in range(3): df1 = pd.DataFrame({'integer': np.random.randint(1, 10, 2), 'float': np.random.rand(2), 'string': np.random.choice(word_list, 2), 'letter': np.random.choice(letter_list, 2), 'run': [i]*2}) # 将字符串列转成category类型 df1['string'] = df1['string'].astype('category') df1['letter'] = df1['letter'].astype('category') df2 = pd.DataFrame({'integer': np.random.randint(1, 10, 2), 'float': np.random.rand(2), 'string': np.random.choice(word_list, 2), 'letter': np.random.choice(letter_list, 2), 'run': [i]*2}) df2['string'] = df2['string'].astype('category') df2['letter'] = df2['letter'].astype('category') store = pd.HDFStore('test.h5') store.append('df1', df1) store.append('df2', df2) store.close()
之后再用rhdf5或hdf5r读取,字符串列可能就能正常解析了,但这个方法的兼容性不如前两种,建议优先考虑前两种方案。
备注:内容来源于stack exchange,提问作者Michelle Johnson
相关产品推荐
相关产品推荐

