web-dev-qa-db-ja.com

sparkデータフレーム内の複数の行を1つの行にマージする

2つの列を持つデータフレームがあります。タイムスタンプ、値のタイムスタンプはエポックからの時間であり、値は浮動小数点値です。行を最小単位の平均値にマージしたい。つまり、タイムスタンプが同じラウンド分(エポックから60秒間隔)からのものであるすべての行を取得し、それらを1つの行にマージします。ここで、値の列はすべての値の平均になります。

例を挙げると、私のデータフレームは次のようになっていると仮定します。

timestamp      value
---------      -----
1441637160      10.0
1441637170      20.0
1441637180      30.0
1441637210      40.0
1441637220      10.0
1441637230      0.0

最初の4行は同じ分の一部です(1441637160%60 == 0、1441637160 + 60 == 1441637220)最後の2行は別の分の一部です。同じ分のすべての行をマージしたいと思います。次のような結果を得るには:

timestamp      value
---------      -----
1441637160      25.0  (since (10+20+30+40)/4 = 25)
1441637220      5.0   (since (10+0)/2 = 5)

それを行うための最良の方法は何ですか?

10
polo

単純にグループ化して集約できます。次のようなデータを使用:

val df = sc.parallelize(Seq(
  (1441637160, 10.0),
  (1441637170, 20.0),
  (1441637180, 30.0),
  (1441637210, 40.0),
  (1441637220, 10.0),
  (1441637230, 0.0))).toDF("timestamp", "value")

必要な関数とクラスをインポートします。

import org.Apache.spark.sql.functions.{lit, floor}
import org.Apache.spark.sql.types.IntegerType

間隔列を作成します。

val tsGroup = (floor($"timestamp" / lit(60)) * lit(60))
  .cast(IntegerType)
  .alias("timestamp")

集計を実行するためにそれを使用します。

df.groupBy(tsGroup).agg(mean($"value").alias("value")).show

// +----------+-----+
// | timestamp|value|
// +----------+-----+
// |1441637160| 25.0|
// |1441637220|  5.0|
// +----------+-----+
6
zero323

最初にタイムスタンプを分バケットにマップし、次にgroupByKeyを使用して平均を計算します。例えば:

rdd.map(x=>{val round = x._1%60; (x._1-round, x._2);})
.groupByKey
.map(x=>(x._1, (x._2.sum.toDouble/x._2.size)))
.collect()
1
Patrick McGloin