Dataframe 从大数据集中删除模糊重复项
我有一个CSV文件,其中有许多记录。每个记录代表一个人。它有Dataframe 从大数据集中删除模糊重复项,dataframe,apache-spark,pyspark,apache-spark-sql,pyspark-dataframes,Dataframe,Apache Spark,Pyspark,Apache Spark Sql,Pyspark Dataframes,我有一个CSV文件,其中有许多记录。每个记录代表一个人。它有名,姓,以及其他详细信息。 我的目标是以智能的方式从这些数据中删除重复项。记录来自不同的来源,副本可能包含不同的信息。 我在下面的示例中简化了问题: df = spark.createDataFrame( [ (1, "Anna", "Smyth", "01/03", "NY"), (2, "Anna&qu
名
,姓
,以及其他详细信息。
我的目标是以智能的方式从这些数据中删除重复项。记录来自不同的来源,副本可能包含不同的信息。
我在下面的示例中简化了问题:
df = spark.createDataFrame(
[
(1, "Anna", "Smyth", "01/03", "NY"),
(2, "Anna", "Smyth", "01/03", ""),
(3, "Anna", "Smyth", "01/03", "NY"),
(4, "Max", "Anderson", "12/04", "Boston"),
(5, "Max", "Anderson", "", "London"),
(6, "Max", "Anderson", "06/07", ""),
(7, "Sarah", "Nicolson", "02/09", ""),
(8, "Sarah", "Jonson", "", "Mexico"),
(9, "Sarah", "Jonson", "01/08", "Dallas"),
],
("id", "first_name", "last_name", "birthday", "city")
)
df.show()
+---+----------+---------+--------+------+
| id|first_name|last_name|birthday| city|
+---+----------+---------+--------+------+
| 1| Anna| Smyth| 01/03| NY|
| 2| Anna| Smyth| 01/03| |
| 3| Anna| Smyth| 01/03| NY|
| 4| Max| Anderson| 12/04|Boston|
| 5| Max| Anderson| |London|
| 6| Max| Anderson| 06/07| |
| 7| Sarah| Nicolson| 02/09| |
| 8| Sarah| Jonson| |Mexico|
| 9| Sarah| Jonson| 01/08|Dallas|
+---+----------+---------+--------+------+
<>我想用“代码>第一个名字< /COD>和<代码> LASTYNMENT//CODE分组记录,然后做一些比较来考虑记录是否是重复的。
如果几乎没有记录有相同的名字和姓氏,我想检查生日
,如果它等于-它是重复的。
如果一条或多条记录已填充生日
,则另一条记录-不填充,它是重复的。如果两个(或多个)记录都是空的生日
-则重复。
相比之下,我忽略了city
字段,但在考虑重复项时,我希望留下“最富”的记录,即填充了更多字段的记录。
如果记录有相同的名字,但不同的生日-它不是重复的
例如,在上面,我想得到:
+---+----------+---------+--------+------+
| id|first_name|last_name|birthday| city|
+---+----------+---------+--------+------+
| 1| Anna| Smyth| 01/03| NY|
| 4| Max| Anderson| 12/04|Boston|
| 6| Max| Anderson| 06/07| |
| 7| Sarah| Nicolson| 02/09| |
| 9| Sarah| Jonson| 01/08|Dallas|
+---+----------+---------+--------+------+
在实际问题中,我有更多的字段——大约70个,其中一些字段应该是必须匹配的,而另一些字段则不是。我需要处理的记录数量——大约1亿条。
我正在考虑使用pyspark,但任何技术都欢迎首先,您可以通过连接列First_name#last_name#birth
来为每行创建组列grp
,其中birth
由分区的max替换[First_name
,last_name]
,如果它是null或空字符串:
from pyspark.sql import Window
from pyspark.sql import functions as F
w1 = Window.partitionBy("first_name", "last_name").orderBy()
df1 = df.withColumn(
"grp",
F.concat_ws(
"#",
"first_name",
"last_name",
F.coalesce(F.expr("nullif(birthday, '')"), F.max("birthday").over(w1))
)
).withColumn(
"rich_columns",
F.array(
*[F.col(c) for c in df.columns if c not in ["id", "first_name", "last_name"]]
)
)
df1.show(truncate=False)
#+---+----------+---------+--------+------+--------------------+---------------+
#|id |first_name|last_name|birthday|city |grp |rich_columns |
#+---+----------+---------+--------+------+--------------------+---------------+
#|1 |Anna |Smyth |01/03 |NY |Anna#Smyth#01/03 |[01/03, NY] |
#|2 |Anna |Smyth |01/03 | |Anna#Smyth#01/03 |[01/03, ] |
#|3 |Anna |Smyth |01/03 |NY |Anna#Smyth#01/03 |[01/03, NY] |
#|7 |Sarah |Nicolson |02/09 | |Sarah#Nicolson#02/09|[02/09, ] |
#|8 |Sarah |Jonson | |Mexico|Sarah#Jonson#01/08 |[, Mexico] |
#|9 |Sarah |Jonson |01/08 |Dallas|Sarah#Jonson#01/08 |[01/08, Dallas]|
#|4 |Max |Anderson |12/04 |Boston|Max#Anderson#12/04 |[12/04, Boston]|
#|5 |Max |Anderson | |London|Max#Anderson#12/04 |[, London] |
#|6 |Max |Anderson |06/07 | |Max#Anderson#06/07 |[06/07, ] |
#+---+----------+---------+--------+------+--------------------+---------------+
列生日
和城市
也用于创建一个数组列rich_columns
,该列将用于对max info不为空/null的行进行优先级排序
然后,使用上面创建的组列执行行号,并按rich\u列的大小排序
数组:
w2 = Window.partitionBy("grp").orderBy(
F.expr("size(filter(rich_columns, x -> nullif(x, '') is not null))").desc()
)
df2 = df1.withColumn("rn", F.row_number().over(w2)) \
.filter("rn = 1") \
.drop("grp", "rn", "rich_columns")
df2.show()
#+---+----------+---------+--------+------+
#| id|first_name|last_name|birthday| city|
#+---+----------+---------+--------+------+
#| 7| Sarah| Nicolson| 02/09| |
#| 1| Anna| Smyth| 01/03| NY|
#| 9| Sarah| Jonson| 01/08|Dallas|
#| 6| Max| Anderson| 06/07| |
#| 4| Max| Anderson| 12/04|Boston|
#+---+----------+---------+--------+------+
在实际应用程序中,在执行此操作之前,应将列姓
、名
转换为大写字母和带重音符号(如果有)