我正在编写一个算法,基于兴趣相似性,使用NearestNeighbors(n_neighbors = 1)将setA中的每个人与setB中的某个人进行匹配。
这是我目前的代码:
dfA = pd.DataFrame(np.array([[1, 1, 1, 1], [1,1,2,2], [4, 5, 2, 0], [8, 8, 8, 8]]), columns=['interest0', 'interest2', 'interest3','interest4'], index=['personA0','personA1','personA2','personA3'])dfB = pd.DataFrame(np.array([[1, 1, 1, 1], [1, 1, 1, 2], [2,3,2,2], [8, 6, 8, 8]]), columns=['interest0', 'interest2', 'interest3','interest4'], index=['personB0','personB1','personB2','personB3'])knn = NearestNeighbors(n_neighbors = 1, metric = my_dist).fit(dfA)distances, indices = knn.kneighbors(dfB)>>> dfA drink interest2 interest3 interest4personA0 1 1 1 1personA1 1 1 2 2personA2 4 5 2 0personA3 8 8 8 8>>> dfB drink interest2 interest3 interest4personB0 1 1 1 1personB1 1 1 1 2personB2 2 3 2 2personB3 8 6 8 8>>> print("Distances\n\n", distances, "\n\nIndices\n\n", indices)Distances [[0. ] [0.125] [1.125] [0.5 ]] Indices [[0] [0] [1] [3]]
从输出结果来看,personB0的最佳匹配是personA0(距离 = 0)。然而,personB1的最佳匹配也是personA0(距离 = 0.125)!
我想找到一种方法,将personB0与personA0匹配(因为它们的距离最小),然后将它们移到另一个表中,再次运行K-邻居算法,希望现在建议personB1的最佳匹配是personA1(因为A0已经被移除)。我已经开始编写一个for循环来迭代这个过程,但是对我来说这相当复杂(需要迭代多个不同的数组、数据框等),所以我想知道最好的方法是什么?我想要一个像下面这样的最终数据框,具有1:1的对应关系:
SetA SetBpersonA0 personB0personA1 personB1personA2 personB3personA3 personB2
回答:
你可以使用一个列表来检查一个人是否已经被匹配。此外,你需要获取按距离排序的邻居列表,而不是通过更改传递给参数n_neighbors
的值来获取最近的邻居。
knn = NearestNeighbors(n_neighbors=len(dfB)).fit(dfB)distances, indices = knn.kneighbors(dfA)matched = []pairs = []for indexA, candidatesB in enumerate(indices): personA = dfA.index[indexA] for indexB in candidatesB: if indexB not in matched: matched.append(indexB) personB = dfB.index[indexB] pairs.append([personA, personB]) breakmatches = pd.DataFrame(pairs, columns=['SetA', 'SetB'])
生成的数据框如下所示:
SetA SetB0 personA0 personB01 personA1 personB12 personA2 personB23 personA3 personB3
请注意,我使用了默认的度量标准(minkowski,p=2)。如果您将metric=my_dist
传递给NearestNeighbors
,结果可能会有所不同。