存储含混合数据类型(时间戳与字符串)列的Pandas DataFrame为Parquet文件时遇类型转换错误的解决方法
解决Pandas DataFrame存储Parquet时的ArrowTypeError问题
嘿,这个问题我之前刚踩过坑!你完全猜对了——就是foo列里同时混了Timestamp和字符串类型才触发的这个pyarrow.lib.ArrowTypeError。Parquet(准确说背后的pyarrow引擎)对列类型的一致性要求很严格,同一列里不能同时存两种不兼容的类型,所以得先把数据类型统一或者拆分处理才行。给你几个实用的解决方案:
方案1:统一转换为字符串类型(最简单)
如果你的业务场景允许把时间戳转成字符串格式,直接把整列统一成字符串类型就搞定了:
#!/usr/bin/env python3 import pandas df = pandas.DataFrame( data={ 'foo': [pandas.Timestamp('2022-06-01'), 'foobar'] } ) # 将Timestamp转为指定格式的字符串,非时间戳元素保持原样 df['foo'] = df['foo'].apply(lambda x: x.strftime('%Y-%m-%d') if isinstance(x, pandas.Timestamp) else x) # 现在可以顺利写入Parquet了 df.to_parquet('output.parquet')
这样整列都是字符串类型,完全符合Parquet的列类型要求。
方案2:拆分成两列分别存储(最规范)
如果需要保留原始的时间戳类型,更专业的做法是把混合数据拆成两个独立列:一列专门存时间戳,另一列存字符串,空值用pandas.NaT/None填充:
#!/usr/bin/env python3 import pandas df = pandas.DataFrame( data={ 'foo': [pandas.Timestamp('2022-06-01'), 'foobar'] } ) # 新增时间戳列,只保留原列中的Timestamp元素,其余填NaT df['foo_timestamp'] = df['foo'].apply(lambda x: x if isinstance(x, pandas.Timestamp) else pandas.NaT) # 新增字符串列,只保留原列中的字符串元素,其余填None df['foo_str'] = df['foo'].apply(lambda x: x if isinstance(x, str) else None) # 删除原混合类型列,写入Parquet df.drop('foo', axis=1).to_parquet('output_separated.parquet')
这种方式能完整保留原始数据的类型信息,后续数据分析时也更清晰,是推荐的做法。
方案3:标记类型后存为结构化对象(进阶,不推荐)
如果一定要在一列里保留混合类型,也可以把每个元素转成带类型标记的结构化对象,但这种方式会失去Parquet的类型优化优势,后续读取还需要手动解析:
#!/usr/bin/env python3 import pandas df = pandas.DataFrame( data={ 'foo': [pandas.Timestamp('2022-06-01'), 'foobar'] } ) # 把每个元素转为包含类型标记的字典 df['foo'] = df['foo'].apply( lambda x: {'type': 'timestamp', 'value': x} if isinstance(x, pandas.Timestamp) else {'type': 'str', 'value': x} ) # 指定dtype为object后写入Parquet df.to_parquet('output_struct.parquet', engine='pyarrow', dtype={'foo': 'object'})
除非有特殊业务需求,否则优先用前两种方案哦。
内容的提问来源于stack exchange,提问作者buhtz
相关产品推荐
相关产品推荐

