Получить верхнюю часть n в каждой группе DataFrame в pyspark

Там находится DataFrame в pyspark с данными, как показано ниже:

user_id object_id score
user_1  object_1  3
user_1  object_1  1
user_1  object_2  2
user_2  object_1  5
user_2  object_2  2
user_2  object_2  6

Я ожидаю, что возвратит 2 записи в каждой группе с тем же user_id, который должен иметь самый высокий балл. Следовательно, результат должен выглядеть следующим образом:

user_id object_id score
user_1  object_1  3
user_1  object_2  2
user_2  object_2  6
user_2  object_1  5

Я действительно новичок в pyspark, может ли кто-нибудь дать мне фрагмент кода или портал для соответствующей документации по этой проблеме? Большое спасибо!

Ответ 1

Я считаю, что вам нужно использовать функции окна для достижения ранга каждой строки на основе user_id и score, а затем фильтра ваши результаты сохраняют только первые два значения.

from pyspark.sql.window import Window
from pyspark.sql.functions import rank, col

window = Window.partitionBy(df['user_id']).orderBy(df['score'].desc())

df.select('*', rank().over(window).alias('rank')) 
  .filter(col('rank') <= 2) 
  .show() 
#+-------+---------+-----+----+
#|user_id|object_id|score|rank|
#+-------+---------+-----+----+
#| user_1| object_1|    3|   1|
#| user_1| object_2|    2|   2|
#| user_2| object_2|    6|   1|
#| user_2| object_1|    5|   2|
#+-------+---------+-----+----+

В общем, официальное руководство по программированию является хорошим местом для начала изучения Искры.

Данные

rdd = sc.parallelize([("user_1",  "object_1",  3), 
                      ("user_1",  "object_2",  2), 
                      ("user_2",  "object_1",  5), 
                      ("user_2",  "object_2",  2), 
                      ("user_2",  "object_2",  6)])
df = sqlContext.createDataFrame(rdd, ["user_id", "object_id", "score"])

Ответ 2

Top-n более точен, если вместо rank использовать row_number вместо равенства ранга:

val n = 5
df.select(col('*'), row_number().over(window).alias('row_number')) \
  .where(col('row_number') <= n) \
  .limit(20) \
  .toPandas()

Примечание limit(20).toPandas() трюк вместо show() для ноутбуков Jupyter для лучшего форматирования.

Ответ 3

Я знаю, что вопрос задан для pyspark, и я искал аналогичный ответ в Scala, т.е.

Получить первые n значений в каждой группе DataFrame в Scala

Вот [@TG42] версия ответа @mtoto.

import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.functions.rank
import org.apache.spark.sql.functions.col

val window = Window.partitionBy("user_id").orderBy('score desc)
val rankByScore = rank().over(window)
df1.select('*, rankByScore as 'rank).filter(col("rank") <= 2).show() 
# you can change the value 2 to any number you want. Here 2 represents the top 2 values

Больше примеров можно найти здесь here.

Ответ 4

Чтобы найти N-е наибольшее значение в SQL-запросе PYSPARK с помощью функции ROW_NUMBER():

SELECT * FROM (
    SELECT e.*, 
    ROW_NUMBER() OVER (ORDER BY col_name DESC) rn 
    FROM Employee e
)
WHERE rn = N

N - это девятое наибольшее значение, требуемое из столбца

Выход:

[Stage 2:>               (0 + 1) / 1]++++++++++++++++
+-----------+
|col_name   |
+-----------+
|1183395    |
+-----------+

запрос вернет N наибольшее значение