如何在sklearn中获取多个节点的共同最近邻?
多节点共同最近邻实现方案(推荐系统场景)
问题核心
你需要为推荐系统实现同时接近多个选中电影节点的共同最近邻查找,但当前使用neigh.kneighbors(X)返回的是每个输入节点各自的最近邻(2x2数组),无法直接满足需求。
解决方案思路与代码示例
以下是三种实用的实现方法,基于scikit-learn的NearestNeighbors:
方法1:基于平均距离排序(最通用)
计算每个候选节点到所有输入节点的平均距离,取平均距离最小的前N个节点,确保结果同时接近所有输入节点。
from sklearn.neighbors import NearestNeighbors import numpy as np # 示例完整数据集(替换为你的实际电影特征数据) movie_data = np.array([ [0., 1., 0.], # 选中电影1(索引0) [1., 0., 1.], # 选中电影2(索引1) [0.5, 0.5, 0.5], # 候选电影A [0., 0., 1.], # 候选电影B [1., 1., 0.] # 候选电影C ]) # 初始化最近邻模型 neigh = NearestNeighbors(n_neighbors=len(movie_data)) neigh.fit(movie_data) # 用户选中的电影特征 selected_movies = np.array([[0., 1., 0.], [1., 0., 1.]]) # 获取选中电影在数据集里的索引(用于后续过滤自身) selected_indices = np.where((movie_data == selected_movies[:,None]).all(axis=2))[1] # 获取所有节点到每个选中电影的距离和索引 all_distances, all_indices = neigh.kneighbors(selected_movies, n_neighbors=len(movie_data)) # 计算每个候选节点的总距离,再求平均 total_dist = np.zeros(len(movie_data)) for dist_list, idx_list in zip(all_distances, all_indices): for dist, idx in zip(dist_list, idx_list): total_dist[idx] += dist avg_dist = total_dist / len(selected_movies) # 按平均距离排序,过滤掉选中的电影,取前2个共同最近邻 k = 2 sorted_candidates = np.argsort(avg_dist) common_neighbors = [idx for idx in sorted_candidates if idx not in selected_indices][:k] print("共同最近邻索引:", common_neighbors)
方法2:基于最近邻交集
先获取每个选中电影的最近邻集合,再取这些集合的交集,确保结果是所有选中电影的共同近邻,最后按距离排序。
# 每个选中电影取前3个最近邻 k_per_movie = 3 distances, indices = neigh.kneighbors(selected_movies, n_neighbors=k_per_movie) # 生成每个选中电影的最近邻集合(排除自身) neighbor_sets = [] for idx_list in indices: neighbor_set = set(idx for idx in idx_list if idx not in selected_indices) neighbor_sets.append(neighbor_set) # 求所有集合的交集 common_neighbor_set = set.intersection(*neighbor_sets) # 对交集内的节点按平均距离排序,取前k个 common_neighbors = sorted(common_neighbor_set, key=lambda x: avg_dist[x])[:k] print("共同最近邻索引(交集法):", common_neighbors)
方法3:基于平均特征向量
将所有选中电影的特征向量取平均值,用这个平均向量作为新的查询节点,查找最近邻,简化多节点查询为单节点查询。
# 计算选中电影的平均特征向量 avg_selected = np.mean(selected_movies, axis=0).reshape(1, -1) # 查询平均向量的最近邻(多取几个用于过滤自身) distances_avg, indices_avg = neigh.kneighbors(avg_selected, n_neighbors=k + len(selected_indices)) # 过滤选中的电影,取前k个 common_neighbors = [idx for idx in indices_avg[0] if idx not in selected_indices][:k] print("共同最近邻索引(平均向量法):", common_neighbors)
内容的提问来源于stack exchange,提问作者Shivang Khandelwal
相关产品推荐
相关产品推荐

