我有来自csv的用户日志并转换为DataFrame以利用SparkSQL查询功能。单个用户每小时会创建大量条目,我想为每个用户收集一些基本的统计信息;实际上只是用户实例的数量,平均值以及众多列的标准偏差。我能够通过使用groupBy($“user”)以及具有计数和平均值的SparkSQL函数的聚合器来快速获取均值和计数信息:
val meanData = selectedData.groupBy($"user").agg(count($"logOn"),
avg($"transaction"), avg($"submit"), avg($"submitsPerHour"), avg($"replies"),
avg($"repliesPerHour"), avg($"duration"))
然而,我似乎无法找到同样优雅的方法来计算标准偏差。到目前为止,我只能通过映射字符串,双对并使用StatCounter()来计算它.stdev实用程序:
val stdevduration = duration.groupByKey().mapValues(value =>
org.apache.spark.util.StatCounter(value).stdev)
但是这会返回一个RDD,我想尝试将其全部保存在DataFrame中,以便对返回的数据进行进一步的查询。
答案 0 :(得分:33)
Spark 1.6 +
您可以使用stddev_pop
计算人口标准差,并使用stddev
/ stddev_samp
计算无偏样本标准差:
import org.apache.spark.sql.functions.{stddev_samp, stddev_pop}
selectedData.groupBy($"user").agg(stdev_pop($"duration"))
Spark 1.5及以下(原始答案):
不那么漂亮且有偏见(与从describe
返回的值相同)但使用公式:
你可以这样做:
import org.apache.spark.sql.functions.sqrt
selectedData
.groupBy($"user")
.agg((sqrt(
avg($"duration" * $"duration") -
avg($"duration") * avg($"duration")
)).alias("duration_sd"))
您当然可以创建一个减少混乱的功能:
import org.apache.spark.sql.Column
def mySd(col: Column): Column = {
sqrt(avg(col * col) - avg(col) * avg(col))
}
df.groupBy($"user").agg(mySd($"duration").alias("duration_sd"))
也可以使用Hive UDF:
df.registerTempTable("df")
sqlContext.sql("""SELECT user, stddev(duration)
FROM df
GROUP BY user""")
答案 1 :(得分:1)
接受的代码有错别字(如MRez指出的),因此无法编译。以下代码段可以正常工作并经过测试。
对于Spark 2.0 + :
import org.apache.spark.sql.functions._
val _avg_std = df.groupBy("user").agg(
avg(col("duration").alias("avg")),
stddev(col("duration").alias("stdev")),
stddev_pop(col("duration").alias("stdev_pop")),
stddev_samp(col("duration").alias("stdev_samp"))
)