如何从Python字典创建物品-特征稀疏二进制矩阵及索引错误排查
问题解决:创建推荐系统物品-特征稀疏矩阵时的索引越界错误
问题场景
有一个.tsv文件,已生成Python字典movie_features_dict,键为movie_id,值为对应电影的特征列表(每部电影特征数量不同)。目标是构建二进制稀疏矩阵,电影拥有某特征时对应位置为1,但运行代码时报错:
raise IndexError('index (%d) out of range' % max_indx) IndexError: index (614734) out of range
原代码如下:
创建字典
def Dictionary(): d={} l=[] with open(filepath_mapping) as f: for line in f.readlines(): line = line.split() key = int(line[0]) value = [int(el) for el in line[1:]] d[key] = value return(d) movie_features_dict = Dictionary()
原矩阵构建代码
n = len(movie_features_dict) value_lengths = [len(v) for v in movie_features_dict.values()] d = max(value_lengths) print(f"ITEM*FEATURES matrix shape: {n,d}\n") item_feature_matrix = sp.dok_matrix((n,d), dtype=np.int8) for movie_ids, features in movie_features_dict.items(): item_feature_matrix[movie_ids, features] = 1 item_feature_matrix = item_feature_matrix.tocsr() print(item_feature_matrix.shape)
错误原因
- 特征索引误用:你把特征的原始ID当成了矩阵的列索引,但特征ID的数值(比如报错里的614734)远大于单部电影的最大特征数量885,矩阵列数只设为885,自然会越界。矩阵列数应该基于所有特征ID的范围,而非单部电影的特征数量最大值。
- 行索引问题:原始
movie_id可能不是从0开始的连续整数,直接用movie_id作为行索引的话,若movie_id大于矩阵行数22069,也会触发索引越界。
修复方案
步骤1:映射movie_id到连续行索引
创建字典将每个原始movie_id映射到0~n-1的连续索引,避免行索引越界。
步骤2:确定所有特征的范围或映射特征ID到列索引
要么直接用所有特征ID的最大值+1作为列数,要么对特征ID做连续映射(推荐,若特征ID不连续可节省空间)。
步骤3:重构稀疏矩阵
用映射后的索引填充矩阵。
完整修复代码
import numpy as np import scipy.sparse as sp def Dictionary(): d={} with open(filepath_mapping) as f: for line in f.readlines(): line = line.split() key = int(line[0]) value = [int(el) for el in line[1:]] d[key] = value return d movie_features_dict = Dictionary() # 映射movie_id到连续行索引 movie_ids = list(movie_features_dict.keys()) movie_to_idx = {mid: idx for idx, mid in enumerate(movie_ids)} n_rows = len(movie_to_idx) # 收集所有特征ID并映射到连续列索引 all_features = [] for features in movie_features_dict.values(): all_features.extend(features) unique_features = list(set(all_features)) feature_to_idx = {fid: idx for idx, fid in enumerate(unique_features)} n_cols = len(feature_to_idx) # 构建稀疏矩阵 item_feature_matrix = sp.dok_matrix((n_rows, n_cols), dtype=np.int8) for mid, features in movie_features_dict.items(): row_idx = movie_to_idx[mid] for fid in features: col_idx = feature_to_idx[fid] item_feature_matrix[row_idx, col_idx] = 1 item_feature_matrix = item_feature_matrix.tocsr() print(f"修复后矩阵形状: {item_feature_matrix.shape}")
补充说明
- 如果特征ID本身是连续的(从0开始),可以跳过特征映射,直接用
max(all_features)+1作为n_cols,简化代码。 - 使用
dok_matrix适合逐元素赋值,最后转成csr_matrix方便后续推荐系统的矩阵运算。
内容的提问来源于stack exchange,提问作者Pybubb
相关产品推荐
相关产品推荐

