我叫沈砚,做数据工程已经第 9 个年头了,现在在一家垂直电商平台负责推荐与风控数据底座。每天睁眼,面对的就是一堆矩阵——用户行为矩阵、商品特征矩阵、Embedding 矩阵,有的能直接丢进模型,有的得被“折腾”几轮才能派上用场。
说得直白点:如果你准备认真做数据分析、机器学习建模,甚至只是想把 Excel 弄不动的表算清楚,numpy 创建矩阵这件小事,会悄悄决定你后面是不是一路顺畅。
这篇文章我不准备讲那些“教科书式”的定义,而是站在一个一线数据工程师的视角,把我日常在生产环境里用 numpy 创建和管理矩阵的经验摊开,帮你解决三个核心痛点:
- 到底该用
array还是“矩阵”?怎么创建才不踩坑? - 热门场景下(推荐、AB 测试、广告投放)业内都怎么高效创建矩阵?
- 面对百万级别的数据,怎样让
numpy既快又省内存,而不是把电脑搞崩?
2026 年,看似大家都在聊大模型、向量数据库,但底层的数据还是要落回到一个个矩阵上。你用矩阵的姿势,对不对,很快就会体现在算力账单和模型效果里。
刚入行那会儿,我写 numpy 创建矩阵,最爱干的一件事就是在代码里疯狂 reshape —— 结果就是自己都看不懂代码,更别提同事。后来换了公司,Leader 只给我提了一个要求:“你创建矩阵的时候,先把形状想清楚。”
听起来有点鸡汤,但落实到代码,是一些非常实际的小细节:
- 用户画像做推荐:我们一般会建一个
user_item的交互矩阵,行是用户、列是商品,典型形状num_users x num_items。 - Embedding 表:假设我们用 128 维的向量表示用户,那就是
num_users x 128的矩阵。 - AB 实验指标矩阵:
num_experiments x num_metrics,每行一个实验,每列一个核心指标。
在创建矩阵时,我现在习惯先在注释里写清楚形状的“含义”:
# 用户 x 商品 的点击次数矩阵
user_item_matrix = np.zeros((num_users, num_items), dtype=np.int32)看似只是多写一行注释,却解决了一个常见痛点:团队协作时,谁都不会再问“这个第一维到底是用户还是商品”。
很多人问我:“到底要不要用 numpy.matrix?”我的经验是:在 2026 年的项目里,几乎没人再用 numpy.matrix 类型。主流做法是统一用 ndarray,好处很简单:
- 生态兼容:机器学习框架(scikit-learn、PyTorch、TensorFlow)、向量数据库、特征平台,清一色都对
ndarray友好。 - 行为更直观:
ndarray的乘法要么是*做逐元素,要么是@做矩阵乘法,不会和老式matrix混起来。
所以我现在在团队里定得规矩是:只教新人用 np.array、np.zeros、np.ones、np.eye 等方式来创建矩阵,完全跳过 np.matrix。
很多人以为“创建矩阵”只是一个 np.array([...]) 的语法问题,实际真正拉开水平差距的是你怎么从真实业务数据,平滑落地到 numpy 矩阵。
在我们推荐系统里,一个标准链路大概是这样:
- 日志平台每天落 20TB 左右原始行为数据(2026 年初我们在内部做过统计,日活 6000 万的规模)。
- 经过 Flink 清洗,落到特征仓里,大概缩到几百 GB。
- 取其中一部分特征,拉回 Python 环境,用
numpy做特征工程、实验验证。
“创建矩阵”的动作就变得非常关键:它决定了你从离线数仓到本地实验环境的成本。
几个日常用得很多、却容易被忽略的技巧:
import numpy as np# 从列表创建:适合小规模数据或快速试验clicks = [[1, 0, 3], [0, 2, 1]]click_matrix = np.array(clicks, dtype=np.int16)# 从文件批量创建:适合导出的 CSV 或 TSVdata = np.loadtxt("user_item_sample.tsv", delimiter="t", dtype=np.float32)# 预分配再填充:适合你已经知道规模的情况下num_users, num_items = 100000, 5000user_item = np.zeros((num_users, num_items), dtype=np.uint8)# 后面用索引逐步填充预分配矩阵这一点,我在一个广告投放项目里感受特别深。那次我们要做上亿条曝光日志的 CTR 估计,如果用“不断 append” 的写法,内存翻倍很容易;换成预先用 np.zeros 或 np.empty 创建好矩阵,按行填数据,单机内存直接从 64GB 打到 32GB 左右就可以跑完,同一批数据快了接近 40%。
从工程视角看,“怎么创建矩阵”,就是“怎么把数据稳稳落在内存里”。如果你已经心里有底,大概会有多少行多少列,那就不要怕麻烦,用预分配的方式;代价只是一行代码,多的是算力账单上的节省。
说一个很真实的数据:我们现在线上推荐里用到的用户-商品交互矩阵,稀疏度基本都在 99.5% 以上,也就是 100 个格子,只有不到 1 个有值。这种情况下,如果你用普通 numpy 稠密矩阵去存,全是浪费。
日常工作中,我的做法是这样的:
- 在特征抽取阶段,用
scipy.sparse来存大矩阵,只在某些需要 dense 的操作里,才转换成numpy。 - 把矩阵创建这件事拆成两层:
- 业务层:决定哪些特征进矩阵。
- 工程层:决定稀疏还是稠密,用哪种数据类型。
对稠密矩阵,我会用类似这样的方式去控制:
# 用户 embedding:float32 足够,很多人默认 float64 只是浪费user_embedding = np.random.randn(num_users, 128).astype(np.float32)# 指标矩阵:比如 AB 实验的转化率,可以用 float32,统计量则用 float64metrics = np.zeros((num_experiments, num_metrics), dtype=np.float32)对稀疏矩阵,一个常见搭配是这样的:
from scipy import sparse# 先用三元组形式收集数据rows, cols, values = [], [], []# 遍历日志,填充 rows/cols/values# ...interaction_sparse = sparse.coo_matrix( (values, (rows, cols)), shape=(num_users, num_items), dtype=np.float32)这和“numpy 创建矩阵”有什么关系?很直接——你在一开始选择了稠密矩阵或稀疏矩阵,就已经决定了能不能在一台机器上跑完任务。
我们在 2026 年春节档营销项目里有一个典型场景:用户数约 4500 万,候选商品池约 30 万。如果你暴力建一个稠密用户-商品矩阵,那就是 4.5e7 × 3e5,根本没法装进内存。实际做法是只保留有过行为的三元组,然后用稀疏矩阵加上分布式存储,最后抽样一部分转换成 numpy 稠密矩阵做实验。
结论很朴素:别把 numpy 当成万能仓库,它是你的“工作台”,真正的仓库应该在数仓、向量数据库或稀疏存储系统里。
做推荐和广告建模时,有一个经常被问到的问题:“为什么线上模型和线下复现时,效果总对不上?”
在我们工程团队的排查经验里,有一部分问题就出在矩阵创建的“节奏”不一致上:线上某些特征是实时拼的,顺序、缺失值填充策略、归一化方式都很稳定;线下有人随手写一个 np.array([...]) 或 np.concatenate,就已经偏了。
我现在会刻意在矩阵创建时,遵守几个“看似唠叨”的约定:
- 对每个特征块,用固定顺序创建矩阵列,写清楚“列的含义”。
- 对缺失值,统一约定填什么,比如浮点型特征填
0.0,类别型用-1。 - 用
np.stack、np.concatenate的地方,配一个简单的维度断言。
# 比如对三个特征块,统一 stack 成训练矩阵feat_block_1 = np.array(block_1, dtype=np.float32) # shape: (N, 16)feat_block_2 = np.array(block_2, dtype=np.float32) # shape: (N, 32)feat_block_3 = np.array(block_3, dtype=np.float32) # shape: (N, 8)assert feat_block_1.shape[0] == feat_block_2.shape[0] == feat_block_3.shape[0]X = np.concatenate([feat_block_1, feat_block_2, feat_block_3], axis=1)# X.shape = (N, 56)这点在 2025 年底我们接入一个 new user 冷启动模型时,救过我们一次。当时线上 CTR 相比线下 benchmark 差了将近 7% 相对值,排查了两天,最后发现是线下矩阵创建时有一列归一化特征顺序对错了;如果一开始我们就给矩阵列严格“起名字”“定顺序”,这类问题通常不会发生。
矩阵不是静态的数据,它代表的是一整套生成流程。你怎么创建它,决定了这套流程是不是可复现。
做了这么多年数据工程,我越来越不信“语法层面的炫技”,更关心的是:一段代码,能不能被别人接手,能不能撑得住真实的业务量,能不能在一年后回头看还说得通。
用 numpy 创建矩阵 这件看起来微不足道的小事,其实刚好符合这种标准:
- 它暴露了你对数据形状的理解是不是清晰;
- 它体现了你对内存和算力的基本尊重;
- 它会默默影响你团队里模型效果的稳定性。
如果你刚入门数据分析、机器学习,我会真心建议你,从今天开始做两件小而实在的事:
- 每次创建矩阵,先在脑子里,或者注释里,把“这几维分别是什么”写清楚,再敲代码。
- 在项目里,多看一眼自己的
dtype、形状、是否稀疏,别被默认值牵着走。
等你习惯了这种方式,某一天再回头看自己的代码,你会明显感觉到一种“专业感”:不是用了多少高深的库,而是每一个 numpy 创建矩阵的地方,都干净、清晰、可靠。
如果你在某个业务场景里,对矩阵的形状设计还有疑惑,可以直接把场景和大致的数据规模抛出来,我也乐意用一个真正做了几年这一行的人的眼光,帮你一起拆一拆。