在循环中过滤和重新分配pyspark数据帧

时间:2017-11-16 21:33:55

标签: loops apache-spark dataframe filter pyspark

我试图遍历Pyspark数据框的所有列,计算IQR以过滤上部异常值,并重新分配相同的数据帧。有200多列。这是有效的,但随着它在循环中前进,它会越来越慢。我怀疑问题可能在于重新分配数据帧(dfBufferOutlier = dfBufferOutlier.filter(col(i)

nameList=dfBuffer.schema.names[1:]    
dfBufferOutlier=dfBuffer
for i in nameList:
    cuenta=dfBufferOutlier.filter(col(i)>0).count()
    if cuenta>0:
        Q1, Q2, Q3 = dfBufferOutlier.filter(col(i)>0).approxQuantile(col=i,probabilities=[0.25,0.5,0.75],relativeError=0.005)
        IQR=(Q3-Q1)
        top_limit=Q3+1.5*IQR
        dfBufferOutlier=dfBufferOutlier.filter(col(i)<top_limit)

肯定有另一种方法可以让它变得更好,但无法弄清楚......有什么帮助吗?

1 个答案:

答案 0 :(得分:1)

如果你愿意修改程序(可以说你应该修改它),你可以在一次通过中完成所有工作:

from pyspark.sql.functions import col, count, when
from functools import reduce
from operator import and_

def iqr_filter(df, cols, relativeError=0.005):
    # Find quantiles
    quantiles = (df
        # Convert values <= 0 to NULL
        .select([when(col(c) > 0, col(c)).alias(c) for c in cols])
        .approxQuantile(cols, [0.25, 0.5, 0.75], relativeError))

    # Compute thresholds
    thresholds = [
        q3 + 1.5 * (q3 - q1) for q1, _, q3 in quantiles
    ]
    # Create SQL expression of form c1 < t1 AND c2 < t2 AND ... AND cn < tn
    expr  = reduce(and_, [col(c) < t for c, t in zip(cols, thresholds)])
    # Filter
    return df.where(expr)

用法:

iqr_filter(dfBuffer, dfBuffer.schema.names[1:])

由于相对误差非常小,它可能仍然是非常苛刻的工作,所以我强烈建议稍微放松一下,一旦列数增加。

请注意,结果将与您当前方法生成的结果不同:

  • 在你的情况下,每个传递计算非增加行集上的分位数,因此它取决于列的顺序。
  • 这会对所有行计算一次分位数,并且不依赖于列的顺序。