web-dev-qa-db-ja.com

欠落している値を平均に置き換えます-Spark Dataframe

Spark欠損値のあるデータフレームがあります。欠損値をその列の平均値に置き換えることで簡単な代入を実行したいと思います。私はSparkに非常に慣れていないので、このロジックを実装するのに苦労しています。

a)これを単一の列(列Aとしましょう)で実行するには、次のコード行が機能するようです。

df.withColumn("new_Col", when($"ColA".isNull, df.select(mean("ColA"))
  .first()(0).asInstanceOf[Double])
  .otherwise($"ColA"))

b)しかし、データフレームのすべての列に対してこれを行う方法を理解することができませんでした。 Map関数を試してみましたが、データフレームの各行をループしていると思います

c)SO- here 。)にも同様の質問があります。また、(集計テーブルと合体を使用した)ソリューションは気に入っていましたが、これは、各列をループすることによってこれを行う方法です(私はRから来ているので、lapplyのような高次関数を使用して各列をループするのが私には自然に思えます)。

ありがとう!

12
Dataminer

スパーク> = 2.2

org.Apache.spark.ml.feature.Imputerを使用できます(平均と中央値の両方の戦略をサポートしています)。

スカラ

import org.Apache.spark.ml.feature.Imputer

val imputer = new Imputer()
  .setInputCols(df.columns)
  .setOutputCols(df.columns.map(c => s"${c}_imputed"))
  .setStrategy("mean")

imputer.fit(df).transform(df)

Python

from pyspark.ml.feature import Imputer

imputer = Imputer(
    inputCols=df.columns, 
    outputCols=["{}_imputed".format(c) for c in df.columns]
)
imputer.fit(df).transform(df)

スパーク<2.2

はい、どうぞ:

import org.Apache.spark.sql.functions.mean

df.na.fill(df.columns.Zip(
  df.select(df.columns.map(mean(_)): _*).first.toSeq
).toMap)

どこ

df.columns.map(mean(_)): Array[Column] 

各列の平均を計算し、

df.select(_: *).first.toSeq: Seq[Any]

集計された値を収集し、行をSeq[Any]に変換します(これは最適ではないことはわかっていますが、これは私たちが操作する必要があるAPIです)。

df.columns.Zip(_).toMap: Map[String,Any] 

列名からその平均にマップするaMap: Map[String, Any]を作成し、最後に:

df.na.fill(_): DataFrame

次を使用して欠損値を埋めます:

fill: Map[String, Any] => DataFrame 

DataFrameNaFunctionsから。

NaNエントリを単一化するには、次のように置き換えます。

df.select(df.columns.map(mean(_)): _*).first.toSeq

と:

import org.Apache.spark.sql.functions.{col, isnan, when}


df.select(df.columns.map(
  c => mean(when(!isnan(col(c)), col(c)))
): _*).first.toSeq
16
user6910411

PySpark <2.2の(平均ではなく)中央値を代入するため

## filter numeric cols
num_cols = [col_type[0] for col_type in filter(lambda dtype: dtype[1] in {"bigint", "double", "int"}, df.dtypes)]
### Compute a dict with <col_name, median_value>
median_dict = dict()
for c in num_cols:
   median_dict[c] = df.stat.approxQuantile(c, [0.5], 0.001)[0]

次に、na.fill

df_imputed = df.na.fill(median_dict)
3
noleto

PySparkの場合、これは私が使用したコードです。

_mean_dict = { col: 'mean' for col in df.columns }
col_avgs = df.agg( mean_dict ).collect()[0].asDict()
col_avgs = { k[4:-1]: v for k,v in col_avgs.iteritems() }
df.fillna( col_avgs ).show()
_

4つのステップは次のとおりです。

  1. 辞書_mean_dict_を作成し、列名を集計演算にマッピングします(平均)
  2. 各列の平均を計算し、辞書として保存します_col_avgs_
  3. _col_avgs_の列名は_avg(_で始まり、_)_で終わります。 avg(col1)。括弧を取り除きます。
  4. _col_avgs_を使用して、データフレームの列に平均を入力します
2
Michael P