我有一个相似矩阵(构建为数据帧):
mat = pd.DataFrame(index = df.a.values,columns = df.a.values)
mat[:] = [[1,0.2,0.3],[0.7,1,0.6],[0,0.4,1]]
id1 id2 id3
id1 1.0 0.2 0.3
id2 0.7 1.0 0.6
id3 0.0 0.4 1.0
我想创建另一个包含相同索引但包含最近id
的列的数据框:
id closest
0 id1 id3
1 id2 id1
2 id3 id2
我们的想法是在相似度矩阵中寻找第二个最高值的每一行(第一个在对角线上始终为1),并检索相应列的名称。
我知道我可以将对角线设置为零,然后使用类似的东西:
def closest(x):
return np.where(x == x.max())
temp = mat.apply(lambda x: closest(x))
df['closest'] = df.index[[w[0][0] for w in temp.values]].tolist()
但我无法在不重新分配的情况下找到如何过滤对角线。
注意:矩阵中的值都在0到1之间,唯一的1在对角线上
答案 0 :(得分:2)
减去单位矩阵,然后使用DataFrame.idxmax()
查找每行中最大值的索引。
import numpy as np
import pandas as pd
index = ['id1', 'id2', 'id3']
mat = pd.DataFrame([[1, 0.2, 0.3],[0.7, 1, 0.6],[0, 0.4, 1]],
index=index, columns=index)
(mat - np.identity(3)).idxmax(axis=1)
输出:
id1 id3
id2 id1
id3 id2
dtype: object
答案 1 :(得分:1)
一种方法是通过减去相同顺序的单位矩阵来摆脱对角线1。如果你不想做任何重新分配或减去(我没有看到原因 - 可能是为了练习在Pandas中使用许多功能),我会建议这样的事情:
def closest(x):
return mat.loc[x['id']].nlargest(2).values.tolist()[1]
def closest_label(x):
return mat.loc[x['id']].nlargest(2).index[1]
df['closest'] = df.apply(closest, axis=1)
df['closest_label'] = df.apply(closest_label, axis=1)
输出:
id closest closest_label
0 id1 0.3 id3
1 id2 0.7 id1
2 id3 0.4 id2