Pyspark:DataFrame遇到的数据类型问题汇总

Pyspark版本:V3.2.1

  关于Pyspark.sql中的DataFrame中的数据类型,可以参考博客:https://blog.csdn.net/yeshang_lady/article/details/89528090。这篇博客主要介绍使用DataFrame时遇到的数据类型问题。

1 创建DataFrame时的数据类型问题

1.1 同一字段Int和Float型混用导致创建不成功

  因为Python是动态类型语言,所以其在定义变量时不需要特地声明变量类型,而且变量可以根据条件改变自身结构。但是发现把这种习惯带到Pyspark.sql的DataFrame中时却频繁报错。举例如下:

from pyspark.sql import SparkSession
import os
from pyspark.ml.linalg import Vectors
from pyspark.sql.types import *
from pyspark.sql import functions as func

os.environ['SPARK_HOME'] ='/Users/sherry/documents/spark/spark-3.2.1-bin-hadoop3.2'
spark=SparkSession.builder.appName('ml').getOrCreate()

data=spark.createDataFrame([[Vectors.dense([1,3]),[1,2,3]],
                            [Vectors.dense([2,3]),[1.0,2.0,3.0]]])

运行上述代码会提示如下错误:TypeError: element in array field _2: Can not merge type <class ‘pyspark.sql.types.LongType’> and <class ‘pyspark.sql.types.DoubleType’>。所以DataFrame并不会根据需要改变变量的结构,同一个列的数据的类型必须一致。

1.2 数据类型与schema指定的不一致导致创建不成功

  如果使用数据推断出的数据类型与schema指定的数据类型不一致,同样也会报错。举例如下:

data=spark.createDataFrame([[1,2,3],
                            [2,3,3.4]],
                           schema='A INT,B DOUBLE,C FLOAT')

运行上述代码会提示如下错误:TypeError: field B: DoubleType can not accept object 2 in type <class ‘int’>。对于字段B,传入的是Int型,但是声明的确是Double型。

1.3 传入Numpy型数据导致创建不成功
  • DataFrame不能识别numpy中的数据类型。具体如下:
import numpy as np
data=spark.createDataFrame([[1,np.int8(2)],
                            [4,5]],['a','b'])

上述代码运行不成功,会提示如下错误:TypeError: Unable to infer the type of the field b.

  • DataFrame中的ArrayType类型可以接受List、Tuple,但无法接受Numpy中的array。举例如下:
data=spark.createDataFrame([([1,2,3],),
                            ([2,4,5],)],
                           schema=StructType([StructField('A', ArrayType(IntegerType()))])
                           )
                           
data1=spark.createDataFrame([((1,2,3),),
                             ((2,4,5),)],
                           schema=StructType([StructField('A', ArrayType(IntegerType()))])
                           )
                           
data2=spark.createDataFrame([(np.array([1,2,3]),),
                            (np.array([2,4,5]),)],
                           schema=StructType([StructField('A', ArrayType(IntegerType()))])
                           )

运行上述代码会发现data和data1会顺利执行,但data2无法执行(仍然是TypeError错误)。

2 自定义函数遇到的问题

2.1 处理Vectors变量不要转换成numpy型数据

  虽然Vectors变量可以作为Pyspark.DataFrame中的列数据,但是functions包中并没有提供能处理Vectors类型数据的函数,所以很多时候需要自定义函数来处理数据。这时候就需要用到自定义函数。但对于Vectors型的数据,在自定义函数中不要把数据转换成numpy型数据。具体如下:

data=spark.createDataFrame([(Vectors.dense([1,2,3]),),
                            (Vectors.dense([3,4,8]),)],
                           ['A'])
func0=func.udf(lambda x:x.toArray().tolist()[0],FloatType())
func1=func.udf(lambda x:float(x.dot([0,1,1])),FloatType())
func2=func.udf(lambda x:x.toArray().tolist()[0],IntegerType())
func3=func.udf(lambda x:x.toArray()[0],FloatType())
data0=data.select('A',func0('A').alias('A0'))
data1=data.select('A',func1('A').alias('A1'))
data2=data.select('A',func2('A').alias('A2'))
data3=data.select('A',func3('A').alias('A3'))
data0.show()
data1.show()
data2.show()
data3.show()

运行上述代码会发现data0和data1会正确运行,data2也可以正确执行,data3会报错。提示如下错误: net.razorvine.pickle.PickleException: expected zero arguments for construction of ClassDict (for numpy.dtype)。这是因为从Pyspark V2.2以后就不能使用numpy内置的dtype数据了。
  data0、data1、data2的结果如下:
在这里插入图片描述
为了说明上述的结果,需要先对Vectors变量做一些补充说明。这里主要说明两点:

  • Vectors中每个元素的数据类型都是float型。
    在这里插入图片描述
  • Vectors变量通过toArray()方法返回的是numpy型的数据。
    在这里插入图片描述
    因为Pyspark中的DataFrame不能接受numpy型数据,所以在自定义用户函数的时候,要将数据类型转换成python中内置的Int或Float型,比如func0中的tolist()操作以及func1中的float()操作。而data2虽然没有报错但是结果却不对,目前原因还不清楚,猜测还是数据类型的问题。

猜你喜欢

转载自blog.csdn.net/yeshang_lady/article/details/127465717
今日推荐