将Dask DataFrame写入S3时遇UTF8编码转换错误求解决
问题详情
执行以下Dask代码将DataFrame写入S3 Parquet时触发编码错误:
dd.from_pandas(pred, npartitions=npart).to_parquet(out_path)
报错信息:
error.. Error converting column "team_nm" to bytes using encoding UTF8. Original error: bad argument type for built-in operation Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/fastparquet/writer.py", line 175, in convert
out = array_encode_utf8(data)
File "fastparquet/speedups.pyx", line 60, in fastparquet.speedups.array_encode_utf8
TypeError: bad argument type for built-in operationDuring handling of the above exception, another exception occurred:
已尝试的无效操作:
- 将team_nm列编码为latin-1:
pred['team_nm'] = pred['team_nm'].str.encode("Latin-1") - 升级fastparquet从0.4.1到0.7.1
解决步骤
1. 排查列内的数据类型和异常值
报错核心原因大概率是team_nm列存在非字符串类型数据(比如混合了数字、列表、字典,或者非标准空值)。先在Pandas层面检查:
# 查看列的数据类型 print(pred['team_nm'].dtype) # 筛选出非字符串且非空值的行 non_str_rows = pred[~pred['team_nm'].apply(lambda x: isinstance(x, str) or pd.isna(x))] print(non_str_rows)
如果发现异常数据,统一转换为字符串:
pred['team_nm'] = pred['team_nm'].apply(lambda x: str(x) if pd.notna(x) else x)
2. 切换Parquet引擎或调整写入参数
尝试用pyarrow替代fastparquet引擎,避免fastparquet的C扩展编码问题:
dd.from_pandas(pred, npartitions=npart).to_parquet(out_path, engine='pyarrow')
如果坚持用fastparquet,试试禁用speedups或显式指定编码:
# 禁用C加速模块 dd.from_pandas(pred, npartitions=npart).to_parquet(out_path, engine='fastparquet', write_index=False) # 显式指定UTF-8编码 dd.from_pandas(pred, npartitions=npart).to_parquet(out_path, engine='fastparquet', encoding='UTF-8')
3. 强制转换为String类型
将team_nm列转为Pandas的String dtype(而非Object dtype),明确数据类型后再写入:
pred['team_nm'] = pred['team_nm'].astype('string') dd.from_pandas(pred, npartitions=npart).to_parquet(out_path)
4. 验证本地写入是否正常
先写入本地路径排除S3权限或路径问题:
dd.from_pandas(pred, npartitions=npart).to_parquet('./local_test.parquet')
如果本地写入正常,再排查S3的访问配置。
内容的提问来源于stack exchange,提问作者Justin Shan

