读取Excel转JSON存储HDFS时遇Spark类型合并错误
我帮你分析下这个问题——你遇到的TypeError: Can not merge type <class 'pyspark.sql.types.StringType'> and <class 'pyspark.sql.types.DoubleType'>本质上是因为你的Pandas DataFrame里同一列同时存在字符串和数值两种类型的数据,Spark在创建DataFrame时无法自动将这两种不兼容的类型合并成统一的列类型,所以抛出了这个错误。
问题根源定位
看你的代码里用了这行:
data[c] = pd.to_numeric(data[c], errors='ignore')
errors='ignore'这个参数的作用是:如果某行数据无法转换成数值类型,就保留它原来的字符串格式不变。这就导致同一列里既有成功转成Double的数值,又有没转成的字符串,两种类型混在一列里,Spark自然没法处理。
具体解决方法
下面给你几个不同场景下的解决方案:
方案1:统一转为字符串类型(快速解决)
如果你的业务场景不需要对这些数据做数值计算,直接把所有列转成字符串就能彻底解决类型冲突:
# 替换原来的pd.to_numeric循环 data = data.astype(str)
这样Spark创建DataFrame时,所有列都是StringType,就不会有类型合并的问题了。
方案2:强制统一为数值类型(保留可转换数据)
如果需要保留数值类型,把无法转换的内容转为NaN(后续可以根据业务逻辑处理这些NaN),只需要把errors='ignore'改成errors='coerce':
for c in data.columns: data[c] = pd.to_numeric(data[c], errors='coerce')
errors='coerce'会把所有无法转成数值的内容变成NaN,整列类型就统一为float(对应Spark的DoubleType),Spark就能正常识别了。
方案3:排查问题列后针对性处理
如果你想精确知道哪一列出了问题,可以先检查每列的类型分布:
for col in data.columns: type_counts = data[col].apply(type).value_counts() print(f"列{col}的类型分布:\n{type_counts}\n")
找到混合类型的列后,再针对性处理——比如把字符串类型的行筛选出来单独修正,或者替换成符合业务逻辑的数值。
额外的代码优化建议
- 你的
data变量是在if sheet_name=='Passed':的分支里定义的,要是这个sheet不存在,后续代码会直接报错,建议加个判断:
data = None for sheet_name in excel_file.sheet_names: df = pd.read_excel(excel_file, header=None, squeeze=True, sheet_name=sheet_name) if sheet_name=='Passed': print(f'**************{sheet_name}******************') for i, row in df.iterrows(): data = df.iloc[(i+1):].reset_index(drop=True) data.columns = pd.Series(list(df.iloc[i])).str.replace(' ','_') break if data is not None: # 后续的类型转换、Spark处理逻辑放在这里 ...
- 注意Python版本兼容:Python3里
print需要加括号,建议把字符串拼接改成f-string写法更简洁。
内容的提问来源于stack exchange,提问作者Krishna

