更简单的方法已在问题的最后更新。
我有一个名为matrixcorr_of_user
的用户 - 用户相关矩阵,如下所示:
userId 316 320 359 370 910
userId
316 1.000000 0.202133 0.208618 0.176050 0.174035
320 0.202133 1.000000 0.242837 0.019035 0.031737
359 0.208618 0.242837 1.000000 0.357620 0.175914
370 0.176050 0.019035 0.357620 1.000000 0.317371
910 0.174035 0.031737 0.175914 0.317371 1.000000
对于每个用户,我只想保留与他最相似的2个其他用户(排除对角线元素后每行的最高相关值)。像这样:
Out[40]:
userId 316 320 359 370 910
corr_user
316 NaN 0.202133 0.208618 NaN NaN
320 0.202133 NaN 0.242837 NaN NaN
359 NaN 0.242837 NaN 0.357620 NaN
370 NaN NaN 0.357620 NaN 0.317371
910 NaN NaN 0.175914 0.317371 NaN
我知道如何实现它,但我提出的方式太复杂了。 任何人都可以提供更好的主意吗?
我首先melt
矩阵:
melted_corr = corr_of_user.reset_index().melt(id_vars ="userId",var_name="corr_user")
melted_corr.head()
Out[23]:
userId corr_user value
0 316 316 1.000000
1 320 316 0.202133
2 359 316 0.208618
3 370 316 0.176050
4 910 316 0.174035
filter
一行一行:
get_secend_third = lambda x : x.sort_values(ascending =False).iloc[1:3]
filted= melted_corr.set_index("userId").groupby("corr_user")["value"].apply(get_secend_third)
filted
Out[39]:
corr_user userId
316 359 0.208618
320 0.202133
320 359 0.242837
316 0.202133
359 370 0.357620
320 0.242837
370 359 0.357620
910 0.317371
910 370 0.317371
359 0.175914
最后reshape
:
filted.reset_index().pivot_table("value","corr_user","userId")
Out[40]:
userId 316 320 359 370 910
corr_user
316 NaN 0.202133 0.208618 NaN NaN
320 0.202133 NaN 0.242837 NaN NaN
359 NaN 0.242837 NaN 0.357620 NaN
370 NaN NaN 0.357620 NaN 0.317371
910 NaN NaN 0.175914 0.317371 NaN
在看到@John Zwinck的答案
之后,我想出了一个更简单的方法我们假设有一个新的矩阵df
,其中包含一些重复的值NaN
userId 316 320 359 370 910
userId
316 1.0 0.500000 0.500000 0.500000 NaN
320 0.5 1.000000 0.242837 0.019035 0.031737
359 0.5 0.242837 1.000000 0.357620 0.175914
370 0.5 0.019035 0.357620 1.000000 0.317371
910 NaN 0.031737 0.175914 0.317371 1.000000
首先我得到每一行的rank
。
rank = df.rank(1, ascending=False, method="first")
然后我使用df.isin()
来获取我想要的面具。
mask = rank.isin(list(range(2,4)))
最后
df.where(mask)
然后我想要我想要的。
userId 316 320 359 370 910
userId
316 NaN 0.5 0.500000 NaN NaN
320 0.5 NaN 0.242837 NaN NaN
359 0.5 NaN NaN 0.357620 NaN
370 0.5 NaN 0.357620 NaN NaN
910 NaN NaN 0.175914 0.317371 NaN
答案 0 :(得分:4)
首先,使用np.argsort()
查找哪些位置具有最高值:
sort = np.argsort(df)
这给出了一个DataFrame,其列名无意义,但右边的第二列和第三列包含每行中的所需索引:
316 320 359 370 910
userId
316 4 3 1 2 0
320 3 4 0 2 1
359 4 0 1 3 2
370 1 0 4 2 3
910 1 0 2 3 4
接下来,构造一个布尔掩码,在上述位置设置为true:
mask = np.zeros(df.shape, bool)
rows = np.arange(len(df))
mask[rows, sort.iloc[:,-2]] = True
mask[rows, sort.iloc[:,-3]] = True
现在你有了所需的面具:
array([[False, True, True, False, False],
[ True, False, True, False, False],
[False, True, False, True, False],
[False, False, True, False, True],
[False, False, True, True, False]], dtype=bool)
最后,df.where(mask)
:
316 320 359 370 910
userId
316 NaN 0.202133 0.208618 NaN NaN
320 0.202133 NaN 0.242837 NaN NaN
359 NaN 0.242837 NaN 0.357620 NaN
370 NaN NaN 0.357620 NaN 0.317371
910 NaN NaN 0.175914 0.317371 NaN
答案 1 :(得分:1)
这应该有效:
melted_corr['group_rank']=melted_corr.groupby('userId')['value']\
.rank(ascending=False)
然后选择每个用户的前2名:
melted_corr[melted_corr.group_rank<=2]
答案 2 :(得分:1)
这是我的numpy-esque解决方案:
top_k = 3
top_corr = corr_of_user.copy()
top_ndarray = top_corr.values
np.fill_diagonal(top_ndarray, np.NaN)
rows = np.arange(top_corr.shape[0])[:, np.newaxis]
columns = top_ndarray.argsort()[:, :-top_k]
top_ndarray[rows, columns] = np.NaN
top_corr
我们得到了
userId 316 320 359 370 910
userId
316 NaN 0.202133 0.208618 NaN NaN
320 0.202133 NaN 0.242837 NaN NaN
359 NaN 0.242837 NaN 0.357620 NaN
370 NaN NaN 0.357620 NaN 0.317371
910 NaN NaN 0.175914 0.317371 NaN
如果您不想要副本,而是使用就地解决方案,则可以将top_corr = corr_of_user.copy()
替换为top_corr = corr_of_user
。
这些想法与John Zwinck的想法几乎相同 - 获取必要字段的索引并使用它来索引数组并清除我们不需要的值。我的解决方案的一个小优点是K(我们想要的顶级结果的数量)是一个参数而不是硬编码。当corr_of_user
包含所有1
时,它也有效。