假设我有一个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和聚合函数无效。
答案 0 :(得分: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 commented,您可以通过将when
转换为col
来消除lit
,boolean
和integer
:
df.withColumn('e', (f.count('*').over(windowSpec) > 1).cast('int')).show(truncate=False)
答案 1 :(得分:2)
只是扩展my comment:
您可以按所有列进行分组,并使用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()
的结果相连接。
答案 2 :(得分: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()
答案 3 :(得分:0)
df1=df_interr.groupBy("Item_group","Item_name","price").count().filter("count > 1")