我有 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。但是,有一些问题-
merge(left)
列执行 path
2 个数据帧,因为正确的路径也取决于 hierarchy
列。not
完全相同。有一些差异,例如 Path_2
和 path2
。这同样适用于路径列。我尝试了 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}})
感谢任何帮助。
答案 0 :(得分:0)
将 df1 和 df2 中的文本转换为小写:
df1['path'] = df1['path'].str.lower()
df2['path'] = df2['path'].str.lower()
合并:
result = pd.merge(df1, df2, on=['path'])
结果:
答案 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] | [' |
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 |
如果在同一位置存在多个具有随机路径的类似层次结构,代码可能会在计算上进行优化,并且将无法运行。在这种情况下,我不会分配随机整数,而是在计算距离之前使用语言模型检索路径的嵌入。