PySpark - получить индексы повторяющихся строк

1

Скажем, у меня есть фрейм данных 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 и агрегата безрезультатно.

Теги:
apache-spark
pyspark

3 ответа

2

Определите функцию 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)
  • 0
    Здесь не нужно 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)
  • 1
    Спасибо @pault за комментарий :) очень полезно, я включил ваш комментарий в свой ответ
1

Просто чтобы увеличить мой комментарий:

Вы можете группировать все столбцы и использовать 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() на всех столбцах.

1

Разделите свой фреймворк со всеми столбцами и примените 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()
  • 0
    AnalysisException: u'Window function dense_rank() requires window to be ordered
  • 0
    Я не думаю, что это работает. Ты это пробовал?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню