PySpark转Pandas时datetime类型传递的正确方法
问题现象
将Spark DataFrame转换为Pandas DataFrame时,不同版本Pandas会触发不同的兼容性问题:
- 在 Python 3.9 + PySpark 3.4.0 + Pandas 1.5.3 环境下,会抛出FutureWarning:
/Users/[me]/miniconda3/envs/py39/lib/python3.9/site-packages/pyspark/sql/pandas/conversion.py:251: FutureWarning: Passing unit-less datetime64 dtype to .astype is deprecated and will raise in a future version. Pass 'datetime64[ns]' instead
series = series.astype(t, copy=False)
- 升级到 Pandas 2.0.0及以上版本 时,该警告会变为直接报错,核心要求是必须传入带单位的
datetime64[ns]类型,而非无单位的datetime64。
问题根源
问题出在PySpark的类型转换逻辑中:pyspark/sql/pandas/conversion.py文件的第251行代码,使用了无单位的datetime64类型调用Pandas的astype方法。而Pandas从1.5.x版本开始废弃了无单位datetime类型的传入方式,2.0+版本则直接禁止该用法,从而引发警告或报错。
复现代码
from pyspark.sql.types import StructType,StructField, StringType, IntegerType, TimestampType, FloatType from pyspark.sql import SparkSession import datetime spark = ( SparkSession .builder .getOrCreate() ) testAggData = [ { 'postId': '1234567', 'title': 'Test1', 'createdTSUTC': datetime.strptime('2023-04-19 03:14:30', '%Y-%m-%d %H:%M:%S'), }, { 'postId': '1234568', 'title': 'Test2', 'createdTSUTC': datetime.strptime('2023-04-20 03:14:30', '%Y-%m-%d %H:%M:%S'), } ] testSchema = StructType([ StructField("postId", StringType(), False), StructField("title", StringType(), False), StructField("createdTSUTC", TimestampType(), False), ]) testAggDataDf = spark.createDataFrame(testAggData, testSchema).toPandas()
解决方案
临时规避:降低Pandas版本
将Pandas版本回退到1.5.3以下,暂时避开该兼容性限制,但这只是临时方案,不利于后续版本升级。手动修复PySpark源码
找到PySpark安装目录下的pyspark/sql/pandas/conversion.py文件,定位到第251行,将无单位的datetime64替换为datetime64[ns],确保类型传入符合Pandas的要求。长期方案:等待官方修复
该问题属于PySpark与新版本Pandas的兼容性bug,可关注PySpark官方更新日志,后续版本会针对性修复该类型转换逻辑。
内容的提问来源于stack exchange,提问作者Ken Myers

