Dataframe pyspark使用每个id的最小值筛选数据帧

Dataframe pyspark使用每个id的最小值筛选数据帧,dataframe,filter,pyspark,conditional-statements,Dataframe,Filter,Pyspark,Conditional Statements,给出如下表: +--+------------------+-----------+ |id| diagnosis_age| diagnosis| +--+------------------+-----------+ | 1|2.1843037179180302| 315.320000| | 1| 2.80033330216659| 315.320000| | 1| 2.8222365762732| 315.320000| | 1| 5.64822705794013| 325

给出如下表:

+--+------------------+-----------+
|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.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]]))
如果是rdd,您可以执行以下操作:

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.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操作


谢谢

您可以先使用带有
功能的
窗口
,然后再使用
过滤
排除所有其他功能

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|
+---+------------------+---------+
您也可以在不使用窗口功能的情况下执行此操作,使用
groupBy
min
首先

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|
+---+------------------+---------+

注意我在
组b之前按
诊断年龄
排序
,以处理所需诊断值未出现在第一行的情况但是,如果您的数据已经按
诊断年龄
排序,您可以使用上述代码,而不使用
排序依据

,尝试运行代码并获得以下错误:AnalysisException:u无法解析窗口函数“第一个值”。请注意,使用窗口函数当前需要HiveContext;“我假设如果我使用配置单元上下文,这将得到修复,但没有其他解决方案吗?@mad-a我已使用groupBy.version 1.6和sql上下文更新了解决方案。我使用配置单元上下文运行了您的第一个代码,它确实起作用。您的第二个解决方案实际上不起作用(数据比我提供的示例表大得多)。一个id在同一最小诊断年龄可以有多个诊断,因此,如果我没有弄错的话,第一次诊断排除了id在同一诊断年龄可能具有的任何其他诊断?无论哪种方式,您的第一个解决方案都可以完美地工作,只是遗憾的是,它无法在没有配置单元上下文的情况下复制。非常感谢:)