フィーチャ内の文字列の列にインデックスを付けるときに、PySparkに奇妙な問題があります。これが私のtmp.csvファイルです:
x0,x1,x2,x3
asd2s,1e1e,1.1,0
asd2s,1e1e,0.1,0
,1e3e,1.2,0
bd34t,1e1e,5.1,1
asd2s,1e3e,0.2,0
bd34t,1e2e,4.3,1
ここで、「x0」の値が1つ欠落しています。最初は、pyspark_csvを使用してcsvファイルからDataFrameに機能を読み込んでいます: https://github.com/seahboonsiew/pyspark-csv 次に、StringIndexerでx0のインデックスを作成します。
import pyspark_csv as pycsv
from pyspark.ml.feature import StringIndexer
sc.addPyFile('pyspark_csv.py')
features = pycsv.csvToDataFrame(sqlCtx, sc.textFile('tmp.csv'))
indexer = StringIndexer(inputCol='x0', outputCol='x0_idx' )
ind = indexer.fit(features).transform(features)
print ind.collect()
'' ind.collect() ''を呼び出すとSparkはJava.lang.NullPointerExceptionをスローします。ただし、「x1」などの完全なデータセットではすべて正常に機能します。
誰かがこれを引き起こしているものとそれを修正する方法の手がかりを持っていますか?
前もって感謝します!
セルゲイ
更新:
私はSpark 1.5.1を使用します。正確なエラー:
File "/spark/spark-1.4.1-bin-hadoop2.6/python/pyspark/sql/dataframe.py", line 258, in show
print(self._jdf.showString(n))
File "/spark/spark-1.4.1-bin-hadoop2.6/python/lib/py4j-0.8.2.1-src.Zip/py4j/Java_gateway.py", line 538, in __call__
File "/spark/spark-1.4.1-bin-hadoop2.6/python/lib/py4j-0.8.2.1-src.Zip/py4j/protocol.py", line 300, in get_return_value
py4j.protocol.Py4JJavaError: An error occurred while calling o444.showString.
: Java.lang.NullPointerException
at org.Apache.spark.sql.types.Metadata$.org$Apache$spark$sql$types$Metadata$$hash(Metadata.scala:208)
at org.Apache.spark.sql.types.Metadata$$anonfun$org$Apache$spark$sql$types$Metadata$$hash$2.apply(Metadata.scala:196)
at org.Apache.spark.sql.types.Metadata$$anonfun$org$Apache$spark$sql$types$Metadata$$hash$2.apply(Metadata.scala:196)
... etc
Csvファイルを読み取らずに同じDataFrameを作成しようとしましたが、
df = sqlContext.createDataFrame(
[('asd2s','1e1e',1.1,0), ('asd2s','1e1e',0.1,0),
(None,'1e3e',1.2,0), ('bd34t','1e1e',5.1,1),
('asd2s','1e3e',0.2,0), ('bd34t','1e2e',4.3,1)],
['x0','x1','x2','x3'])
そしてそれは同じエラーを出します。少し異なる例で問題なく動作しますが、
df = sqlContext.createDataFrame(
[(0, None, 1.2), (1, '06330986ed', 2.3),
(2, 'b7584c2d52', 2.5), (3, None, .8),
(4, 'bd17e19b3a', None), (5, '51b5c0f2af', 0.1)],
['id', 'x0', 'num'])
// after indexing x0
+---+----------+----+------+
| id| x0| num|x0_idx|
+---+----------+----+------+
| 0| null| 1.2| 0.0|
| 1|06330986ed| 2.3| 2.0|
| 2|b7584c2d52| 2.5| 4.0|
| 3| null| 0.8| 0.0|
| 4|bd17e19b3a|null| 1.0|
| 5|51b5c0f2af| 0.1| 3.0|
+---+----------+----+------+
更新2:
Scalaで同じ問題を発見したばかりなので、Sparkバグであり、PySparkだけではありません。特にデータフレームです。
val df = sqlContext.createDataFrame(
Seq(("asd2s","1e1e",1.1,0), ("asd2s","1e1e",0.1,0),
(null,"1e3e",1.2,0), ("bd34t","1e1e",5.1,1),
("asd2s","1e3e",0.2,0), ("bd34t","1e2e",4.3,1))
).toDF("x0","x1","x2","x3")
'x0'機能のインデックスを作成すると、Java.lang.NullPointerExceptionがスローされます。さらに、次のデータフレームで「x0」にインデックスを付ける場合
val df = sqlContext.createDataFrame(
Seq((0, null, 1.2), (1, "b", 2.3),
(2, "c", 2.5), (3, "a", 0.8),
(4, "a", null), (5, "c", 0.1))
).toDF("id", "x0", "num")
'Java.lang.UnsupportedOperationException:タイプAnyのスキーマはサポートされていません'があります。これは、5番目のベクトルに 'num'値がないことが原因です。それを数値に置き換えると、最初のベクトルに値が欠落していても、すべてがうまく機能します。
古いバージョンのSpark(1.4.1)も試しましたが、結果は同じです。
使用しているモジュールが空の文字列をnullに変換しているように見え、ある時点でダウンストリーム処理を台無しにしています。一見 PySparkのバグのように見えます 。
それを修正する方法は?簡単な回避策は、インデックスを作成する前にnullを削除することです。
features.na.drop()
または、nullをプレースホルダーに置き換えます。
from pyspark.sql.functions import col, when
features.withColumn(
"x0", when(col("x0").isNull(), "__SOME_PLACEHOLDER__").otherwise(col("x0")))
また、 spark-csv
。これは効率的でテスト済みであり、ボーナスとして空の文字列をnulls
に変換しません。
features = (sqlContext.read
.format('com.databricks.spark.csv')
.option("inferSchema", "true")
.option("header", "true")
.load("tmp.csv"))
さて、現在、唯一の解決策は、提案された@ zero323のようなNAを取り除くか、toPandas()メソッドを使用してSpark DataFrameをPandas DataFrameに変換して代入することですsklearn Imputerまたは任意のカスタムインピュターを使用したデータ。例: scikit-learnでカテゴリの欠落値を代入 次に、PandasデータフレームをSpark DataFrameを使用して作業します。それでも問題は解決しないので、バグレポートを送信してみます。Sparkは比較的新しいので、何かが足りない可能性があります。