【问题标题】:Pyspark .toPandas() results in object column where expected numeric onePyspark .toPandas() 导致对象列中预期的数字一
【发布时间】:2016-02-02 13:40:25
【问题描述】:

我从我们的数据仓库中提取数据,将其存储在 parquet 文件中,并将所有 parquet 文件加载到 spark 数据帧中。 到目前为止,一切都很好。但是,当我尝试使用 pandas.plot() 函数绘制它时,它会抛出一个“TypeError: Empty 'DataFrame': no numeric data to plot”

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

第一步:定义提取数据的 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 
"""

第 2 步:根据提取的数据创建 spark 数据框

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 个分区的 parquet 文件中

df1.coalesce(10).write.parquet("./mpr"+month+"sorted.parquet")
df = sqlContext.read.parquet('./mpr*sorted.parquet')

第 4 步:查看 spark 数据框架构(显示十进制(12,2))

df.printSchema()
root
 |-- DATE_KEY: integer (nullable = true)
 |-- AMD:   integer (nullable = true)
 |-- AMD_2: decimal(12,2) (nullable = true)
 |-- AMD_3: decimal(12,2) (nullable = true)
 |-- AMD_4: decimal(12,2) (nullable = true)
 |-- AMD_0: decimal(12,2) (nullable = true)

第 5 步:将 spark 数据帧转换为 pandas 数据帧并将所有 Null 替换为 0(使用 fillna(0))

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

第 6 步:查看相关列的 pandas 数据框信息。 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

所以我的问题是:

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

【问题讨论】:

    标签: python pandas apache-spark parquet


    【解决方案1】:

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

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

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

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

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

    然后改正

    【讨论】:

    • 被破坏的列的类型是 decimal.Decimal .. 我可以使用 pdf.applymap(lambda x: float(x) if ( isinstance(x, (Decimal))) else x) 更改它.但是我仍然不明白为什么 pandas 的 spark 数据帧会导致类 decimal.Decimal 的对象并且不能直接使用。关于如何解决这个问题的任何想法,我应该在我的提取 SQL 中进行不同的初始转换吗?因为这仍然是我修复它的时候,所以在制作我所有的提取物之前。
    • 我不太熟悉 spark 虽然它很奇怪,因为只有一列有这个问题。
    【解决方案2】:

    我遇到了同样的问题,然后我弄清楚是什么原因。

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

    在 Pandas 数据框中,没有十进制数据类型,因此所有十进制数据类型的列都转换为 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 现在将是数字。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-11
      • 1970-01-01
      • 2021-02-13
      • 2016-04-25
      • 1970-01-01
      • 2019-09-27
      • 2021-08-08
      相关资源
      最近更新 更多