Я пытаюсь пометить дубликаты в моем фрейме данных PySpark на основе их группы, имея при этом полный фрейм данных. Ниже приведен пример кода.

data= [
    ("A", "2018-01-03"),
    ("A", "2018-01-03"),
    ("A", "2018-01-03"),
    ("B", "2019-01-03"),
    ("B", "2019-01-03"),
    ("B", "2019-01-03"),
    ("C", "2020-01-03"),
    ("C", "2020-01-03"),
    ("C", "2020-01-03"),
]

from pyspark.sql import SparkSession
import pyspark.sql.functions as F

spark= SparkSession.builder.getOrCreate()

df= spark.createDataFrame(data=data, schema=["Group", "Date"])
df= df.withColumn("Date", F.to_date("Date", "yyyy-MM-dd"))


from pyspark.sql import Window
windowSpec= Window.partitionBy("Group").orderBy(F.asc("Date"))

df.withColumn("group_number", F.dense_rank().over(windowSpec)).orderBy("Date").show()

Это мой текущий результат, и хотя он верен, так как код ранжируется как «Дата» на основе своей группы, но это не было моим желаемым результатом.

+-----+----------+------------+
|Group|      Date|group_number|
+-----+----------+------------+
|    A|2018-01-03|           1|
|    A|2018-01-03|           1|
|    A|2018-01-03|           1|
|    B|2019-01-03|           1|
|    B|2019-01-03|           1|
|    B|2019-01-03|           1|
|    C|2020-01-03|           1|
|    C|2020-01-03|           1|
|    C|2020-01-03|           1|
+-----+----------+------------+

Я надеялся, что мой результат будет выглядеть так

+-----+----------+------------+
|Group|      Date|group_number|
+-----+----------+------------+
|    A|2018-01-03|           1|
|    A|2018-01-03|           1|
|    A|2018-01-03|           1|
|    B|2019-01-03|           2|
|    B|2019-01-03|           2|
|    B|2019-01-03|           2|
|    C|2020-01-03|           3|
|    C|2020-01-03|           3|
|    C|2020-01-03|           3|
+-----+----------+------------+

Какие-либо предложения? Я нашел этот пост, но это всего лишь двоичное решение! В моем наборе данных более двух групп.

1
Behzad Rowshanravan 21 Янв 2021 в 04:25

2 ответа

Лучший ответ

Вам не нужно использовать функцию partitionBy, когда вы объявляете свой windowSpec. Указывая столбец «Группа» в partionBy, вы сообщаете программе, что необходимо выполнить функцию density_rank () для каждого раздела на основе «Даты». Итак, вывод правильный. Если мы посмотрим на группу A, у них одинаковые даты, таким образом, все они имеют group_rank, равное 1. Переходя к группе B, все они имеют одинаковые даты, таким образом, они имеют ранг группы 1.

Итак, быстрое решение вашей проблемы - удалить partionBy в вашем windowSpec.

РЕДАКТИРОВАТЬ: Если вы должны были сгруппировать по столбцу Group, следующее решение является другим: вы можете использовать определяемую пользователем функцию (UDF) в качестве второго параметра аргумента в df.withColumn (). В этом UDF вы должны указать свой ввод / вывод как обычную функцию. Что-то вроде этого:

import pyspark.sql.functions import udf

def new_column(group):
  return ord(group) - 64 # Unicode integer equivalent as A is 65

funct = udf(new_column, IntegerType())

df.withColumn("group_number", funct(df["Group"])).orderBy("Date").show()

Если бы вы использовали UDF для даты, вам понадобился бы способ отслеживать даты. Пример:

import datetime

date_dict = {}
def new_column(date_obj):
   if len(date_dict) > 0 and date_dict[date_obj.strftime("%Y-%m-%d")]:
     return date_dict[date_obj.strftime("%Y-%m-%d")]
   date_dict[date_obj.strftime("%Y-%m-%d")] = len(date_obj.strftime("%Y-%m-%d")) + 1
   return date_dict[date_obj.strftime("%Y-%m-%d")]
1
Willy Chang 21 Янв 2021 в 03:52

Что вы хотите, так это ранжировать по всем группам, а не в каждой группе, поэтому вам не нужно разбивать по Window, просто отсортируйте по Group, и Date даст вам желаемый результат :

windowSpec = Window.orderBy(F.asc("Group"), F.asc("Date"))

df.withColumn("group_number", F.dense_rank().over(windowSpec)).orderBy("Date").show()

#+-----+----------+------------+
#|Group|      Date|group_number|
#+-----+----------+------------+
#|    A|2018-01-03|           1|
#|    A|2018-01-03|           1|
#|    A|2018-01-03|           1|
#|    B|2019-01-03|           2|
#|    B|2019-01-03|           2|
#|    B|2019-01-03|           2|
#|    C|2020-01-03|           3|
#|    C|2020-01-03|           3|
#|    C|2020-01-03|           3|
#+-----+----------+------------+

И вам, безусловно, не нужен UDF , как предполагает другой ответ.

0
blackbishop 21 Янв 2021 в 12:15