查看全课大纲(第 40 / 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.实战:通过移动设备行为数据预测性别和年龄

运算与对齐

约 11 分钟

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

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

在数据分析中,我们经常需要对不同来源、不同结构的数据进行合并与计算。Pandas 的强大之处在于,它能够智能地处理这些操作,而“对齐”正是其核心机制。本节我们将深入探讨 Pandas 中 Series 和 DataFrame 进行算术运算时,索引是如何决定计算结果的,以及如何处理未对齐的数据。

💡 核心导读

  • 索引是运算的“导航图”:Pandas 的运算不是基于数据的位置,而是基于索引标签的匹配。
  • Series 间的对齐:发生在索引上,相同索引的值进行计算,未对齐的位置补 NaN。
  • DataFrame 间的对齐:同时发生在行索引和列索引两个维度上。
  • Series 与 DataFrame 的混合运算:规则特殊,Series 的索引会被视为列,与 DataFrame 的列进行匹配计算。

理解索引对齐机制

Pandas 的设计哲学是“带标签的数据计算”。这意味着,当对两个 Pandas 对象进行运算时,Pandas 不会简单地将第一个对象的第一行与第二个对象的第一行相加,而是会去寻找两个对象中索引标签相同的位置,并对这些位置上的值进行计算。

如果某个索引标签只存在于一个对象中,而在另一个对象中找不到对应的标签,那么该位置在计算结果中将被填充为 NaN(Not a Number,表示缺失值)。这种自动对齐的特性,使得我们可以安全地对不同形状、不同来源的数据进行运算,而无需手动对齐。

Series 间的运算与对齐

我们通过一个具体的例子来理解 Series 间的对齐。假设有两个 Series:

import pandas as pd
import numpy as np

# 创建 Series 1: 索引 0-9,值 10-19
ser1 = pd.Series(range(10, 20), index=range(10))
print("Series 1:")
print(ser1)
print()

# 创建 Series 2: 索引 0-4,值 20-24
ser2 = pd.Series(range(20, 25), index=range(5))
print("Series 2:")
print(ser2)
print()

# Series 间的加法运算
result = ser1 + ser2
print("ser1 + ser2 的结果:")
print(result)
Series 1:
0    10
1    11
2    12
3    13
4    14
5    15
6    16
7    17
8    18
9    19
dtype: int64

Series 2:
0    20
1    21
2    22
3    23
4    24
dtype: int64

ser1 + ser2 的结果:
0    30.0
1    32.0
2    34.0
3    36.0
4    38.0
5     NaN
6     NaN
7     NaN
8     NaN
9     NaN
dtype: float64

运算过程解析:

  1. 对齐:Pandas 首先找到两个 Series 共有的索引标签:0, 1, 2, 3, 4。
  2. 计算:对共有索引位置的值进行相加:10+20=30, 11+21=32, …, 14+24=38。
  3. 处理未对齐项:ser1 中索引 5 到 9 在 ser2 中找不到对应项。因此,结果中索引 5 到 9 的位置被填充为 NaN。
  4. 数据类型:由于引入了 NaN(在 Pandas 中属于浮点类型),整个结果 Series 的数据类型从 int64 自动提升为 float64。

这个例子清晰地展示了 “索引对齐优先于位置顺序” 的原则。

DataFrame 间的运算与对齐

DataFrame 是二维表格,其对齐发生在两个维度:行索引(index)和列索引(columns)。只有行和列标签都匹配的位置,才会进行计算。

import pandas as pd
import numpy as np

# 创建 DataFrame 1: 2行2列,值全为1
df1 = pd.DataFrame(np.ones((2, 2)), columns=['a', 'b'], index=[0, 1])
print("DataFrame 1:")
print(df1)
print()

# 创建 DataFrame 2: 3行3列,值全为1
df2 = pd.DataFrame(np.ones((3, 3)), columns=['a', 'b', 'c'], index=[0, 1, 2])
print("DataFrame 2:")
print(df2)
print()

# DataFrame 间的加法运算
df_result = df1 + df2
print("df1 + df2 的结果:")
print(df_result)
DataFrame 1:
     a    b
0  1.0  1.0
1  1.0  1.0

DataFrame 2:
     a    b    c
0  1.0  1.0  1.0
1  1.0  1.0  1.0
2  1.0  1.0  1.0

df1 + df2 的结果:
     a    b   c
0  2.0  2.0 NaN
1  2.0  2.0 NaN
2  NaN  NaN NaN

运算过程解析:

  1. 行列对齐:Pandas 寻找两个 DataFrame 行和列标签的交集。
    • 行交集:[0, 1]
    • 列交集:[‘a‘, ‘b‘]
  2. 计算:仅对行标签和列标签都匹配的单元格进行计算,即 (0,a), (0,b), (1,a), (1,b) 这四个位置。每个位置都是 1.0 + 1.0 = 2.0。
  3. 处理未对齐项:
    • 对于行2和列c,因为它们在 df1 中不存在,所以对应行/列的所有位置都是 NaN。
    • 结果 DataFrame 的形状由两个输入对象的行、列标签的并集决定。

Series 与 DataFrame 的混合运算

这是最容易令人困惑的部分。核心规则是:当 Series 与 DataFrame 进行运算时,Series 的索引(index)会被匹配到 DataFrame 的列(columns)上。然后,Series 的值会沿着 DataFrame 的行方向进行广播(即每一行都会与这个 Series 进行运算)。

情况一:Series 的索引与 DataFrame 的列完全不匹配

import pandas as pd
import numpy as np

# 创建 DataFrame 1
df1 = pd.DataFrame(np.ones((2, 2)), columns=['a', 'b'], index=[0, 1])
# 创建 Series 2 (索引为数字0-4)
ser2 = pd.Series(range(20, 25), index=range(5))

print("DataFrame 1 (列为字母‘a‘,‘b‘):")
print(df1)
print()
print("Series 2 (索引为数字0-4):")
print(ser2)
print()

mixed_result_1 = ser2 + df1
print("ser2 + df1 的结果:")
print(mixed_result_1)
DataFrame 1 (列为字母‘a‘,‘b‘):
     a    b
0  1.0  1.0
1  1.0  1.0

Series 2 (索引为数字0-4):
0    20
1    21
2    22
3    23
4    24
dtype: int64

ser2 + df1 的结果:
    a   b   0   1   2   3   4
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN

结果分析: 运算时,ser2 的索引 [0,1,2,3,4] 被当作列标签去匹配 df1 的列 [‘a‘, ‘b‘]。由于没有一列能匹配上,所以所有交叉位置都产生 NaN。同时,结果 DataFrame 的列是两者列标签的并集 [0,1,2,3,4,‘a‘,‘b‘],行与 df1 相同 [0,1]。

情况二:Series 的索引与 DataFrame 的列部分匹配

import pandas as pd
import numpy as np

# 创建 DataFrame 1
df1 = pd.DataFrame(np.ones((2, 2)), columns=['a', 'b'], index=[0, 1])
# 创建 Series 3 (索引为字母‘a‘,‘b‘,‘c‘)
ser3 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])

print("DataFrame 1:")
print(df1)
print()
print("Series 3 (索引为字母‘a‘,‘b‘,‘c‘):")
print(ser3)
print()

mixed_result_2 = ser3 + df1
print("ser3 + df1 的结果:")
print(mixed_result_2)
DataFrame 1:
     a    b
0  1.0  1.0
1  1.0  1.0

Series 3 (索引为字母‘a‘,‘b‘,‘c‘):
a    1
b    2
c    3
dtype: int64

ser3 + df1 的结果:
     a    b   c
0  2.0  3.0 NaN
1  2.0  3.0 NaN

结果分析:

  1. 列对齐:ser3 的索引 [‘a‘, ‘b‘, ‘c‘] 与 df1 的列进行匹配。‘a‘ 和 ‘b‘ 匹配成功。
  2. 广播与计算:对于匹配成功的列,ser3 中该列对应的值会与 df1 中该列的每一行进行计算。
    • 列 a: df1 中所有行的值都是 1.0,加上 ser3[‘a‘]=1,结果该列所有行变为 2.0。
    • 列 b: 1.0 + 2 = 3.0。
  3. 处理未匹配项:ser3 中的 ‘c‘ 在 df1 中没有对应列,因此结果中新增一列 c,其值全部为 NaN。

本章小结

Pandas 的运算与对齐机制是其数据处理能力的基石。它让我们能够以声明式的方式操作数据,而无需陷入繁琐的循环和条件判断中。

  • 对齐是核心:所有运算都基于索引标签的匹配,而非数据的位置。
  • NaN 是安全符:未对齐的数据用 NaN 填充,避免了计算错误,也明确标识了数据缺失的情况。
  • 维度决定规则:
    • Series vs Series:在索引维度对齐。
    • DataFrame vs DataFrame:在行和列两个维度对齐。
    • Series vs DataFrame:Series 的索引对齐 DataFrame 的列,然后沿行广播。

📋 行动清单

  • 尝试创建两个索引部分重叠的 Series,手动预测它们相加的结果,再用代码验证。
  • 构造一个 Series 和一个 DataFrame,确保 Series 的索引与 DataFrame 的列部分一致,观察广播计算的效果。
  • 在遇到包含 NaN 的计算结果时,思考这些 NaN 产生的原因是由于行索引、列索引,还是两者都不匹配导致的。

📝 动手练一练

  1. 概念辨析:如果两个 DataFrame 具有完全相同的行索引,但列索引完全不同,它们相加的结果会是什么形状?结果中会有非 NaN 的值吗?
👉 点击查看参考答案

结果 DataFrame 的形状将是:行数为共同的行索引数量,列数为两个 DataFrame 列索引的并集的数量。因为没有任何一列是相同的,所以所有单元格都无法对齐计算,结果中将全部是 NaN 值。

  1. 动手实验:参考视频中的思考题,将 ser2 的索引从 [0,1,2,3,4] 改为 [0,2,4,6,8],然后计算 ser1 + ser2。请先手动推理结果,再用以下代码验证你的想法。
import pandas as pd

# 创建 Series 1
ser1 = pd.Series(range(10, 20), index=range(10))
# 创建修改索引后的 Series 2
ser2_modified = pd.Series(range(20, 25), index=[0, 2, 4, 6, 8])

print("修改后的 Series 2:")
print(ser2_modified)
print()
print("ser1 + 修改后的ser2 的结果:")
print(ser1 + ser2_modified)
👉 点击查看参考答案
修改后的 Series 2:
0    20
2    21
4    22
6    23
8    24
dtype: int64

ser1 + 修改后的ser2 的结果:
0    30.0
1     NaN
2    33.0
3     NaN
4    36.0
5     NaN
6    39.0
7     NaN
8    42.0
9     NaN
dtype: float64

推理与验证:两个 Series 共有的索引是 0, 2, 4, 6, 8。因此,只有这些位置的值能进行计算:10+20=30, 12+21=33, 14+22=36, 16+23=39, 18+24=42。其他索引位置由于无法对齐,结果均为 NaN。

—— 小象教研组

配套资料 · 直接下载

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

  • 本节课件:运算与对齐
    PDF · 193KB
    下载
  • 全套课件打包(第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 数据库
    下载