J'ai des journaux d'utilisateurs que j'ai extraits d'un fichier csv et convertis en un DataFrame afin de tirer parti des fonctionnalités de requête SparkSQL. Un seul utilisateur créera de nombreuses entrées par heure, et je voudrais recueillir des informations statistiques de base pour chaque utilisateur; vraiment juste le nombre d'instances utilisateur, la moyenne et l'écart-type de nombreuses colonnes. J'ai pu obtenir rapidement les informations de moyenne et de comptage en utilisant groupBy ($ "user") et l'agrégateur avec les fonctions SparkSQL pour count et avg:
val meanData = selectedData.groupBy($"user").agg(count($"logOn"),
avg($"transaction"), avg($"submit"), avg($"submitsPerHour"), avg($"replies"),
avg($"repliesPerHour"), avg($"duration"))
Cependant, je n'arrive pas à trouver une manière tout aussi élégante de calculer l'écart type. Jusqu'à présent, je ne peux le calculer qu'en mappant une chaîne, une double paire et en utilisant l'utilitaire StatCounter (). Stdev:
val stdevduration = duration.groupByKey().mapValues(value =>
org.Apache.spark.util.StatCounter(value).stdev)
Cela retourne un RDD cependant, et je voudrais essayer de tout garder dans un DataFrame pour que d'autres requêtes soient possibles sur les données retournées.
Spark 1.6 +
Vous pouvez utiliser stddev_pop
pour calculer l'écart type de la population et stddev
/stddev_samp
pour calculer l'écart type de l'échantillon sans biais:
import org.Apache.spark.sql.functions.{stddev_samp, stddev_pop}
selectedData.groupBy($"user").agg(stdev_pop($"duration"))
Spark 1.5 et inférieur ( La réponse originale):
Pas si joli et biaisé (identique à la valeur renvoyée par describe
) mais en utilisant la formule:
vous pouvez faire quelque chose comme ça:
import org.Apache.spark.sql.functions.sqrt
selectedData
.groupBy($"user")
.agg((sqrt(
avg($"duration" * $"duration") -
avg($"duration") * avg($"duration")
)).alias("duration_sd"))
Vous pouvez bien sûr créer une fonction pour réduire l'encombrement:
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"))
Il est également possible d'utiliser Hive UDF:
df.registerTempTable("df")
sqlContext.sql("""SELECT user, stddev(duration)
FROM df
GROUP BY user""")
Source de l'image: https://en.wikipedia.org/wiki/Standard_deviation