J'ai PySpark DataFrame (pas des pandas) appelé df
qui est assez grand pour utiliser collect()
. Par conséquent, le code ci-dessous n'est pas efficace. Il fonctionnait avec une plus petite quantité de données, mais maintenant il échoue.
import numpy as np
myList = df.collect()
total = []
for product,nb in myList:
for p2,score in nb:
total.append(score)
mean = np.mean(total)
std = np.std(total)
Existe-t-il un moyen d'obtenir mean
et std
comme deux variables en utilisant pyspark.sql.functions
ou similaire?
from pyspark.sql.functions import mean as mean_, std as std_
Je pourrais utiliser withColumn
, cependant, cette approche applique les calculs ligne par ligne et ne renvoie pas une seule variable.
MISE À JOUR:
Exemple de contenu de df
:
+----------+------------------+
|product_PK| products|
+----------+------------------+
| 680|[[691,1], [692,5]]|
| 685|[[691,2], [692,2]]|
| 684|[[691,1], [692,3]]|
Je devrais calculer la moyenne et l'écart type des valeurs de score
, par exemple la valeur 1
dans [691,1]
est l'un des scores.
Vous pouvez utiliser les fonctions intégrées pour obtenir des statistiques agrégées. Voici comment obtenir la moyenne et l'écart type.
from pyspark.sql.functions import mean as _mean, stddev as _stddev, col
df_stats = df.select(
_mean(col('columnName')).alias('mean'),
_stddev(col('columnName')).alias('std')
).collect()
mean = df_stats[0]['mean']
std = df_stats[0]['std']
Notez qu'il existe trois fonctions d'écart type différentes. À partir des documents, celui que j'ai utilisé (stddev
) renvoie ce qui suit:
Fonction d'agrégation: renvoie l'écart type d'échantillon sans biais de l'expression dans un groupe
Vous pouvez également utiliser la méthode describe()
:
df.describe().show()
Reportez-vous à ce lien pour plus d'informations: pyspark.sql.functions
[~ # ~] mise à jour [~ # ~] : voici comment vous pouvez travailler sur les données imbriquées.
Utilisez explode
pour extraire les valeurs dans des lignes distinctes, puis appelez mean
et stddev
comme indiqué ci-dessus.
Voici un MWE:
from pyspark.sql.types import IntegerType
from pyspark.sql.functions import explode, col, udf, mean as _mean, stddev as _stddev
# mock up sample dataframe
df = sqlCtx.createDataFrame(
[(680, [[691,1], [692,5]]), (685, [[691,2], [692,2]]), (684, [[691,1], [692,3]])],
["product_PK", "products"]
)
# udf to get the "score" value - returns the item at index 1
get_score = udf(lambda x: x[1], IntegerType())
# explode column and get stats
df_stats = df.withColumn('exploded', explode(col('products')))\
.withColumn('score', get_score(col('exploded')))\
.select(
_mean(col('score')).alias('mean'),
_stddev(col('score')).alias('std')
)\
.collect()
mean = df_stats[0]['mean']
std = df_stats[0]['std']
print([mean, std])
Quelles sorties:
[2.3333333333333335, 1.505545305418162]
Vous pouvez vérifier que ces valeurs sont correctes en utilisant numpy
:
vals = [1,5,2,2,1,3]
print([np.mean(vals), np.std(vals, ddof=1)])
Explication: votre colonne "products"
Est un list
de list
s. L'appel de explode
créera une nouvelle ligne pour chaque élément du list
externe. Saisissez ensuite la valeur "score"
De chacune des lignes éclatées, que vous avez définies comme deuxième élément d'un list
à 2 éléments. Enfin, appelez les fonctions d'agrégation sur cette nouvelle colonne.
Vous pouvez utiliser mean
et stddev
à partir de pyspark.sql.functions
:
import pyspark.sql.functions as F
df = spark.createDataFrame(
[(680, [[691,1], [692,5]]), (685, [[691,2], [692,2]]), (684, [[691,1], [692,3]])],
["product_PK", "products"]
)
result_df = (
df
.withColumn(
'val_list',
F.array(df.products.getItem(0).getItem(1),df.products.getItem(1).getItem(1))
)
.select(F.explode('val_list').alias('val'))
.select(F.mean('val').alias('mean'), F.stddev('val').alias('stddev'))
)
print(result_df.collect())
qui génère:
[Row(mean=2.3333333333333335, stddev=1.505545305418162)]
Vous pouvez en savoir plus sur pyspark.sql.functions
ici.
Pour l'écart-type, une meilleure façon d'écrire est la suivante. Nous pouvons utiliser la mise en forme (à 2 décimales) et en utilisant le nom de la colonne Alias
data_agg=SparkSession.builder.appName('Sales_fun').getOrCreate()
data=data_agg.read.csv('sales_info.csv',inferSchema=True, header=True)
from pyspark.sql.functions import *
*data.select((format_number(stddev('Sales'),2)).alias('Sales_Stdev')).show()*