6

複数の double データ型列の中央値を見つける必要があります。正しいアプローチを見つけるための提案をリクエストしてください。

以下は、1 列のサンプル データセットです。サンプルの中央値が 1 として返されることを期待しています。

  scala> sqlContext.sql("select num from test").show();
+---+
|num|
+---+
|0.0|
|0.0|
|1.0|
|1.0|
|1.0|
|1.0|
+---+

次のオプションを試しました

1) Hive UDAF パーセンタイル。BigInt でのみ機能しました。

2) Hive UDAT percentile_approx ですが、期待どおりに動作しません (0.25 対 1 を返します)。

sqlContext.sql("select percentile_approx(num,0.5) from test").show();

+----+
| _c0|
+----+
|0.25|
+----+

3) Spark ウィンドウ関数 percent_rank - 中央値を見つける方法は、0.5 を超えるすべての percent_rank を探し、最大 percent_rank の対応する num 値を選択することです。しかし、特にレコード数が偶数の場合、すべての場合に機能するとは限りません。そのような場合、中央値はソートされた分布の中央値の平均です。

また、percent_rank では、複数の列の中央値を見つける必要があるため、異なるデータフレームで計算する必要がありますが、これは私にとっては少し複雑な方法です。私の理解が正しくない場合は、修正してください。

+---+-------------+
|num|percent_rank |
+---+-------------+
|0.0|0.0|
|0.0|0.0|
|1.0|0.4|
|1.0|0.4|
|1.0|0.4|
|1.0|0.4|
+---+---+
4

1 に答える 1

9

好奇心から、Apache Spark のどのバージョンを使用していますか? への変更を含む Apache Spark 2.0+ 内にいくつかの修正がありましたapproxQuantile

以下の pySpark コード スニペットを実行するとします。

rdd = sc.parallelize([[1, 0.0], [1, 0.0], [1, 1.0], [1, 1.0], [1, 1.0], [1, 1.0]])
df = rdd.toDF(['id', 'num'])
df.createOrReplaceTempView("df")

次のようにmedian計算するapproxQuantileと:

df.approxQuantile("num", [0.5], 0.25)

また

spark.sql("select percentile_approx(num, 0.5) from df").show()

結果は次のとおりです。

  • スパーク 2.0.0 : 0.25
  • スパーク 2.0.1 : 1.0
  • スパーク 2.1.0 : 1.0

これらはおおよその数値であるため( 経由approxQuantile)、一般的にはこれでうまくいくはずです。正確な中央値が必要な場合、1 つの方法は を使用することnumpy.medianです。以下のコード スニペットは、 How to find the median in Apache Spark with Python Dataframe API?dfに対する gench の SO 応答に基づいて、この例用に更新されています。:

from pyspark.sql.types import *
import pyspark.sql.functions as F
import numpy as np

def find_median(values):
    try:
        median = np.median(values) #get the median of values in a list in each row
        return round(float(median),2)
    except Exception:
        return None #if there is anything wrong with the given values

median_finder = F.udf(find_median,FloatType())

df2 = df.groupBy("id").agg(F.collect_list("num").alias("nums"))
df2 = df2.withColumn("median", median_finder("nums"))

# print out
df2.show()

次の出力で:

+---+--------------------+------+
| id|                nums|median|
+---+--------------------+------+
|  1|[0.0, 0.0, 1.0, 1...|   1.0|
+---+--------------------+------+

更新: RDD を使用した Spark 1.6 Scala バージョン

Spark 1.6 を使用している場合は、medianEugene Zhulenev の応答How can I calculate the exact median with Apache Spark を介して Scala コードを使用して計算できます。以下は、この例で動作する変更されたコードです。

import org.apache.spark.SparkContext._

  val rdd: RDD[Double] = sc.parallelize(Seq((0.0), (0.0), (1.0), (1.0), (1.0), (1.0)))

  val sorted = rdd.sortBy(identity).zipWithIndex().map {
    case (v, idx) => (idx, v)
  }

  val count = sorted.count()

  val median: Double = if (count % 2 == 0) {
    val l = count / 2 - 1
    val r = l + 1
    (sorted.lookup(l).head + sorted.lookup(r).head).toDouble / 2
  } else sorted.lookup(count / 2).head.toDouble

次の出力で:

// output
import org.apache.spark.SparkContext._
rdd: org.apache.spark.rdd.RDD[Double] = ParallelCollectionRDD[227] at parallelize at <console>:34
sorted: org.apache.spark.rdd.RDD[(Long, Double)] = MapPartitionsRDD[234] at map at <console>:36
count: Long = 6
median: Double = 1.0

これは を使用して正確な中央値を計算していることに注意してください。RDDsつまり、この計算を実行するには、DataFrame 列を RDD に変換する必要があります。

于 2016-12-31T05:30:51.350 に答える