查看全课大纲(第 32 / 101 节)
  1. 1.数据分析基本概念
  2. 2.学习数据分析的一般路线
  3. 3.数据分析的流程
  4. 4.数据类型
  5. 5.环境部署(1)
  6. 6.环境部署(2)
  7. 7.课程介绍
  8. 8.TXT文件操作
  9. 9.JSON文件操作
  10. 10.CSV文件操作
  11. 11.Excel文件操作
  12. 12.数据库及SQL常用语法
  13. 13.数据库基本操作
  14. 14.数据库多表连接
  15. 15.实战:欧洲职业足球数据库分析
  16. 16.爬虫简介
  17. 17.URL管理模块
  18. 18.网页下载模块
  19. 19.网页解析模块(1)
  20. 20.网页解析模块(2)
  21. 21.Scrapy简介
  22. 22.Scrapy使用步骤(1)
  23. 23.Scrapy使用步骤(2)
  24. 24.Scrapy使用步骤(3)
  25. 25.Scrapy使用步骤(4)
  26. 26.实战:获取国内城市空气质量指数数据
  27. 27.NumPy和SciPy介绍
  28. 28.多维数组
  29. 29.多维数组操作
  30. 30.NumPy的常用方法
  31. 31.向量化介绍
  32. 32.向量化及通用函数
  33. 33.实战:2016美国大选分析
  34. 34.数据结构-Series
  35. 35.数据结构-DataFrame
  36. 36.数据结构-Index
  37. 37.Series的索引操作
  38. 38.DataFrame的索引操作
  39. 39.索引操作总结
  40. 40.运算与对齐
  41. 41.函数应用操作(1) -- map
  42. 42.函数应用操作 (2) -- apply applymap
  43. 43.文件读写操作
  44. 44.排序操作
  45. 45.数据清洗--处理缺失数据
  46. 46.数据清洗--处理重复数据
  47. 47.数据清洗--替换数据
  48. 48.常用统计方法(1) -- describe quantile
  49. 49.常用统计方法(2) -- sum mean median count
  50. 50.常用统计方法(3) -- max min idxmax idxmin
  51. 51.常用统计方法(4) -- mad var std cumsum
  52. 52.实战:全球食品数据分析
  53. 53.层级索引
  54. 54.分组与聚合介绍
  55. 55.分组操作(1) -- GroupBy对象及常用聚合操作
  56. 56.分组操作(2) -- 自定义分组及聚合操作
  57. 57.透视表介绍
  58. 58.透视表操作
  59. 59.数据规整(1) -- 数据合并concat
  60. 60.数据规整(2) -- 数据连接merge
  61. 61.数据重构(3) -- 数据重构stack unstack
  62. 62.实战:互联网电影资料库分析
  63. 63.探索性数据分析EDA介绍
  64. 64.EDA的目的
  65. 65.EDA常用工具
  66. 66.Matplotlib绘图基本介绍
  67. 67.Matplotlib画布
  68. 68.散点图和柱状图的绘制
  69. 69.直方图的绘制
  70. 70.矩阵绘图
  71. 71.子图的使用
  72. 72.Matplotlib颜色、标记、线型
  73. 73.Matplotlib坐标刻度、标签、图例、标题
  74. 74.Seaborn介绍
  75. 75.数据集分布可视化(1) -- 单变量分布、双变量分布
  76. 76.数据集分布可视化(2) -- 变量关系可视化
  77. 77.类别数据可视化 -- 类别散布图、类别内数据分布、类别内统计图
  78. 78.交互式数据可视化工具Bokeh介绍
  79. 79.Bokeh绘制散点图、柱状图、盒子图、弦图
  80. 80.Bokeh绘制常用图形元素
  81. 81.3D绘图 -- mplot3d
  82. 82.3D曲线可视化
  83. 83.3D散点图可视化
  84. 84.3D柱状图可视化
  85. 85.Pandas绘图
  86. 86.实战:Lending Club借贷数据探索性分析及可视化
  87. 87.机器学习介绍及应用场景
  88. 88.机器学习建模介绍 (1) -- 分类
  89. 89.机器学习建模介绍 (2) -- 回归
  90. 90.机器学习建模介绍 (3) -- 聚类
  91. 91.机器学习分类
  92. 92.机器学习工具scikit-learn
  93. 93.使用scikit-learn的流程
  94. 94.数据集准备及划分
  95. 95.模型选择
  96. 96.数据预处理及特征工程
  97. 97.过拟合与欠拟合
  98. 98.模型调参介绍
  99. 99.模型调参方法
  100. 100.模型测试及评价
  101. 101.实战:通过移动设备行为数据预测性别和年龄

向量化及通用函数

约 7 分钟

📺 正在播放小象学院官方高清录播(支持倍速与清晰度调节)

向量化与通用函数

小象实战讲义 · Python数据分析实战

在上一节我们理解了向量化(Vectorization)和广播(Broadcasting)的概念,它们是NumPy高效运算的核心思想。本节我们将通过代码实战,直观感受向量化运算相比传统循环的巨大性能优势,并学习NumPy中另一类重要工具——通用函数(Universal functions, ufuncs),它们提供了丰富的元素级运算能力。

💡 核心导读

  • 向量化实战对比:通过10万量级数组的乘法运算,对比循环与向量化两种实现方式的代码简洁度与执行效率。
  • 广播操作验证:用代码复现上节课讲解的几种典型广播场景,验证NumPy自动处理形状兼容的能力。
  • 通用函数入门:掌握ceil、floor、rint、isnan等常用数学通用函数,理解其元素级操作的本质。
  • 运算辨析:明确multiply(元素相乘)与矩阵乘法是完全不同的操作,避免概念混淆。

向量化代码实战:效率的飞跃

我们通过一个具体的例子来感受向量化的威力:将两个长度均为10万的一维数组进行逐元素相乘。

方法一:使用循环(非向量化)

传统思路是使用for循环遍历每个索引,取出对应元素进行计算。这种方法直观,但效率较低。

import numpy as np
import time

# 创建两个长度为10万的数组(每个代码块自包含)
a = np.arange(100000, dtype=float)  # 0, 1, 2, ..., 99999
b = np.arange(100000, 0, -1, dtype=float)  # 100000, 99999, ..., 1

# 方法一:使用循环
begin = time.time()
results_loop = []
for i, j in zip(a, b):
    results_loop.append(i * j)
end = time.time()
time_loop = end - begin  # 循环耗时(秒数随机器/负载而变,属非确定值,不打印)
print('循环计算完成,前5个结果:', [float(x) for x in results_loop[:5]])
循环计算完成,前5个结果: [0.0, 99999.0, 199996.0, 299991.0, 399984.0]

方法二:使用向量化操作

NumPy的向量化允许我们直接对整个数组进行运算,无需显式循环。代码极其简洁。

import numpy as np
import time

# 创建两个长度为10万的数组(每个代码块自包含)
a = np.arange(100000, dtype=float)
b = np.arange(100000, 0, -1, dtype=float)

# 方法二:使用向量化操作
begin = time.time()
results_vectorized = a * b  # 直接对整个数组进行乘法运算
end = time.time()
time_vectorized = end - begin  # 向量化耗时(秒数随机器/负载而变,属非确定值,不打印)

# 验证两种方式的计算结果完全一致(确定性输出)
results_loop = [i * j for i, j in zip(a, b)]
print('向量化与循环的计算结果一致:', np.allclose(results_loop, results_vectorized))
print('向量化结果前5个元素:', results_vectorized[:5])
向量化与循环的计算结果一致: True
向量化结果前5个元素: [     0.  99999. 199996. 299991. 399984.]

说明:耗时属于「每次运行都会变化」的测量值,不适合作为固定印刷结果展示。在典型笔记本电脑上,本例的向量化写法通常比循环快 20~50 倍;你可以在自己的机器上运行 print(time_loop / time_vectorized) 亲自验证这个倍数。

对比分析:

  1. 代码简洁性:向量化仅需一行 a * b,而循环需要多行代码构造循环体。
  2. 执行效率:向量化运算由NumPy底层通过高度优化的C代码实现,并充分利用了现代CPU的SIMD(单指令多数据流)指令集实现并行计算,速度通常比Python循环快一到两个数量级(本节数据量下约20~50倍),且数据量越大优势越显著。

广播操作代码验证

广播是NumPy中另一个强大的机制,它允许不同形状的数组进行算术运算。我们来验证上节课提到的几个广播例子。

import numpy as np

# 示例1:一维数组与标量相加(标量被广播到数组的每个元素)
print("示例1 - 数组与标量相加:")
print(np.arange(3) + 5)
print()

# 示例2:二维数组与一维数组相加(一维数组被广播到每一行)
print("示例2 - 二维数组与一维数组相加:")
print(np.ones((3, 3)) + np.arange(3))
print()

# 示例3:列向量与行向量相加(两者都被广播,生成一个二维数组)
print("示例3 - 列向量与行向量相加:")
col_vector = np.arange(3).reshape((3, 1))  # 形状(3,1)
row_vector = np.arange(3)                  # 形状(3,)
print(col_vector + row_vector)
示例1 - 数组与标量相加:
[5 6 7]

示例2 - 二维数组与一维数组相加:
[[1. 2. 3.]
 [1. 2. 3.]
 [1. 2. 3.]]

示例3 - 列向量与行向量相加:
[[0 1 2]
 [1 2 3]
 [2 3 4]]

运行结果证实了广播规则的有效性。NumPy自动处理了形状扩展,使得这些运算能够顺利进行,无需我们手动复制数据。

通用函数:元素级运算工具

通用函数(ufunc)是一种对数组中的每个元素进行操作的函数。NumPy提供了大量的通用函数,涵盖数学、三角、逻辑比较等领域。

常用数学通用函数

我们首先看几个处理数值的通用函数:ceil(向上取整)、floor(向下取整)、rint(舍入到最近整数;遇到 .5 时取偶数,即“银行家舍入”,如 np.rint([0.5, 1.5, 2.5]) 得到 [0, 2, 2])和isnan(判断是否为非数字NaN)。

import numpy as np

# 一个2行3列的示例数组(硬编码字面量,保证每次运行输出一致)
arr = np.array([[ 0.01511223,  0.38603533,  1.10498912],
                [ 1.04669897, -0.34327965, -0.40234461]])
print("原始数组:")
print(arr)
print()

print("向上取整 (np.ceil):")
print(np.ceil(arr))
print()

print("向下取整 (np.floor):")
print(np.floor(arr))
print()

print("舍入到最近整数 (np.rint, .5 取偶):")
print(np.rint(arr))
print()

print("判断是否为NaN (np.isnan):")
print(np.isnan(arr))
原始数组:
[[ 0.01511223  0.38603533  1.10498912]
 [ 1.04669897 -0.34327965 -0.40234461]]

向上取整 (np.ceil):
[[ 1.  1.  2.]
 [ 2. -0. -0.]]

向下取整 (np.floor):
[[ 0.  0.  1.]
 [ 1. -1. -1.]]

舍入到最近整数 (np.rint, .5 取偶):
[[ 0.  0.  1.]
 [ 1. -0. -0.]]

判断是否为NaN (np.isnan):
[[False False False]
 [False False False]]

可以看到,每个函数都独立地作用于数组arr的每一个元素上,输出一个形状相同的新数组。

算术通用函数:multiply 与 divide

np.multiply 和 np.divide 是进行元素级乘法和除法的通用函数。

import numpy as np

# 元素乘法
arr = np.arange(3)  # [0, 1, 2]
print("使用 np.multiply 进行元素乘法:")
print(np.multiply(arr, 5))
print()

print("使用数组的 * 运算符 (效果等同):")
print(arr * 5)
print()

# 元素除法
print("使用 np.divide 进行元素除法:")
print(np.divide(arr, 5))
print()

print("使用数组的 / 运算符 (效果等同):")
print(arr / 5)
使用 np.multiply 进行元素乘法:
[ 0  5 10]

使用数组的 * 运算符 (效果等同):
[ 0  5 10]

使用 np.divide 进行元素除法:
[0.  0.2 0.4]

使用数组的 / 运算符 (效果等同):
[0.  0.2 0.4]

重要辨析: np.multiply 执行的是元素对应相乘(Element-wise multiplication),它与Python的*运算符在NumPy数组上的行为完全一致。这与线性代数中的矩阵乘法(Matrix multiplication)是截然不同的操作。矩阵乘法在NumPy中通常使用 np.dot、@运算符或 np.matmul 函数来实现。初学者务必注意区分,避免混淆。

📝 动手练一练

  1. 概念辨析:假设有两个二维数组 A (形状 2x3) 和 B (形状 3x2)。A * B 和 A @ B 这两个操作,哪个能成功执行?它们分别代表什么类型的运算?
👉 点击查看参考答案
  • A * B:这个操作会失败。注意元素级乘法并非要求形状严格相同——只要满足广播规则即可(如本节示例中 (3,1) 数组与 (3,) 向量相乘就靠广播成功);但这一对形状恰好不兼容:按广播规则从末尾维度对齐时,A 的末维 3 与 B 的末维 2 既不相等、也不是 1,无法广播到共同形状,因此报错。
  • A @ B:这个操作可以成功执行。@ 运算符代表矩阵乘法。矩阵乘法要求第一个数组的列数(3)等于第二个数组的行数(3),因此 A(2x3) @ B(3x2) 是有效的,结果将是一个形状为 (2, 2) 的新数组。
  1. 代码实战:创建一个包含 [1.2, 2.7, 3.5, 4.1] 的NumPy数组。请编写代码,分别计算:
    • 每个元素平方根(np.sqrt)的结果。
    • 每个元素以2为底的对数(np.log2)的结果。
👉 点击查看参考答案
import numpy as np
arr = np.array([1.2, 2.7, 3.5, 4.1])
print("原始数组:", arr)
print("平方根:", np.sqrt(arr))
print("以2为底的对数:", np.log2(arr))

运行结果示例(具体小数位可能因环境略有差异):

原始数组: [1.2 2.7 3.5 4.1]
平方根: [1.09544512 1.64316767 1.87082869 2.02484567]
以2为底的对数: [0.26303441 1.43295941 1.80735492 2.03562391]

本章小结

本节我们通过实战深刻体会了NumPy两大核心特性带来的好处:

  • 向量化:用简洁的数组表达式替代冗长的循环,不仅提升了代码的可读性,更借助底层优化获得了数十倍乃至更高的性能提升,是数据分析中必须掌握的核心写法。
  • 广播:让形状不同的数组进行算术运算成为可能,规则清晰且自动执行,极大地增加了代码的灵活性和表达力。
  • 通用函数:提供了丰富的、高性能的元素级运算工具,从基本的四则运算到复杂的数学函数,是构建向量化计算的基础模块。

📋 行动清单

  • 在遇到需要对数组每个元素进行操作时,第一反应应是“能否用向量化表达式或通用函数实现?”,尽量避免手动编写Python循环。
  • 练习使用 np.ceil, np.floor, np.sqrt, np.log 等常用通用函数处理小型示例数组,熟悉其输入输出。
  • 明确区分 * (元素乘) 与 @ 或 np.dot (矩阵乘) 的使用场景,避免在后续线性代数运算中出错。

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 本节课件:向量化及通用函数
    PDF · 260KB
    下载
  • 全套课件打包(第1-5章)
    ZIP · 12.8MB
    下载
  • 全套课件打包(第6-8章)
    ZIP · 15MB
    下载
  • 实战数据集:AppleStore 应用商城分析
    ZIP · 329KB
    下载
  • 实战数据集:女性服装电商分析
    ZIP · 2.8MB
    下载
  • Python 数据分析环境搭建指南
    PDF · 2MB
    下载
  • Scrapy 安装教程
    PDF · 12.7MB
    下载
  • 附加实战项目:AppleStore 应用商城数据分析
    ZIP · 0.3MB · ipynb + CSV 数据
    下载
  • 附加实战项目:银行电话营销数据分析
    ZIP · 0.4MB · ipynb + CSV 数据
    下载
  • 附加实战项目:女性服装电商评论数据分析
    ZIP · 2.7MB · ipynb + CSV 数据
    下载
  • 附加实战项目:美国化学学会杂志数据分析
    ZIP · 34.2MB · ipynb + SQLite 数据库
    下载