Скажем, у меня есть фрейм данных PySpark, например:
+--+--+--+--+
|a |b |c |d |
+--+--+--+--+
|1 |0 |1 |2 |
|0 |2 |0 |1 |
|1 |0 |1 |2 |
|0 |4 |3 |1 |
+--+--+--+--+
Как я могу создать столбец, обозначающий все повторяющиеся строки, например:
+--+--+--+--+--+
|a |b |c |d |e |
+--+--+--+--+--+
|1 |0 |1 |2 |1 |
|0 |2 |0 |1 |0 |
|1 |0 |1 |2 |1 |
|0 |4 |3 |1 |0 |
+--+--+--+--+--+
Я попытался использовать функции groupBy и агрегата безрезультатно.
Определите функцию window
чтобы проверить, больше ли count
строк при группировке по всем столбцам больше 1. Если да, то его дубликат (1) еще не дублирует (0)
allColumns = df.columns
import sys
from pyspark.sql import functions as f
from pyspark.sql import window as w
windowSpec = w.Window.partitionBy(allColumns).rowsBetween(-sys.maxint, sys.maxint)
df.withColumn('e', f.when(f.count(f.col('d')).over(windowSpec) > 1, f.lit(1)).otherwise(f.lit(0))).show(truncate=False)
которые должны дать вам
+---+---+---+---+---+
|a |b |c |d |e |
+---+---+---+---+---+
|1 |0 |1 |2 |1 |
|1 |0 |1 |2 |1 |
|0 |2 |0 |1 |0 |
|0 |4 |3 |1 |0 |
+---+---+---+---+---+
Я надеюсь, что ответ будет полезен
обновленный
Как прокомментировал @pault, вы можете устранить, when
, col
и lit
, отбрасывая boolean
в integer
:
df.withColumn('e', (f.count('*').over(windowSpec) > 1).cast('int')).show(truncate=False)
Просто чтобы увеличить мой комментарий:
Вы можете группировать все столбцы и использовать pyspark.sql.functions.count()
для определения дублирования столбца:
import pyspark.sql.functions as f
df.groupBy(df.columns).agg((f.count("*")>1).cast("int").alias("e")).show()
#+---+---+---+---+---+
#| a| b| c| d| e|
#+---+---+---+---+---+
#| 1| 0| 1| 2| 1|
#| 0| 2| 0| 1| 0|
#| 0| 4| 3| 1| 0|
#+---+---+---+---+---+
Здесь мы используем count("*") > 1
как агрегированную функцию и передаем результат в int
. У groupBy()
будет результат сброса повторяющихся строк. В зависимости от ваших потребностей этого может быть достаточно.
Однако, если вы хотите сохранить все строки, вы можете использовать функцию Window
как показано в других ответах, или вы можете использовать join()
:
df.join(
df.groupBy(df.columns).agg((f.count("*")>1).cast("int").alias("e")),
on=df.columns,
how="inner"
).show()
#+---+---+---+---+---+
#| a| b| c| d| e|
#+---+---+---+---+---+
#| 1| 0| 1| 2| 1|
#| 1| 0| 1| 2| 1|
#| 0| 2| 0| 1| 0|
#| 0| 4| 3| 1| 0|
#+---+---+---+---+---+
Здесь мы соединяем исходный фреймворк с тем, который является результатом groupBy()
на всех столбцах.
Разделите свой фреймворк со всеми столбцами и примените dense_rank.
import sys
from pyspark.sql.functions import dense_rank
from pyspark.sql import window as w
df.withColumn('e', dense_rank().over(w.Window.partitionBy(df.columns))).show()
AnalysisException: u'Window function dense_rank() requires window to be ordered
df.withColumn('e', (f.count('*').over(windowSpec) > 1).cast('int')).show(truncate=False)
when
,col
илиlit
вы можете привести условие к целому числу:df.withColumn('e', (f.count('*').over(windowSpec) > 1).cast('int')).show(truncate=False)