2017-07-19 94 views
2

我想從熊貓轉換數據幀到spark,我使用spark_context.createDataFrame()方法來創建數據幀。我還在createDataFrame()方法中指定了架構。熊貓數據框到Spark數據框,處理NaN轉換爲實際的空?

我想知道的是如何處理特殊情況。例如,NaN在轉換爲Spark數據幀的pandas中最後爲字符串「NaN」。我正在尋找如何獲得實際的空值而不是「NaN」的方法。

+0

歡迎堆棧溢出!請通過[tour](http://stackoverflow.com/tour),[幫助中心](http://stackoverflow.com/help)和[如何提出一個好問題](http:// stackoverflow.com/help/how-to-ask)章節,瞭解本網站的工作原理,並幫助您改善當前和未來的問題,從而幫助您獲得更好的答案。 –

+0

@ help-info.de你的名字太貼切。 –

回答

4

TL; DR你現在最好的選擇是完全跳過熊貓。

問題的根源在於熊貓的表達力不如Spark SQL。 Spark提供了NULL(在SQL意義上,作爲缺失值)和NaN(數字不是數字)。

來自其他handm的熊貓沒有原生值,可以用來表示缺失值。因此,它使用了像NaN/NaTInf這樣的佔位符,它們與實際的NaNsInfs不可區分,並且轉換規則取決於列類型。唯一的例外是object列(通常是字符串),其中可以包含None值。您可以從the documentation瞭解有關處理缺失值熊貓的更多信息。

例如,當轉換爲Spark數據幀時,熊貓中的NaN最終爲字符串「NaN」。

這實際上是不正確的。取決於輸入列的類型。如果列顯示NaN這是最有可能不是一個數值,而不是一個簡單的字符串:

from pyspark.sql.functions import isnan, isnull 

pdf = pd.DataFrame({ 
    "x": [1, None], "y": [None, "foo"], 
    "z": [pd.Timestamp("20120101"), pd.Timestamp("NaT")] 
}) 
sdf = spark.createDataFrame(pdf) 

sdf.show() 
+---+----+-------------------+ 
| x| y|     z| 
+---+----+-------------------+ 
|1.0|null|2012-01-01 00:00:00| 
|NaN| foo|    null| 
+---+----+-------------------+ 
sdf.select([ 
    f(c) for c in sdf.columns for f in [isnan, isnull] 
    if (f, c) != (isnan, "z") # isnan cannot be applied to timestamp 
]).show() 
+--------+-----------+--------+-----------+-----------+ 
|isnan(x)|(x IS NULL)|isnan(y)|(y IS NULL)|(z IS NULL)| 
+--------+-----------+--------+-----------+-----------+ 
| false|  false| false|  true|  false| 
| true|  false| false|  false|  true| 
+--------+-----------+--------+-----------+-----------+ 

在實踐中,並行局部集合(包括熊貓對象)都有超越了簡單的可以忽略不計的重要性測試和玩具示例,以便您始終可以手動轉換數據(跳過可能的箭頭優化):

import numpy as np 

spark.createDataFrame([ 
    tuple(
     None if isinstance(x, (float, int)) and np.isnan(x) else x 
     for x in record.tolist()) 
    for record in pdf.to_records(index=False) 
], pdf.columns.tolist()).show() 
+----+----+-------------------+ 
| x| y|     z| 
+----+----+-------------------+ 
| 1.0|null|1325376000000000000| 
|null| foo|    null| 
+----+----+-------------------+ 

如果丟失/不是數字模糊不是問題,那麼只需像往常一樣加載數據並替換爲Spark。

from pyspark.sql.functions import col, when 

sdf.select([ 
    when(~isnan(c), col(c)).alias(c) if t in ("double", "float") else c 
    for c, t in sdf.dtypes 
]).show() 
+----+----+-------------------+ 
| x| y|     z| 
+----+----+-------------------+ 
| 1.0|null|2012-01-01 00:00:00| 
|null| foo|    null| 
+----+----+-------------------+