我正在尝试计算数据框中每列的平均值,并从列中的每个元素中减去。我创建了一个尝试这样做的函数,但是当我尝试使用UDF实现它时,我得到一个错误:'float'对象没有属性'map'。关于如何创建这样一个函数的任何想法?谢谢!
def normalize(data):
average=data.map(lambda x: x[0]).sum()/data.count()
out=data.map(lambda x: (x-average))
return out
mapSTD=udf(normalize,IntegerType())
dats = data.withColumn('Normalized', mapSTD('Fare'))
答案 0 :(得分:3)
在您的示例中,UDF函数存在问题,无法应用于行和整个DataFrame。 UDF只能应用于单行,但Spark也可以实现在整个DataFrame上工作的UDAF(用户自定义聚合函数)。
要解决您的问题,您可以使用以下功能:
from pyspark.sql.functions import mean
def normalize(df, column):
average = df.agg(mean(df[column]).alias("mean")).collect()[0]["mean"]
return df.select(df[column] - average)
像这样使用:
normalize(df, "Fare")
请注意,上面仅适用于单列,但可以实现更通用的内容:
def normalize(df, columns):
selectExpr = []
for column in columns:
average = df.agg(mean(df[column]).alias("mean")).collect()[0]["mean"]
selectExpr.append(df[column] - average)
return df.select(selectExpr)
使用它像:
normalize(df, ["col1", "col2"])
这样可行,但是您需要为每个列运行聚合,因此对于许多列,可能会出现性能问题,但是只能生成一个聚合表达式:
def normalize(df, columns):
aggExpr = []
for column in columns:
aggExpr.append(mean(df[column]).alias(column))
averages = df.agg(*aggExpr).collect()[0]
selectExpr = []
for column in columns:
selectExpr.append(df[column] - averages[column])
return df.select(selectExpr)
答案 1 :(得分:2)
添加到Piotr的答案。如果您需要保留现有数据框并添加带有别名的规范化列,则可以将该函数修改为:
def normalize(df, columns):
aggExpr = []
for column in columns:
aggExpr.append(mean(df[column]).alias(column))
averages = df.agg(*aggExpr).collect()[0]
selectExpr = ['*']
for column in columns:
selectExpr.append((df[column] - averages[column]).alias('normalized_'+column))
return df.select(selectExpr)