【问题标题】:pyspark filter a dataframe using the min value for each idpyspark 使用每个 id 的最小值过滤数据帧
【发布时间】:2020-03-24 18:11:11
【问题描述】:

给定如下表格:

+--+------------------+-----------+
|id|     diagnosis_age|  diagnosis|
+--+------------------+-----------+
| 1|2.1843037179180302| 315.320000|
| 1|  2.80033330216659| 315.320000|
| 1|   2.8222365762732| 315.320000|
| 1|  5.64822705794013| 325.320000|
| 1| 5.686557787521759| 335.320000|
| 2|  5.70572315231258| 315.320000|
| 2| 5.724888517103389| 315.320000|
| 3| 5.744053881894209| 315.320000|
| 3|5.7604813374292005| 315.320000|
| 3|  5.77993740687426| 315.320000|
+--+------------------+-----------+

我试图通过仅考虑每个 id 诊断年龄最小的诊断来减少每个 id 的记录数量。在 SQL 中,您可以将表连接到自身,例如:

SELECT a.id, a.diagnosis_age, a.diagnosis
    FROM tbl1 a
INNER JOIN
(SELECT id, MIN(diagnosis_age) AS min_diagnosis_age
    FROM tbl1
        GROUP BY id) b
ON b.id = a.id
WHERE b.min_diagnosis_age = a.diagnosis_age

如果是 rdd,你可以这样做:

rdd.map(lambda x: (x["id"], [(x["diagnosis_age"], x["diagnosis"])]))\
.reduceByKey(lambda x, y: x + y)\
.map(lambda x: (x[0], [i for i in x[1] if i[0] == min(x[1])[0]]))

您将如何仅使用 spark 数据帧操作来实现相同的目标?如果这是可能的?特别是没有 sql/rdd 操作。

谢谢

【问题讨论】:

    标签: dataframe filter pyspark conditional-statements


    【解决方案1】:

    您可以将windowfirst 函数一起使用,然后将filter 与所有其他函数一起使用。

    from pyspark.sql import functions as F
    from pyspark.sql.window import Window
    w=Window().partitionBy("id").orderBy("diagnosis_age")
    df.withColumn("least_age", F.first("diagnosis_age").over(w))\
    .filter("diagnosis_age=least_age").drop("least_age").show()
    
    +---+------------------+---------+
    | id|     diagnosis_age|diagnosis|
    +---+------------------+---------+
    |  1|2.1843037179180302|   315.32|
    |  3| 5.744053881894209|   315.32|
    |  2|  5.70572315231258|   315.32|
    +---+------------------+---------+
    

    你也可以这样做没有窗口功能,使用groupByminfirst

    from pyspark.sql import functions as F
    df.orderBy("diagnosis_age").groupBy("id")\
    .agg(F.min("diagnosis_age").alias("diagnosis_age"), F.first("diagnosis").alias("diagnosis"))\
    .show()
    +---+------------------+---------+
    | id|     diagnosis_age|diagnosis|
    +---+------------------+---------+
    |  1|2.1843037179180302|   315.32|
    |  3| 5.744053881894209|   315.32|
    |  2|  5.70572315231258|   315.32|
    +---+------------------+---------+
    

    注意,我在groupyBy 之前订购了由diagnosis_age 处理那些所需的诊断值没有出现在第一行的情况强>组但是,如果您的数据已经按diagnosis_age 排序,您可以使用上面的代码没有orderBy

    【讨论】:

    • 您好,尝试运行您的代码并收到以下错误:AnalysisException: u"Could not resolve window function 'first_value'。请注意,当前使用窗口函数需要 HiveContext;"如果我使用配置单元上下文,我认为这将得到解决,但是没有其他解决方法吗?
    • @mad-a 我已经使用 groupBy 更新了解决方案。
    • 1.6 版,带有 sql 上下文。我用 hive 上下文运行了你的第一个代码,它确实有效。您的第二个解决方案实际上不起作用(数据比我提供的示例表大得多)。一个 id 可以在同一 min diagnostic_age 有多个诊断,所以如果我没记错的话,第一个诊断会排除该 id 在相同诊断年龄时可能有的任何其他诊断?无论哪种方式,您的第一个解决方案都可以完美运行,可惜没有配置单元上下文就无法复制它。非常感谢:)
    猜你喜欢
    • 1970-01-01
    • 2017-03-16
    • 2021-04-10
    • 1970-01-01
    • 2017-10-21
    • 1970-01-01
    • 2019-02-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多