Python Pyspark.toPandas()将在对象列中生成所需的数字列

Python Pyspark.toPandas()将在对象列中生成所需的数字列,python,pandas,apache-spark,parquet,Python,Pandas,Apache Spark,Parquet,我从数据仓库中提取数据,将其存储在拼花文件中,并将所有拼花文件加载到spark数据框中。 到现在为止,一直都还不错。但是,当我尝试使用pandas.plot()函数打印时,它会抛出一个“TypeError:Empty'DataFrame”:没有要打印的数字数据” 所以我开始追溯到我的源代码,我认为从我的初始sql语句转换为十进制是问题之一。但我不知道如何解决这个问题。我原以为一个fillna(0)就可以了,但事实并非如此 步骤1:定义SQL语句以提取数据 mpr_sql = """ select

我从数据仓库中提取数据,将其存储在拼花文件中,并将所有拼花文件加载到spark数据框中。 到现在为止,一直都还不错。但是,当我尝试使用pandas.plot()函数打印时,它会抛出一个“TypeError:Empty'DataFrame”:没有要打印的数字数据”

所以我开始追溯到我的源代码,我认为从我的初始sql语句转换为十进制是问题之一。但我不知道如何解决这个问题。我原以为一个fillna(0)就可以了,但事实并非如此

步骤1:定义SQL语句以提取数据

mpr_sql = """
select 
CAST(DATE_KEY  AS INTEGER) AS DATE_KEY ,
CAST(AMD  AS INTEGER) AS AMD ,
CAST(AMD_2  AS DECIMAL(12,2)) AS AMD_2 ,
CAST(AMD_3  AS DECIMAL(12,2)) AS AMD_3 ,
CAST(AMD_4  AS DECIMAL(12,2)) AS AMD_4 ,
CAST(AMD_0  AS DECIMAL(12,2)) AS AMD_0 
"""
df1 = sqlContext.load(source="jdbc", 
                         driver="com.teradata.jdbc.TeraDriver", 
                         url=db_url,
                         user=db_user
                         TMODE="TERA",
                         password=db_pwd,
                         dbtable="( "+sql+") a")
步骤2:从提取的数据创建spark数据帧

mpr_sql = """
select 
CAST(DATE_KEY  AS INTEGER) AS DATE_KEY ,
CAST(AMD  AS INTEGER) AS AMD ,
CAST(AMD_2  AS DECIMAL(12,2)) AS AMD_2 ,
CAST(AMD_3  AS DECIMAL(12,2)) AS AMD_3 ,
CAST(AMD_4  AS DECIMAL(12,2)) AS AMD_4 ,
CAST(AMD_0  AS DECIMAL(12,2)) AS AMD_0 
"""
df1 = sqlContext.load(source="jdbc", 
                         driver="com.teradata.jdbc.TeraDriver", 
                         url=db_url,
                         user=db_user
                         TMODE="TERA",
                         password=db_pwd,
                         dbtable="( "+sql+") a")
步骤3:将spark数据框存储在一个有10个分区的拼花地板文件中

df1.coalesce(10).write.parquet("./mpr"+month+"sorted.parquet")
df = sqlContext.read.parquet('./mpr*sorted.parquet')
步骤4:查看spark数据帧模式(它显示十进制(12,2))

步骤5:将spark数据帧转换为pandas数据帧,并将任何空值替换为0(使用fillna(0))

步骤6:查看相关列的数据帧信息。AMD是正确的(整数),但AMD_4是object类型,我希望它是double或float之类的(抱歉,总是忘记正确的类型)。由于AMD_4是一种非数字类型,我不能用它来打印。

pdf[['AMD','AMD4']].info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 20 entries, 20140101 to 20150801
Data columns (total 2 columns):
AMD         20 non-null int64
AMD_4       20 non-null object
dtypes: int64(1), object(1)
memory usage: 480.0+ bytes
pdf['AMD','AMD4']].info()
INT64索引:20个条目,20140101至20150801
数据列(共2列):
AMD 20非空int64
AMD_4 20非空对象
数据类型:int64(1),对象(1)
内存使用:480.0+字节
所以我的问题是:

  • 为什么AMD_4(以及此处未显示的其他AMD_x列)是object类型,而AMD是int64类型
  • 或者换句话说,我怎样才能使AMD_x列成为浮点/双精度/十进制类型

  • 首先检查pdf.isnull().sum():
    1.应该都是零。出于某种原因,如果某个列计数返回na或nan,则始终可以使用pandas
    fillna()

    pdf = df.fillna(0).toPandas()
    pdf = pdf.fillna(0)
    

    2.如果全部为零,则检查类型不匹配的位置

    pdf.applymap(lambda x: isinstance(x, (int, float)))  
    

    纠正它

    我也有同样的问题,然后我找出了原因

    在转换过程中,会合并数据类型,例如int/long->int64、double->float64、string->obj。对于所有未知数据类型,它将转换为obj类型

    在熊猫数据帧中,没有十进制数据类型,因此十进制数据类型的所有列都转换为obj类型

    如果在应用toPandas()之前可以将所有十进制数据类型转换为双精度类型,则所有数字数据都可以使用

    from pyspark.sql.functions import *
    from pyspark.sql.types import *
    df = df.withColumn('AMD_4', col('AMD_4').cast(DoubleType())).withColumn('AMD_2', col('AMD_2').cast(DoubleType()))
    pdf = df.toPandas()
    

    在pdf中,AMD_4和AMD_2现在将是数字的

    损坏的列的类型为decimal.decimal。。我可以使用pdf.applymap(lambda x:float(x)if(isinstance(x,(Decimal)))else x)来更改它。然而,我仍然不明白为什么spark dataframe会导致decimal.decimal类的对象,并且不能直接使用。关于如何解决这个问题,我应该在提取SQL中进行不同的初始转换吗?因为这仍然是我在做所有摘录之前修复它的时间。我对spark不太熟悉,尽管它很奇怪,因为只有一个专栏有这个问题。
    from pyspark.sql.functions import *
    from pyspark.sql.types import *
    df = df.withColumn('AMD_4', col('AMD_4').cast(DoubleType())).withColumn('AMD_2', col('AMD_2').cast(DoubleType()))
    pdf = df.toPandas()