Fuzzywuzzy 合并多列 - 熊猫

时间:2021-07-27 16:14:59

标签: python pandas string networkx fuzzywuzzy

我有 2 个数据框:

数据框 1:

    path                      hierarchy
0  path3              path1/path2/path3
1  path2                    path1/path2
2  path6  path1/path2/path4/path5/path6

数据帧 2:

    path                       hierarcy  unique_id
0  path2    path1/<random_string>/path2          1
1  Path3   <random_string>/Path_2/path3          2
2  path2                    path1/Path2          3
3  pAth6        path1/path2/path4/path6          4
4  path6  path1/path2/path4/path5/path6          5

预期输出:

    path                      hierarchy  unique_id
0  path3              path1/path2/path3          2
1  path2                    path1/path2          3
2  path6  path1/path2/path4/path5/path6          5

现在,我想填写从第二个数据帧到第一个数据帧的 unique_id。但是,有一些问题-

  1. 我无法直接根据 merge(left) 列执行 path 2 个数据帧,因为正确的路径也取决于 hierarchy 列。
  2. hierarchy 列中的字符串 not 完全相同。有一些差异,例如 Path_2path2。这同样适用于路径列。

我尝试了 fuzzy 匹配,但导致问题的是 hierarchy 列。我想从层次结构列的右侧开始匹配,然后向左移动,在每个级别上应用模糊匹配。 我不确定这是否是一个好方法。

基本上,要求是根据两个路径/层次结构列确定最完美的匹配。

用于创建数据框的字典:

df1 = pd.DataFrame({'path': {0: 'path3', 1: 'path2', 2: 'path6'},
 'hierarchy': {0: 'path1/path2/path3',
  1: 'path1/path2',
  2: 'path1/path2/path4/path5/path6'}})


df2 = pd.DataFrame({'path': {0: 'path2', 1: 'Path3', 2: 'path2', 3: 'path6', 4: 'path6'},
 'hierarcy': {0: 'path1/<random_string>/path2',
  1: '<random_string>/Path_2/path3',
  2: 'path1/Path2',
  3: 'path1/path2/path4/path6',
  4: 'path1/path2/path4/path5/path6'},
 'unique_id': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5}})


df3 = pd.DataFrame({'path': {0: 'path3', 1: 'path2', 2: 'path6'},
 'hierarchy': {0: 'path1/path2/path3',
  1: 'path1/path2',
  2: 'path1/path2/path4/path5/path6'},
 'unique_id': {0: 2, 1: 3, 2: 5}})

感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

将 df1 和 df2 中的文本转换为小写:

df1['path'] = df1['path'].str.lower()
df2['path'] = df2['path'].str.lower()

合并:

result = pd.merge(df1, df2, on=['path'])

结果:

enter image description here

答案 1 :(得分:0)

我尝试了模糊匹配,但没有得到令人满意的结果,因为层次结构的顺序在这里至关重要。让我建议一种替代方法,将层次结构视为向量,然后检索 idx 中向量的 df2 与最近的空间接近度。在下面的示例中,路径被清理,由 / 分割并被分配一个唯一值。随后,针对 df1 中具有相同长度的向量计算 df2 中每个层次的空间距离:

import pandas as pd
import numpy as np
from scipy import spatial

df1 = pd.DataFrame({'path': {0: 'path3', 1: 'path2', 2: 'path6'},
 'hierarchy': {0: 'path1/path2/path3',
  1: 'path1/path2',
  2: 'path1/path2/path4/path5/path6'}})


df2 = pd.DataFrame({'path': {0: 'path2', 1: 'Path3', 2: 'path2', 3: 'path6', 4: 'path6'},
 'hierarchy': {0: 'path1/<random_string>/path2',
  1: '<random_string>/Path_2/path3',
  2: 'path1/Path2',
  3: 'path1/path2/path4/path6',
  4: 'path1/path2/path4/path5/path6'},
 'unique_id': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5}})

#clean up paths
df1['hierarchy'] = df1['hierarchy'].str.lower().str.replace('_','').str.split('/')
df2['hierarchy'] = df2['hierarchy'].str.lower().str.replace('_','').str.split('/')

#create unique integer ids per path and map them to the dataframes
unique_dirs = set(list(np.concatenate(df1['hierarchy'].to_list() + df2['hierarchy'].to_list())))
dir_map = dict(zip(unique_dirs, range(len(unique_dirs))))

df1 = df1.assign(mapped=[list(map(dir_map.get, x)) for x in df1.hierarchy])
df2 = df2.assign(mapped=[list(map(dir_map.get, x)) for x in df2.hierarchy])

#calculate spatial distance to vectors from df2 with the same length, then return the matched hierarchy and idx
def check(row):
  value = row['mapped']
  arr = np.array(df2[df2['mapped'].str.len() == len(value)]['mapped'].to_list())
  tree = spatial.KDTree(arr)
  distances, indices = tree.query(value)
  matches = df2[df2['mapped'].astype(str) == str(tree.data[indices].tolist())]
  return matches['hierarchy'].tolist()[0], matches['unique_id'].tolist()[0]

df1[['match', 'idx']] = df1.apply(check, axis=1, result_type="expand")

结果df1

<头>
路径 层次结构 映射 匹配 idx
0 path3 ['path1', 'path2', 'path3'] [0, 1, 3] ['', 'path2', 'path3'] 2
1 path2 ['path1', 'path2'] [0, 1] ['path1', 'path2'] 3
2 path6 ['path1', 'path2', 'path4', 'path5', 'path6'] [0, 1, 6, 5, 4] ['path1', 'path2', 'path4', 'path5', 'path6'] 5

如果在同一位置存在多个具有随机路径的类似层次结构,代码可能会在计算上进行优化,并且将无法运行。在这种情况下,我不会分配随机整数,而是在计算距离之前使用语言模型检索路径的嵌入。