如何对行列数不同的scipy.sparse稀疏矩阵实现类外连接合并?
问题描述
我有多个scipy.sparse.csr_matrix类型的稀疏矩阵,这些矩阵是按user_id分组后,用CountVectorizer处理文本生成的,所有矩阵的行数总和等于原数据集data的行数。现在需要把它们合并成一个形状为(总行数, 所有矩阵列数之和)的矩阵——即把所有行拼接起来,同时每个矩阵的行在其他矩阵的列位置补0(类似外连接效果)。但由于各矩阵的行、列数均不相同,无法直接使用vstack或hstack方法,寻求解决方案。
原生成矩阵的代码如下:
import pandas as pd from sklearn.feature_extraction.text import CountVectorizer from local_utils import get_data def _count_words_within_userid(x): model = CountVectorizer(min_df=1, ngram_range=(1, 2), binary=True) transformed_data = model.fit_transform(x) return transformed_data data = get_data() user_models_and_data = data.groupby("user_id")["text"].apply(_count_words_within_userid)
矩阵合并效果示例:
m1 = [[0,0,1], [0,1,0]] m2 = [[0,1], [1,1], [1,0]] result = some_function((m1,m2)) # 前3列来自m1,后2列来自m2。 # m2的行拼接到m1的行之后,在m1的列位置填充0; # m1的行在m2的列位置填充0,最终形状为`(m1.rows+m2.rows, m1.columns+m2.columns)` print(result) # [[0,0,1,0,0], # [0,1,0,0,0], # [0,0,0,0,1], # [0,0,0,1,1], # [0,0,0,1,0] # ]
解决方案
核心思路:先给每个稀疏矩阵补全对应其他矩阵列数的0列,让所有矩阵的列数统一为总列数,再垂直拼接所有矩阵。
步骤实现
- 提取所有稀疏矩阵,统计总列数
- 对每个矩阵,拼接原矩阵和对应行数的0矩阵(补全剩余列数)
- 垂直拼接所有处理后的矩阵,得到最终结果
完整代码如下:
import pandas as pd from sklearn.feature_extraction.text import CountVectorizer from scipy.sparse import csr_matrix, hstack, vstack from local_utils import get_data def _count_words_within_userid(x): model = CountVectorizer(min_df=1, ngram_range=(1, 2), binary=True) transformed_data = model.fit_transform(x) return transformed_data data = get_data() user_models_and_data = data.groupby("user_id")["text"].apply(_count_words_within_userid) # 提取所有稀疏矩阵 sparse_matrices = list(user_models_and_data.values) # 计算所有矩阵的总列数 total_cols = sum(mat.shape[1] for mat in sparse_matrices) # 处理每个矩阵,补全0列 processed_matrices = [] for mat in sparse_matrices: mat_rows, mat_cols = mat.shape # 需要补充的0列数 zero_col_count = total_cols - mat_cols # 创建对应行数的稀疏0矩阵 zero_mat = csr_matrix((mat_rows, zero_col_count), dtype=mat.dtype) # 水平拼接原矩阵和0矩阵,得到列数统一的矩阵 processed_mat = hstack([mat, zero_mat]) processed_matrices.append(processed_mat) # 垂直拼接所有处理后的矩阵,得到最终结果 final_matrix = vstack(processed_matrices) # 验证示例(可选) def test_merge_example(): m1 = csr_matrix([[0,0,1], [0,1,0]]) m2 = csr_matrix([[0,1], [1,1], [1,0]]) test_matrices = [m1, m2] test_total_cols = sum(m.shape[1] for m in test_matrices) test_processed = [] for m in test_matrices: zero_mat = csr_matrix((m.shape[0], test_total_cols - m.shape[1]), dtype=m.dtype) test_processed.append(hstack([m, zero_mat])) result = vstack(test_processed) print(result.toarray()) # 运行测试 test_merge_example()
说明
- 采用稀疏矩阵操作,补0过程不会占用额外内存,适合处理大规模文本数据
- 保持所有矩阵的数据类型一致,避免拼接时出现类型错误
- 最终矩阵的行数为所有输入矩阵行数之和,列数为所有输入矩阵列数之和,完全符合需求
内容的提问来源于stack exchange,提问作者CutePoison
相关产品推荐
相关产品推荐

