首页 > 解决方案 > 过滤位于 pyspark.sql.dataframe 单元格中的数组

问题描述

我对 PySpark 很陌生,有一些 Python 经验。我已经能够过滤数据帧的行,并编写了 udf,它从 DataFrame 单元格中的数组计算结果,结果为 int 或 double。不,我需要一个数组作为输出,几个小时后我还没有找到一个有用的例子。

这是问题:

DataFrame 具有以下方案,其中 number 是同一 DataFrame 行的数组的条目数:

DataFrame[number: int, code: array<string>, d1: array<double>, d2: array<double>]

这是一个名为 df1 的 DataFrame 示例:

[4 ,['correct', 'correct', 'wrong', 'correct'], [33, 42, 35, 76], [12, 35, 15, 16]] 
[2 ,['correct', 'wrong'], [47, 43], [13, 17]] 

现在,只有当我在 DataFrame 行的代码列的 i 位置有“正确”时,我才想保留 d1 和 d2 的 i 位置。此外,我想有一个新的 numberNew 剩余的职位数量。生成的结构和 DataFrame“df2”应该如下所示:

DataFrame[number: int, numberNew: int, code: array<string>, d1: array<double>, d2: array<double>]

[4 , 3, ['correct', 'correct', 'correct'], [33, 42, 76], [12, 35, 16]] 
[2 , 1, ['correct'], [47], [13]] 

在其他几件事中(并且基于 Python 中的成功解决方案),我尝试了以下代码:

def filterDF(number, code, d1, d2):
    dataFiltered = []
    numberNew = 0
    for i in range(number):
        if code[i] == 'correct':
            dataFiltered.append([d1[i],d2[i]])
            countNew += 1
    newTable = {'countNew' : countNew, 'data' : dataFiltered}
    newDf = pd.DataFrame(newTable)
    return newDf    

from pyspark.sql.types import ArrayType
filterDFudf = sqlContext.udf.register("filterDF", filterDF, "Array<double>")

df2 = df1.select(df1.number, filterDFudf(df1.number, df1.code, df1.d1, df1.d2)).alias('dataNew')

我收到了一条很长且没有帮助的错误消息。即有以下信息: TypeError: 'float' object has no attribute ' getitem '

如果有人能告诉我如何解决这个问题,那就太好了。

标签: arraysdataframepyspark

解决方案


对于替代解决方案,您还可以在 python 中为您的函数使用列表理解:

def get_filtered_data(code, d1, d2):

    indices = [i for i, s in enumerate(code) if 'correct' in s]
    d1_ = [d1[index] for index in indices]
    d2_ = [d2[index] for index in indices]
    return [len(indices), d1_, d2_]

udf_get_filtered_data = udf(get_filtered_data, ArrayType(StringType()))

df = df.withColumn('filtered_data', udf_get_filtered_data('code', 'd1', 'd2'))

df.show() 返回以下内容

+------+--------------------+----------------+----------------+--------------------+
|number|                code|              d1|              d2|       filtered_data|
+------+--------------------+----------------+----------------+--------------------+
|     4|[correct, correct...|[33, 42, 35, 76]|[12, 35, 15, 16]|[3, [33, 42, 76],...|
|     2|    [correct, wrong]|        [47, 43]|        [13, 17]|     [1, [47], [13]]|
+------+--------------------+----------------+----------------+--------------------+

顺便说一句,如果你使用

dataFiltered.append([d1[i],d2[i]]) 

它不会给您指定的所需结果([33, 42, 76], [12, 35, 16])。相反,它会给你([33,12], [42,35], [76,16])

上面的这个答案为您提供了问题中提到的单独列表中d1的正确结果。d2


推荐阅读