为分组的火花数据帧选择最旧的列

时间:2019-07-04 21:17:13

标签: dataframe pyspark apache-spark-sql pyspark-sql

给出具有以下列的数据框(df):

id,
created_date,
name

我需要确保所有具有相同名称的行都具有相同的ID。我可以创建一个从旧ID到新ID(使用max在“随机”中选择)的映射。

df.groupBy('name')\
  .agg(
    func.max('id').alias('new_id'),                         
    func.collect_set(id).alias('grouped_ids'))\
  .filter(func.size('grouped_ids') > 1)\                
  .select(func.explode("grouped_ids").alias('old_id'), "new_id")\
  .filter("new_id != old_id")

我可以将剩下的人加入到原始df中(在id = old_id上),并在有new_id可用的情况下交换ID。

但是,我需要确保所选的new_id是数据框中创建日期最旧的new_id(而不只是选择最大值)。

如何最好地做到这一点?

例如给定数据

id, created_date, name
---
17a, 2019-01-05, Jeff
17a, 2019-01-03, Jeremy
d21, 2019-01-04, Jeremy
u45, 2019-01-04, Jeremy
d21, 2019-01-02, Scott
x22, 2019-01-01, Julian

杰里米(Jeremy)上的第2、3和4组,因此应该具有相同的ID。分组ID中数据框中最早的ID为d21,因为第5行上created_date为2019-01-02,因此应选择该ID并将其应用于具有其他分组ID的数据框中的所有行,最后得到:

id, created_date, name
---
d21, 2019-01-05, Jeff
d21, 2019-01-03, Jeremy
d21, 2019-01-04, Jeremy
d21, 2019-01-04, Jeremy
d21, 2019-01-02, Scott
x22, 2019-01-01, Julian

更新: @Charles Du-干杯,我尝试了您的代码,但是没有解决,最旧的ID是从分组名称中选择的,而不是从整个DF中选择的,而new_id并未在整个DF中应用。

Result:
0 = {Row} Row(name='Scott', created_date='2019-01-02', new_ID='d21', id='d21', created_date='2019-01-02')
1 = {Row} Row(name='Julian', created_date='2019-01-01', new_ID='x22', id='x22', created_date='2019-01-01')
2 = {Row} Row(name='Jeremy', created_date='2019-01-03', new_ID='17a', id='17a', created_date='2019-01-03')
3 = {Row} Row(name='Jeremy', created_date='2019-01-03', new_ID='17a', id='d21', created_date='2019-01-04')
4 = {Row} Row(name='Jeremy', created_date='2019-01-03', new_ID='17a', id='u45', created_date='2019-01-04')
5 = {Row} Row(name='Jeff', created_date='2019-01-05', new_ID='17a', id='17a', created_date='2019-01-05')

1 个答案:

答案 0 :(得分:0)

我的口水在这里

from pyspark.sql import functions as F

new_df = df.groupBy('name').agg(F.min('date'))

new_df = new_df.join(df, on=['name', 'date'], how='inner')

# This should give you a df with a single record for each name with the oldest ID.

new_df = new_df.withColumnRenamed('id', 'new_ID')

#you'll need to decide on a naming convention for your date column since you'll have two if you don't rename

res = new_df.join(df, on='name', how='inner)

应将您的ID与最早的日期相匹配。