在 3 个 DataFrame 列中识别略有不同的唯一可识别通用名称的算法

Posted

技术标签:

【中文标题】在 3 个 DataFrame 列中识别略有不同的唯一可识别通用名称的算法【英文标题】:Algo to identify slightly different uniquely identifiable common names in 3 DataFrame columns 【发布时间】:2021-06-15 08:39:16 【问题描述】:

示例DataFramedf 有 3 列来识别任何给定的人,即namenick_nameinitials。它们在指定方式上可能略有不同,但同时查看三列可以克服这些差异并将给定人员的所有行分开,并为每个人使用单个值规范化这 3 列。

>>> import pandas as pd
>>> df = pd.DataFrame('ID':range(9), 'name':['Theodore', 'Thomas', 'Theodore', 'Christian', 'Theodore', 'Theodore R', 'Thomas', 'Tomas', 'Cristian'], 'nick_name':['Tedy', 'Tom', 'Ted', 'Chris', 'Ted', 'Ted', 'Tommy', 'Tom', 'Chris'], 'initials':['TR', 'Tb', 'TRo', 'CS', 'TR', 'TR', 'tb', 'TB', 'CS'])
>>> df
   ID         name nick_name initials
0   0     Theodore      Tedy       TR
1   1       Thomas       Tom       Tb
2   2     Theodore       Ted      TRo
3   3    Christian     Chris       CS
4   4     Theodore       Ted       TR
5   5   Theodore R       Ted       TR
6   6       Thomas     Tommy       tb
7   7        Tomas       Tom       TB
8   8     Cristian     Chris       CS

在这种情况下,所需的输出如下:

   ID         name nick_name initials
0   0     Theodore       Ted       TR
1   1       Thomas       Tom       TB
2   2     Theodore       Ted       TR
3   3    Christian     Chris       CS
4   4     Theodore       Ted       TR
5   5     Theodore       Ted       TR
6   6       Thomas       Tom       TB
7   7       Thomas       Tom       TB
8   8    Christian     Chris       CS

公共值可以是任何东西,只要它被标准化为相同的值。例如,nameTheodoreTheodore R - 都可以。 我的实际DataFrame 大约有 4000 行。有人可以帮助指定最佳算法来做到这一点。

【问题讨论】:

【参考方案1】:

您需要使用 Levenshtein 距离来识别相似的字符串。一个很好的 Python 包是 fuzzywuzzy。下面我使用基本的字典方法将相似的行收集在一起,然后用指定的主行覆盖每个块。请注意,这会留下一个包含许多重复行的 CSV,我不知道这是否是您想要的,但如果不是,那么很容易将重复项取出。

import pandas as pd
from itertools import chain
from fuzzywuzzy import fuzz


def cluster_rows(df):
    row_clusters = 
    threshold = 90
    name_rows = list(df.iterrows())

    for i, nr in name_rows:
        name = nr['name']
        new_cluster = True
        for other in row_clusters.keys():
            if fuzz.ratio(name, other) >= threshold:
                row_clusters[other].append(nr)
                new_cluster = False
            
        if new_cluster:
            row_clusters[name] = [nr]

    return row_clusters

def normalize_rows(row_clusters):
    for name in row_clusters:
        master = row_clusters[name][0]
        for row in row_clusters[name][1:]:
            for key in row.keys():
                row[key] = master[key]

    return row_clusters

if __name__ == '__main__':
    df = pd.read_csv('names.csv')
    rc = cluster_rows(df)
    normalized = normalize_rows(rc)
    pd.DataFrame(chain(*normalized.values())).to_csv('norm-names.csv')

【讨论】:

以上是关于在 3 个 DataFrame 列中识别略有不同的唯一可识别通用名称的算法的主要内容,如果未能解决你的问题,请参考以下文章

从 pandas DataFrame 中的列中提取 JSON 数据

如何在同一列中写入两个不同变量值的excel/pandas Dataframe

如何将日期,年,月的不同列合并/合并到单个列中

通过从每一行的不同列中选择一个元素,从 Pandas DataFrame 创建一个系列

将列表转换为 DataFrame 并在 DataFrame 列中拆分嵌套字典 - Python 3.6

删除在 DataFrame 列中仅出现一次的值