如何计算PySpark DataFrame的平均值和标准差?

时间:2017-12-27 16:05:04

标签: python apache-spark pyspark apache-spark-sql

我的PySpark DataFrame( not pandas )名为df,使用collect()非常大。因此,下面给出的代码效率不高。它使用的是少量数据,但现在却失败了。

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)

有没有办法通过mean或类似方式将stdpyspark.sql.functions作为两个变量?

from pyspark.sql.functions import mean as mean_, std as std_

我可以使用withColumn,但是,这种方法逐行应用计算,并且它不会返回单个变量。

更新

df的示例内容:

+----------+------------------+
|product_PK|          products|
+----------+------------------+
|       680|[[691,1], [692,5]]|
|       685|[[691,2], [692,2]]|
|       684|[[691,1], [692,3]]|

我应该计算score值的平均值和标准偏差,例如1中的值[691,1]是得分之一。

4 个答案:

答案 0 :(得分:13)

您可以使用内置函数来获取聚合统计信息。以下是如何获得均值和标准偏差。

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']

请注意,有三种不同的标准偏差功能。从文档中我使用的文档(stddev)返回以下内容:

  

聚合函数:返回无偏样本标准差   组中的表达

您也可以使用describe()方法:

df.describe().show()

有关详细信息,请参阅此链接:pyspark.sql.functions

更新:这是您处理嵌套数据的方法。

使用explode将值提取到单独的行中,然后调用meanstddev,如上所示。

这是一个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])

哪个输出:

[2.3333333333333335, 1.505545305418162]

您可以使用numpy验证这些值是否正确:

vals = [1,5,2,2,1,3]
print([np.mean(vals), np.std(vals, ddof=1)])

说明:您的"products"列是list的{​​{1}}。调用list将为外部explode的每个元素创建一个新行。然后从每个展开的行中获取list值,这些行已定义为2元素"score"中的第二个元素。最后,在这个新列上调用聚合函数。

答案 1 :(得分:1)

您可以使用mean中的stddevpyspark.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())

输出:

[Row(mean=2.3333333333333335, stddev=1.505545305418162)]

您可以在此处详细了解pyspark.sql.functions

答案 2 :(得分:0)

对于标准偏差,更好的编写方法如下。我们可以使用格式(小数点后两位)和“别名”列

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()*

答案 3 :(得分:0)

如果您只想要任何列的 MeanStd. dev,那么
我能想到的最简单的方法是使用 agg 函数

获取列的平均值

df.agg({'produ': 'mean'}).show()

# or you can also use 
data.agg({'balance': 'avg'}).show()

获取列的标准差

data.agg({'balance': 'stddev'}).show()

# and for variance you can use
data.agg({'balance': 'variance'}).show()