处理词袋或 one-hot 特征时,列数很大不一定意味着当前矩阵已占用同样大的内存。CSR 只保存非零项、对应列号和每行的起点;转成普通二维数组后,每个位置都要分配存储。先核对两种表示的体积,再决定是否转换,可以避免一次 toarray() 把进程的内存耗尽。
本教程适合已经拿到 SciPy 稀疏特征矩阵、想估算转稠密风险的读者。示例在 Python 3.11、NumPy 2.4.6、SciPy 1.17.1 上运行。使用人工构造的大形状、少非零项矩阵,未加载真实业务数据,也没有实际分配估算中的 40 GB。

先安装,再运行估算脚本
在可写工作目录创建并激活虚拟环境,安装指定版本,保存下面代码为 check_sparse.py,然后运行 python check_sparse.py。macOS/Linux 的激活命令为 source .venv/bin/activate。
python -m venv .venv
.venv\Scripts\activate
python -m pip install numpy==2.4.6 scipy==1.17.1
SciPy CSR 文档给出了 data、indices、indptr 的含义。三组数组的 nbytes 相加是底层存储估算,不包含 Python 对象、分配器及其它临时副本。
import numpy as np
from scipy.sparse import csr_matrix
X = csr_matrix((np.array([1, 2, 3, 4, 5], dtype=np.float32),
([0, 1, 2, 3, 4], [10, 200, 3000, 40000, 99999])),
shape=(100_000, 100_000))
X.sum_duplicates()
X.eliminate_zeros()
stored = X.data.nbytes + X.indices.nbytes + X.indptr.nbytes
dense = int(X.shape[0]) * int(X.shape[1]) * X.dtype.itemsize
print('shape:', X.shape, 'nnz:', X.nnz, 'dtype:', X.dtype)
print('CSR arrays bytes:', stored)
print('dense estimated bytes:', dense)
limit = 512 * 1024**2
if dense > limit:
print('skip full toarray: exceeds 512 MiB budget')
else:
print(X.toarray())
small = X[:5, :12].toarray()
print('small slice shape:', small.shape, 'sum:', float(small.sum()))
assert X.nnz == 5 and small.shape == (5, 12) and small.sum() == 1
这几个数字分别表示什么
| 检查项 | 本地示例输出 | 含义 |
|---|---|---|
| shape | (100000, 100000) | 十万行、十万列 |
| nnz | 5 | 规范化后实际存储五个非零元素 |
| CSR arrays bytes | 400044 | 约391 KiB,包含十万行的行指针 |
| dense estimated bytes | 40000000000 | 40 GB,约37.25 GiB,尚未分配 |
核验时应看到 skip full toarray,而不是一大块二维数组;最后的小片段形状应为 (5, 12),元素和为 1.0。这说明脚本只把一小段转成普通数组。换环境后索引的数据类型可能变化,CSR 的具体字节数也可能变化,应以本机数组的 nbytes 为准。
换成真实训练特征时怎样操作
保留原矩阵,把脚本创建 X 的部分替换为已经生成的稀疏特征。先执行类型检查,确认是支持上述属性的 CSR 表示;若原来是其它稀疏格式,可用 X = X.tocsr(),但转换本身也可能需要额外内存。不要在已有内存压力时先转换再调查。
公式是“行数 × 列数 × 每个元素字节数”。将维度先转为 Python int,可减少定长整数相乘溢出的风险。512 MiB 是本例的保守演示阈值,不是所有电脑都合适的安全线;即便低于阈值,模型训练及转换临时副本仍会使用更多内存。优先选择能直接接受稀疏输入的算法,并检查具体求解器的要求。
toarray 文档说明结果是稠密 ndarray。只为了查看数据时可切小片段,不能为了打印几个值就转换整张特征表。
常见疑问:为什么全零矩阵仍有占用
CSR 仍需要保存每行的起点,indptr 长度与行数相关。nnz 还可能包含显式存进去的零;本例先合并重复坐标,再删除显式零,以免把存储项数误读成数学意义上的非零数。这里估算的是输入矩阵,不包括训练模型参数或 GPU 显存。
Ai菜鸟网。发布者:AI小管家,转载请注明出处:https://www.alyyhw.com/30821.html