Как узнать количество уникальных элементов для столбца в группе в PySpark?

#apache-spark #pyspark #apache-spark-sql

#apache-spark #PySpark #apache-spark-sql

Вопрос:

У меня есть фрейм данных PySpark-

 df1 = spark.createDataFrame([
    ("u1", 1),
    ("u1", 2),
    ("u2", 1),
    ("u2", 1),
    ("u2", 1),
    ("u3", 3),
    ],
    ['user_id', 'var1'])

print(df1.printSchema())
df1.show(truncate=False)
 

Вывод-

 root
 |-- user_id: string (nullable = true)
 |-- var1: long (nullable = true)

None
 ------- ---- 
|user_id|var1|
 ------- ---- 
|u1     |1   |
|u1     |2   |
|u2     |1   |
|u2     |1   |
|u2     |1   |
|u3     |3   |
 ------- ---- 
 

Теперь я хочу сгруппировать всех уникальных пользователей и показать количество уникальных переменных для них в новом столбце. Желаемый результат будет выглядеть так-

  ------- --------------- 
|user_id|num_unique_var1|
 ------- --------------- 
|u1     |2              |
|u2     |1              |
|u3     |1              |
 ------- --------------- 
 

Я могу использовать collect_set и создать udf, чтобы найти длину набора. Но я думаю, что должен быть лучший способ сделать это.
Как мне добиться этого в одной строке кода?

Ответ №1:

 df1.groupBy('user_id').agg(F.countDistinct('var1').alias('num')).show()
 

countDistinct — это именно то, что мне было нужно.

Вывод-

  ------- --- 
|user_id|num|
 ------- --- 
|     u3|  1|
|     u2|  1|
|     u1|  2|
 ------- --- 
 

Ответ №2:

countDistinct это, безусловно, лучший способ сделать это, но для полноты картины то, что вы сказали в своем вопросе, также возможно без использования UDF. Вы можете использовать size , чтобы получить длину collect_set :

 df1.groupBy('user_id').agg(F.size(F.collect_set('var1')).alias('num'))
 

это полезно, если вы хотите использовать его в оконной функции, поскольку countDistinct он не поддерживается в оконной функции.

например ,

 df1.withColumn('num', F.countDistinct('var1').over(Window.partitionBy('user_id')))
 

потерпел бы неудачу, но

 df1.withColumn('num', F.size(F.collect_set('var1')).over(Window.partitionBy('user_id')))
 

это сработало бы.

Комментарии:

1. я попробовал F.len вместо F.size, и это не сработало. Спасибо за новую информацию

2. @n0obcoder не существует такого понятия, как F.len. Вы можете увидеть все доступные функции в документации (их очень МНОГО!).

3. на самом деле есть длина F., но она используется для измерения длины строки.