csr_matrix通过仅存储非零值、行偏移和列索引,内存占用可降至稠密矩阵的1%–5%,但不支持按列切片或直接赋值;scikit-learn多数模型原生支持,但StandardScaler等预处理器会静默转为dense导致OOM。

csr_matrix 为什么比 dense array 节省内存
稀疏矩阵里大量是 0,存满阵列纯属浪费。用 csr_matrix 只存非零值 + 行偏移 + 列索引,内存占用常能压到原来的 1%–5%。但代价是:某些操作(比如按列切片、频繁修改单个元素)会变慢甚至报错。
- 适合场景:
fit()和predict()阶段的特征矩阵(如 TF-IDF、one-hot 编码后),尤其是样本多、特征维数高、0 占比 >90% - 不推荐场景:需要反复
X[:, j]取列、或在训练中动态增删特征 - 注意:
csr_matrix是只读友好的,X[0, 0] = 1会触发NotImplementedError
scikit-learn 模型是否原生支持 csr_matrix
绝大多数线性模型(LogisticRegression、Lasso)、树模型(RandomForestClassifier)和集成方法(GradientBoostingClassifier)都直接接受 csr_matrix 输入,无需转换。但部分预处理器(如 StandardScaler)默认不支持,会静默转成 dense —— 这就是内存暴增的元凶。
- 安全用法:
LogisticRegression().fit(X_csr, y)✅;RandomForestClassifier().fit(X_csr, y)✅ - 危险操作:
StandardScaler().fit_transform(X_csr)❌(返回 dense);改用MaxAbsScaler或手动跳过归一化 - 验证方式:训练后检查
model.coef_.ndim或model.feature_importances_类型,避免中间被转密
如何安全地把 pandas DataFrame 转成 csr_matrix
别用 df.values,它强制生成 dense array;也别用 scipy.sparse.csr_matrix(df),它可能因 dtype 不一致出错。正确路径是先确保数值列、再走 sparse 构造器。
- 步骤:过滤非数值列 →
df.select_dtypes(include=['number'])→scipy.sparse.csr_matrix(df.astype(np.float64).values) - 更稳做法:用
sklearn.preprocessing.OneHotEncoder(sparse_threshold=1.0),它输出就是csr_matrix - 常见坑:
df含 object 列或 NaN 会卡在.values;先df.fillna(0).astype(np.float64)再转
fit 时 OOM 了,光换 csr_matrix 不够怎么办
csr_matrix 解决的是存储冗余,不是算法复杂度。如果模型本身要构造稠密 Gram 矩阵(比如 SVC(kernel='rbf')),或者 batch 太大(SGDClassifier 默认 max_iter=1000),照样爆内存。
- 优先降维:
TruncatedSVD(n_components=1000)(专为 sparse 设计) - 换轻量模型:
SGDClassifier比LogisticRegression(solver='lbfgs')更省内存 - 控制迭代:
SGDClassifier(max_iter=10, tol=1e-3)避免过拟合式长训 - 检查泄漏:
gc.collect()后看sys.getsizeof(X_csr),确认没意外 hold 住 dense 副本
真正卡住的地方往往不是矩阵格式本身,而是某个预处理步骤悄悄把它打回原形,或者模型选型根本没考虑稀疏性约束。

















