2026年了,做数据相关工作,要是还在 for 循环里一个个往列表里 append,再转成数组,那真是有点心疼你的时间。
我叫柳湛,在互联网数据团队里摸爬滚打第 8 年,白天写 Python、SQL、Spark,晚上给新人做内部培训。每一批新同事里,绕不过去的一个坑,就是:明明都在用 numpy,却总在“创建矩阵”这一步掉链子。
听起来只是一个小小的“numpy创建矩阵”操作,实际悄悄影响着你的代码可读性、运行速度,甚至是后面的模型效果和线上稳定性。很多诡异的 Bug,追到根上,就是:矩阵没搞对。
这篇,我就从一个一线数据人的视角,把“numpy创建矩阵”里那些看似细枝末节、实则扎在生产环境里的坑,摊开讲清楚。
新人常说一句话:“我这里就是一个简单矩阵。”

在 numpy 里,ndarray 才是主角,所谓“矩阵”,更多只是 “二维 ndarray”。工作里常见的矩阵来源,大概三种:
- 你自己造的:调试、写 demo、手工构建系数表
- 外部读进来的:CSV、Parquet、线上接口
- 算子运算产出的:特征工程、模型中间结果
最典型的一个小片段:
import numpy as npa = np.array([[1, 2, 3], [4, 5, 6]])这就是一个 2x3 的“矩阵”。没什么花哨。但问题在于,很多人不自觉写出这样的东西:
b = np.array([[1, 2], [3, 4, 5]])看上去像矩阵,其实是个“畸形二维结构”,dtype 变成 object,下游一连串报错、性能骤降,排查时十分抓狂。
在我们组里,我给新人定了个简单的小习惯:只要用 numpy创建矩阵,写完立刻 print(arr.shape, arr.dtype) 看一眼。尤其是:
- 形状带
None/ 不确定就要警惕 dtype=object,基本说明你创建矩阵的方式出问题了
这个 1 秒钟的小检查,在真实项目里,帮我们避掉过不少线上事故。
落到实操上,2026 年写 numpy,创建矩阵常用的手法大致就这几类,我在内部培训时会按“使用频率 + 踩坑概率”来讲。
1)从Python 列表出发:最常见也最容易埋雷
data = [[1, 2, 3], [4, 5, 6]]arr = np.array(data)优势:直观,好读,便于和业务同事沟通“行列含义”。风险点主要在两个:
- 子列表长度不一致 → 变
object,矩阵运算全跪 - 列表太大(10^7 级别) → 纯 Python 构建阶段就慢
在一个电商推荐项目里,我们一度用 Python 循环拼列表,用户行为矩阵一眼看去没问题,却慢得离谱。后来切成用 numpy 原生接口生成(np.zeros + 赋值),整条链路耗时从 40 多秒拉到 10 秒以内,QPS 直接顶上去了。
2)用“套路矩阵”:全0、全 1、单位阵
这类,是工业界里极常见的“初始化动作”。
zeros = np.zeros((1000, 300))ones = np.ones((64, 128))eye = np.eye(128) # 单位矩阵full = np.full((32, 32), fill_value=7)几个实际工作里的细节:
- 参数一定要写成
(行, 列),别写反日常排查“维度不对齐”的 Bug,有一半来自这里。 - dtype 在数值较大时,要有意识地指定,比如:
对内存压力比较敏感的线上服务,这个很关键。2026 年我们服务里普遍监控的是单机内存 32~64GB,但模型与向量一多,浪费一倍内存很容易把你推向 OOM 边缘。zeros = np.zeros((10000, 512), dtype=np.float32)
在我们一次风控模型迭代里,只是把默认 float64 改到 float32,服务内存峰值从 45GB 降到了 26GB,极端流量高峰时就不再需要紧急扩容。
3)用arange、linspace 这类“数列生成器”
这类更偏向“数据科学调参时的好帮手”。
np.arange(start, stop, step)等差序列np.linspace(start, stop, num)指定个数、均匀分布
矩阵就是加一个 .reshape():
grid = np.arange(12).reshape(3, 4)x = np.linspace(0, 1, 5) # [0. 0.25 0.5 0.75 1.]matrix = x.reshape(5, 1) # 切成 5x1 矩阵在真实项目里,linspace 常用来构造参数网格、时间刻度、插值点。比如我们在做 A/B 实验效果分析时,常需要按阈值扫描某个打分分布的表现,thresholds = np.linspace(0, 1, 101) 就比手写列表优雅得多。
一点小经验:arange 用浮点步长时会有精度问题,生产代码里更偏向 linspace。
4)“网格矩阵”:做可视化和二维特征时的隐形主力np.meshgrid 是我见到很多新人忽略的一个宝藏函数。
x = np.linspace(-1, 1, 5)y = np.linspace(-2, 2, 5)X, Y = np.meshgrid(x, y)这两个矩阵常被用于:
- 二维函数可视化(画等高线图、热力图)
- 构造二维特征组合(例如地理栅格、图像坐标)
2024–2026 年,各类 L2/L3 自动驾驶团队在做 BEV(鸟瞰图)特征构造时,大量使用类似的“栅格化”思想。网格矩阵,在那里只是换了个壳。
只要你认真工作,迟早会被“dtype 和 shape”的问题追着跑。每次有人问我:“numpy创建矩阵到底要注意啥?”我基本只会回这两个词。
关于dtype:别小看那个小小的 float32
现在很多公司线上部署模型时,都会有内存和延迟的 SLAs。举个我们这两年真实的体感:2026 年在国内主流云厂商的推理实例里,单核延迟 20ms 以内 已经算比较常见的指标。
在这个背景下,numpy 矩阵的 dtype 直接影响:
- 内存大小(float64 是 float32 的两倍)
- 运算速度(cache 命中率、向量化效率)
一些常见的“隐性坑”——
arr = np.array([1, 2, 3]) # int64arr_f = np.array([1., 2., 3.]) # float64arr32 = np.array([1., 2., 3.], dtype=np.float32)如果你上游是 float32 的 embedding,下游不小心用 int 或 float64 混了,numpy 会自动做类型提升,结果整个矩阵悄悄变肥。在我们一个向量检索项目里,线上监控发现 95% 分位延迟突然从 15ms 输到了 25ms,检查半天,发现有人在 numpy创建矩阵 时忘记加 dtype=np.float32,导致整个 pipeline 在关键一环变成了 float64。
后来我们团队内部的约定是:涉及向量 / 特征矩阵,一律默认 float32,创建时显式写出来。
关于shape:一维 vs 二维的“人格分裂”
numpy 有一个经典梗:一维数组和二维矩阵之间的暧昧关系。
v1 = np.array([1, 2, 3]) # shape: (3,)v2 = np.array([[1, 2, 3]]) # shape: (1, 3)v3 = np.array([[1], [2], [3]]) # shape: (3, 1)在数学上都是“3 个数字”,在 numpy 里完全是三种生物。尤其在以下场景里,区别非常敏感:
- 广播运算
- 矩阵乘法(
@、np.dot) - 与 sklearn / torch 等库的接口对接
2025 年我们在做一个 CTR 预估模型迁移时,因为 numpy创建矩阵 忽略了 batch 维,导致线上预测维度错位,AUC 一下掉了 0.03,被运营追着问“是不是模型退化了”。排查结果:只是训练时喂给模型的是 (batch_size, n_features),线上预估从日志里扒的数据是 (n_features,),没了 batch 维度。
我后来养成了一个小习惯:只要我要的东西是“矩阵”,那么在 numpy创建矩阵 时,坚持让 shape 里出现两个数字。哪怕是某个单样本:
x = np.array([features], dtype=np.float32) # shape: (1, n_features)这样一眼看过去,就知道自己处理的是“矩阵场景”。
在实际项目里,矩阵很少是凭空创建的。更多来自文件、数据库、消息队列。但无论入口是什么,落到本地计算时,还是绕不开“numpy创建矩阵”这一步。
这几年比较常见的几条路径:
CSV/ TSV:老牌但仍顽强
虽然 Parquet、Arrow 越来越多,但在很多业务协同场景里,运营同学发过来的仍然是 CSV。
简单读取:
data = np.loadtxt("data.csv", delimiter=",", skiprows=1)用过的都知道,loadtxt 在数据稍微“脏一点”时就不太抗造,所以我们更多会这样做:
import pandas as pddf = pd.read_csv("data.csv")matrix = df.to_numpy(dtype=np.float32)pandas 做清洗,numpy 做计算,这是 2026 年数据团队里非常主流的搭配。在一次营销投放效果复盘中,我们要分析 2025–2026 年某电商平台的转化数据,原始文件有缺失值、非法字符,用 pandas 先统一清洗,再转换成矩阵,整个流程稳定、不折腾。
Parquet/ Arrow:面向大数据的“矩阵前奏”
对于日均千万级别的日志数据,直接用 numpy 去读文件很不现实。我们常见的姿势是:
- 离线用 Spark / Flink 做预聚合
- 导出到 Parquet
- 进 Python 时用 pandas / pyarrow 读,再转 numpy
import pyarrow.parquet as pqtable = pq.read_table("features.parquet")matrix = table.to_pandas().to_numpy(dtype=np.float32)在一个风控场景里,我们每天会从 10 亿级别的原始日志中抽样 0.1%,做在线模型的“每日体检”。这 0.1% 大概是千万级,最后真正进 Python、转换成矩阵的样本,是清洗后几十万。numpy创建矩阵 在这里看似只是末端一步,却是整个链路的“定型动作”。
讲一点更贴近模型的东西。你怎么用 numpy创建矩阵,决定了模型看到的“世界长什么样”。
举个我们 2025 年在广告排序项目里遇到的真实场景:为了提升训练速度,有人把所有离散特征编码后,直接按“看到的顺序堆在一起”:
X = np.concatenate([x1, x2, x3], axis=1)表面上问题不大,可一旦有某个特征在某天缺失,就会悄悄导致矩阵列偏移。最后模型没学到“点击率随曝光频次变化”的规律,反而学到了一些莫名其妙的“组合噪声”。
后来我们重新梳理了一套规范:
- 用
numpy创建矩阵前,把每一列的含义写清楚 - 所有列按固定 schema 排列,缺失也要填位
- 统一用
np.zeros/np.full预先创建矩阵再填值,而不是临时拼接
类似的片段在真实代码里可能长这样:
num_samples = len(users)num_features = len(schema)X = np.zeros((num_samples, num_features), dtype=np.float32)for i, u in enumerate(users): X[i, 0] = u.age or 0 X[i, 1] = u.exposure_cnt or 0 # ...这种写法有点“笨”,但在模型迭代节奏越来越快的反而稳定。和那种“到处 hstack、vstack 拼矩阵”的写法比,出问题时更容易对齐,回滚也简单。
说到这,你大概能感觉到,“numpy创建矩阵”这件事,本质是一套工程习惯。从一个过来人的视角,我更愿意跟你分享的是这几个落地的小动作:
创建之后立刻检查
shape和dtype用肉眼看一眼终端日志,远比事后在监控里抓异常轻松。涉及向量、特征,给 dtype 指明方向默认 float32,当你有反向理由时,再例外。
宁愿一开始多花 10 行代码,也不要在下游到处救火特别是构建大矩阵时,明确行列含义、保持 schema 稳定,是对自己和同事的体贴。
把“矩阵创建逻辑”写成小函数比如
build_feature_matrix(users),里面封装所有numpy创建矩阵的细节,外层只管传数据。这是我们在中大型项目里维持清晰边界的一种简单做法。
2026 年的数据世界,比几年前复杂太多:多模态、在线学习、向量检索、分布式训练……但不论技术名词怎么变,那些扎实的小习惯,总能在关键时刻把你从坑里拉出来。
如果你现在的困惑刚好卡在“numpy创建矩阵”的各种细节里,不妨从下一段代码就开始练这些小习惯。也许过段时间,你再看自己现在的写法,会有一种很轻微但很愉快的羞涩——那种感觉,说明你已经悄悄进步了。