复杂逻辑下向量化DataFrame过滤:余弦相似度矩阵指定位置置为np.nan
问题需求
现有一个包含ID列与四个数值列(数值为0至50的整数)的大型DataFrame,需要按ID分组计算余弦相似度矩阵,并对矩阵中满足以下规则的元素设为np.nan:
- 同一ID分组内,若行1在四个维度上均不劣于行2,且至少有一个维度更优,则矩阵中
[1,2]与[2,1]位置的元素需置为np.nan。
示例DataFrame
a b c d ID 9 9 7 3 1 9 8 3 2 1 6 5 5 6 1 8 4 7 5 1 4 8 7 2 1 4 6 9 5 1 7 4 3 1 1 5 3 5 2 1 8 9 3 9 1 8 2 7 9 1 6 4 1 1 2 3 9 9 3 2 7 6 7 7 2 7 4 9 3 2 2 5 9 2 2 7 6 2 3 2 5 8 7 5 2 6 9 4 1 3 1 6 8 6 3 1 9 7 6 3 2 8 5 4 3 7 2 5 1 3 9 6 5 3 3 8 2 3 2 3 1 8 2 9 3 1 8 1 6 3 3 6 2 4 3 4 2 9 7 3 9 2 6 8 3 1 2 6 3 3
已实现的筛选逻辑
已编写函数筛选符合规则的行索引,代码如下:
def filter_se(row, df, cols = None): if cols: df = df[cols] row = row[cols] # 筛选所有列都不劣于当前行的记录 df = df[(row >= df).all(axis = 1)] # 筛选至少有一列更优的记录 df = df[(row > df).any(axis = 1)] indexes = df.index.tolist() return indexes sample_group = sample.groupby("ID") r = {} for index, group in sample_group: res = group.apply(filter_se, args = [group, ["a", "b", "c", "d"]], axis = 1).tolist() r[index] = res
筛选结果输出
{1: [[1, 4, 6, 7], [6], [7], [6, 7], [], [], [], [], [6], []], 2: [[], [14], [10, 15], [10], [], [10], []], 3: [[], [29], [25, 29], [], [], [21, 23], [], [25], [], [], [29], [21, 23, 29], []]}
余弦相似度矩阵计算
已通过以下代码计算各ID对应的余弦相似度矩阵,得到以ID为索引、相似度矩阵为值的pd.Series对象:
from sklearn.metrics.pairwise import cosine_similarity sims = sample.groupby("ID").apply(lambda g: cosine_similarity(g[["a", "b", "c", "d"]]))
当前问题
无法将相似度矩阵中符合规则的指定位置元素置为np.nan,需要完成此操作。
解决方案
可以通过遍历每个ID对应的相似度矩阵和筛选结果,直接修改矩阵中的对应位置为np.nan,同时处理双向位置:
import numpy as np # 遍历每个ID的相似度矩阵和筛选结果 for id_val in r.keys(): sim_matrix = sims.loc[id_val] filter_list = r[id_val] n_rows = sim_matrix.shape[0] # 遍历每一行的索引和对应的需置nan的列索引 for i in range(n_rows): cols_to_nan = filter_list[i] # 将[i, col]和[col, i]位置设为nan for col in cols_to_nan: sim_matrix[i, col] = np.nan sim_matrix[col, i] = np.nan # 更新sims中的矩阵 sims.loc[id_val] = sim_matrix
解释
- 遍历每个ID,取出对应的相似度矩阵和筛选得到的索引列表
- 对每一行
i,获取所有需要置为np.nan的列索引cols_to_nan - 分别将矩阵的
[i, col]和[col, i]位置设为np.nan - 更新原
pd.Series中的矩阵
如果需要避免原地修改,可以先创建矩阵的副本再操作:
for id_val in r.keys(): sim_matrix = sims.loc[id_val].copy() filter_list = r[id_val] n_rows = sim_matrix.shape[0] for i in range(n_rows): cols_to_nan = filter_list[i] for col in cols_to_nan: sim_matrix[i, col] = np.nan sim_matrix[col, i] = np.nan sims.loc[id_val] = sim_matrix
内容的提问来源于stack exchange,提问作者Emil Mirzayev
相关产品推荐
相关产品推荐

