You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spark DataFrame转Pandas时None变回NaN(仅Python3.10存在)

问题描述

在Python 3.10环境下,把Spark DataFrame里的NaN替换成None后,转成Pandas DataFrame时,None又变回了NaN;但同样的操作在Python 3.6里不会出现这个问题。

复现代码及现象

环境信息

import sys
print(sys.executable)
print(sys.version)
print(sys.version_info)

输出:

3.10.11 (main, Apr 20 2023, 19:02:41) [GCC 11.2.0]
sys.version_info(major=3, minor=10, micro=11, releaselevel='final', serial=0)

创建Spark DataFrame

another_df = spark.createDataFrame([(float('nan'), 0.0),(0.0,float('nan'))])
another_df.show()

输出:

+---+---+
| _1| _2|
+---+---+
|NaN|0.0|
|0.0|NaN|
+---+---+

替换NaN为None

another_df = another_df.replace(float('nan'), None, subset=['_2'])
another_df.show()

输出:

+---+----+
| _1|  _2|
+---+----+
|NaN| 0.0|
|0.0|null|
+---+----+

转换为Pandas DataFrame

another_df.toPandas()

输出:

_1  _2
0  NaN  0.0
1  0.0  NaN
原因分析

核心原因很直接:
Spark里的None对应SQL的NULL,但如果列是浮点型(DoubleType/FloatType),Pandas在Python 3.10及更高版本中,会把Spark浮点列的NULL自动转成NaN——因为Pandas的数值类型列(比如float64)没法存储None,只能用NaN来表示空值。而Python 3.6环境用的PySpark或Pandas版本较低,当时的类型转换逻辑不同,所以None能被保留下来。

解决方案

方案1:先转字符串类型再转Pandas

把目标浮点列先转成字符串类型,替换NaN为None后再转Pandas,这样NULL会保留成None:

from pyspark.sql.types import StringType

# 将_2列转为字符串类型,再替换NaN为None
another_df = another_df.withColumn("_2", another_df["_2"].cast(StringType())) \
                       .replace(float('nan'), None, subset=['_2'])
# 转成Pandas DataFrame
pd_df = another_df.toPandas()
print(pd_df)

输出:

_1   _2
0  NaN  0.0
1  0.0  None

如果后续需要数值类型,再把列转回浮点型即可:

pd_df['_2'] = pd.to_numeric(pd_df['_2'], errors='coerce')

方案2:转Pandas后替换(转为object类型)

先转成Pandas DataFrame,再把目标列转为object类型,然后把NaN替换成None:

pd_df = another_df.toPandas()
# 转成object类型后替换NaN为None
pd_df['_2'] = pd_df['_2'].astype(object).where(pd_df['_2'].notna(), None)
print(pd_df)

输出:

_1   _2
0  NaN  0.0
1  0.0  None

注意:转为object类型后,列的数值运算性能会下降,适合小数据集场景。

方案3:用Spark UDF处理空值

自定义UDF把浮点列的NaN转为None,逻辑更灵活:

from pyspark.sql.functions import udf

def replace_nan_with_none(val):
    return None if val != val else val  # 通过val != val判断是否为NaN

replace_udf = udf(replace_nan_with_none)
another_df = another_df.withColumn("_2", replace_udf("_2"))
pd_df = another_df.toPandas()
print(pd_df)

这个方案和直接replace效果类似,但能应对更复杂的空值判断逻辑,最终转Pandas时同样需要配合类型转换来保留None。

内容的提问来源于stack exchange,提问作者hsekol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 21:52:59