云计算百科
云计算领域专业知识百科平台

Numpy数据处理详解 02:玩转高性能数组,告别低效循环

Numpy数据处理详解 02:玩转高性能数组,告别低效循环

  • Bilibili 同步视频
  • 前言
  • 一、初识 ndarray:数组 vs Python 列表
  • 二、花式创建各类数组📦
    • 1. arange:生成等差序列(终点不包含)
    • 2. linspace:均分指定区间(终点包含)
    • 3. 多维数组 & shape 查看形状
    • 4. reshape 改变形状、矩阵转置
    • 5. 生成随机数数组🎲
  • 三、索引与切片:提取想要的数据✂️
    • 一维数组索引切片
    • 二维数组索引
  • 四、广播 (Broadcast):NumPy 的黑魔法⚡
  • 五、性能碾压:为什么 NumPy 比原生 Python 快?🚀
  • 小结📝

摘要:NumPy 是 Python 科学计算生态的基石,不管是数据分析、机器学习还是数值仿真,几乎都离不开它。本文从基础用法、数组创建、索引切片、广播机制到性能对比,带你快速上手 NumPy 核心能力,理解为什么它比原生 Python 列表更快。

Bilibili 同步视频

Numpy数据处理详解 02:玩转高性能数组,告别低效循环

前言

写 Python 做数值计算的时候,很多小伙伴第一反应就是用原生list列表存数据。但一旦数据量变大,循环写一堆加减乘除,程序瞬间就变得慢吞吞🐢。这时候就该 NumPy 登场了!

NumPy 核心是ndarray 多维数组对象,它把大量数据存放在连续内存空间,底层由 C 语言实现运算,避开 Python 循环的性能开销。很多数据分析库 Pandas、SciPy,底层都重度依赖 NumPy。今天我们从零上手,搞懂 NumPy 最常用的核心操作。

💡小提示:NumPy 标准导入约定是import numpy as np,后续代码示例全部沿用np这个别名。

一、初识 ndarray:数组 vs Python 列表

首先我们来感受 ndarray 和普通 Python 列表最直观的差别。

普通 Python 列表做乘法,只会复制拼接列表元素,并不会对内部每个数字做运算:

# 原生列表
print([1,2,3] * 3)
# 输出:[1, 2, 3, 1, 2, 3, 1, 2, 3]

而 NumPy 数组则是元素级运算,运算符直接作用于数组里面的每一个元素:

import numpy as np
a = np.array([1,2,3])
print(a * 3) # 每个元素 ×3
print(a + 2) # 每个元素 +2

输出:

[3 6 9]
[3 4 5]

这就是 NumPy 很迷人的一点:不用写 for 循环,一行搞定批量数值运算。

再试试数组与数组之间运算:

a = np.array([1,2,3])
b = np.array([2,2,0])

print(a + b) # 对应位置相加
print(a * b) # 哈达玛积:对应位置逐个相乘
# print(a / b) # 会报RuntimeWarning,除以0得到inf无穷大

📌知识点:*代表哈达玛积(逐元素相乘);如果要做向量内积(点积),需要用np.dot()

print(np.dot(a, b)) # 1*2 + 2*2 +3*0 = 6

二、花式创建各类数组📦

除了手动写np.array([…]),NumPy 提供很多工具函数快速生成序列数组。

1. arange:生成等差序列(终点不包含)

语法:np.arange(起点,终点,步长)

print(np.arange(10)) # 0~9
print(np.arange(0, 10, 2)) # 0,2,4,6,8,终点10不会包含进来

⚠️注意:arange的终止值是开区间,不会被纳入数组。

2. linspace:均分指定区间(终点包含)

如果你希望把一段区间平均切分成 N 份,并且包含首尾两个端点,就用linspace。

# 将0~10,切分成15个点
arr = np.linspace(0, 10, 15)
print(arr)

3. 多维数组 & shape 查看形状

用嵌套列表就可以创建二维、三维甚至更高维数组。

# 二维数组,2行3列矩阵
c = np.array([[1,2,3],
[4,5,6]])
print(c.shape) # 返回元组 (2,3),代表2行,3列

三维数组示例:

d = np.array([[[1, 2, 3],[4, 5, 6], [7, 8, 9],[10, 11,12]],
[[13,14,15],[16,17,18],[19,20,21],[22,23,24]]])
print(d.shape) # (2,4,3)

可以把这个三维数组简单理解为:2 个4×3的二维矩阵堆叠在一起。

4. reshape 改变形状、矩阵转置

数组总元素数量不变的前提下,可以自由重塑维度:

c = np.array([[1,2,3],[4,5,6]])
print(c.reshape(3, 2)) # 改成3行2列
print(c.reshape(6, 1)) # 改成6行1列

矩阵转置两种写法,效果完全等价:

print(c.T)
print(np.transpose(c))

5. 生成随机数数组🎲

np.random模块用来生成随机数组:

  • randn():服从标准正态分布随机数(均值 0,方差 1)

  • rand():生成 0~1 之间均匀分布随机数

  • 传入形状参数,可以直接生成多维随机数组

print(np.random.randn()) # 单个正态随机数
print(np.random.rand()) # 单个0‑1随机小数
print(np.random.randn(2,3)) # 2行3列正态随机数组

三、索引与切片:提取想要的数据✂️

一维数组索引切片

和 Python 列表类似,索引从 0 开始;切片语法[start:end:step],end 位置不包含。

a = np.array([1,2,3])
print(a[0]) # 获取第一个元素
a[1] = 99 # 修改指定索引位置的值
print(a)

d = np.array([0, 5, 2, 7,1,9])
print(d[1:5]) # 取下标1~4
print(d[1:3])
print(d[0:5:2]) # 从0到4,步长2取值
print(d[::–1]) # 🔥超实用!数组逆序翻转

✨记住 [::-1],一行实现数组反转,写代码高频用到。

二维数组索引

二维数组索引格式:[行索引,列索引],逗号隔开行列位置。

c = np.array([[1,2,3],[4,5,6]])
print(c[0,0]) # 第0行第0列
print(c[0,2]) # 第0行第2列
print(c[1,2]) # 第1行第2列

四、广播 (Broadcast):NumPy 的黑魔法⚡

广播是 NumPy 最强大的特性之一:不同形状数组运算时,NumPy 会自动做维度扩展对齐,不需要手动复制数据,省去大量 for 循环。

举个直观例子:一维数组a = [1,2,3],和 2 行 3 列二维数组c相加。

a = np.array([1,2,3])
c = np.array([[1,2,3],
[4,5,6]])

res = a + c
print(res)

输出:

[[2 4 6]
[5 7 9]]

逻辑:一维数组a自动在行方向复制一份,变成和c相同的 2 行 3 列,再逐元素相加。 同样乘法也支持广播:

print(a * c)

💡广播不会真实复制内存数据,只是逻辑层面扩展,内存开销很小,效率很高。

五、性能碾压:为什么 NumPy 比原生 Python 快?🚀

很多同学只知道 NumPy 快,但缺少直观感受。 原因在于:

  • ndarray 数据存储在连续内存块;

  • 核心运算逻辑由 C 实现,避开 Python 循环解释开销;

  • 广播、向量化运算代替手写 for 循环。

  • 我们写一段测试代码,对比np.sum()和 Python 内置sum()计算大数据:

    import time
    import numpy as np

    def calculate_time():
    # 十万个随机数
    a = np.random.randn(100000)
    b = list(a)

    start_time = time.time()
    for _ in range(1000):
    s1 = np.sum(a)
    print(f"NumPy求和耗时:{time.time()–start_time:.6f} sec")

    start_time = time.time()
    for _ in range(1000):
    s2 = sum(b)
    print(f"原生list sum耗时:{time.time()–start_time:.6f} sec")

    calculate_time()

    输出示例:

    NumPy求和耗时:0.064xxx sec
    原生list sum耗时:0.095xxx sec

    十万规模已经拉开差距,如果数据量上升到千万级别,差距会变得极其恐怖。在 IPython 中可以用魔法命令%timeit做精准测速:

    a = np.random.randn(10000000)
    %timeit np.sum(a)
    %timeit sum(a)

    千万级数组测试可以看到,np.sum毫秒级别完成,原生 sum 要耗费 1 秒以上。

    ✨开发经验:尽量避免 for 循环遍历数组,优先用 NumPy 向量化、广播写法,这是写出高性能数值代码的关键。

    小结📝

  • NumPy 核心是ndarray多维数组,支持逐元素运算,和 Python list 行为差异很大;

  • 可以用array、arange、linspace创建数组,.shape查看维度,reshape、.T调整形态;

  • 索引切片[start:end:step],[::-1]实现数组翻转;二维数组用[行,列]取值;

  • 广播机制自动对齐数组维度,消除循环,简洁又高效;

  • 底层 C 实现 + 连续内存,NumPy 向量化运算性能远超 Python 原生循环。

  • Numpy数据处理详解 02:玩转高性能数组,告别低效循环

    NumPy 是科学计算的地基,熟练掌握数组、广播、向量化,后面学习 Pandas、机器学习库时就会事半功倍。赶快打开 IPython,动手敲一遍上面的示例代码吧!

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Numpy数据处理详解 02:玩转高性能数组,告别低效循环
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!