我叫沈砚,做数据工程已经第 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 商品 的点击次数矩阵

从零到实战的数据工程师,我是如何用 numpy创建矩阵 撑起整套分析管线的

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.arraynp.zerosnp.onesnp.eye 等方式来创建矩阵,完全跳过 np.matrix

用 numpy创建矩阵,其实是在设计你的数据“入口”

很多人以为“创建矩阵”只是一个 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.zerosnp.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.stacknp.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 创建矩阵 这件看起来微不足道的小事,其实刚好符合这种标准:

  • 它暴露了你对数据形状的理解是不是清晰;
  • 它体现了你对内存和算力的基本尊重;
  • 它会默默影响你团队里模型效果的稳定性。

如果你刚入门数据分析、机器学习,我会真心建议你,从今天开始做两件小而实在的事:

  1. 每次创建矩阵,先在脑子里,或者注释里,把“这几维分别是什么”写清楚,再敲代码。
  2. 在项目里,多看一眼自己的 dtype、形状、是否稀疏,别被默认值牵着走。

等你习惯了这种方式,某一天再回头看自己的代码,你会明显感觉到一种“专业感”:不是用了多少高深的库,而是每一个 numpy 创建矩阵的地方,都干净、清晰、可靠。

如果你在某个业务场景里,对矩阵的形状设计还有疑惑,可以直接把场景和大致的数据规模抛出来,我也乐意用一个真正做了几年这一行的人的眼光,帮你一起拆一拆。