7.数据透视与合并
本文最后更新于 2025年7月31日 晚上
数据透视表 (pivot_table)
数据透视表是探索多维数据关系的强大工具,它可以将“长”格式的数据重塑为“宽”格式的、类似电子表格的视图。
1. 加载数据
- 题目: 读取当前目录下
"某超市销售数据.csv"并设置千分位符号为,。 - 答案:
1
2
3
4import pandas as pd
# thousands=',' 用于在读取时自动处理带千分位逗号的数字字符串
df = pd.read_csv("某超市销售数据.csv", thousands=',') - 解题过程:
- 在数据分析中,经常会遇到用逗号作为千分位分隔符的数字(如 “1,234.56”)。如果直接读取,Pandas 会将其识别为字符串
object类型,无法进行数值计算。 pd.read_csv()的thousands参数就是为了解决这个问题。通过设置thousands=',',Pandas 在读取时会自动移除逗号,并将该列正确地解析为数值类型(如int64或float64)。
- 在数据分析中,经常会遇到用逗号作为千分位分隔符的数字(如 “1,234.56”)。如果直接读取,Pandas 会将其识别为字符串
2. 数据透视|默认
- 题目: 制作各省「平均销售额」的数据透视表。
- 答案:
1
2
3# 使用 pivot_table
pivot_table_mean = pd.pivot_table(df, values = '销售额',index = '省/自治区')
print(pivot_table_mean) - 解题过程:
pd.pivot_table()是创建数据透视表的核心函数。df: 第一个参数是待操作的 DataFrame。index='省/自治区':index参数指定了新表的行索引,我们想按省份来观察数据,所以将其设置为'省/自治区'。- 默认行为: 当我们不指定
values(要聚合的数值)和aggfunc(聚合函数)时,pivot_table默认会:- 选取所有数值类型的列作为
values。 - 使用均值 (
'mean') 作为默认的aggfunc。
- 选取所有数值类型的列作为
- 因此,这个简单的调用就能得到各省所有数值列的平均值,其中就包含了平均销售额。
3. 数据透视|指定方法
- 题目: 制作各省「销售总额」的数据透视表。
- 答案:
1
2pivot_table_sum = pd.pivot_table(df, index='省/自治区', values='销售额', aggfunc='sum')
print(pivot_table_sum) - 解题过程:
- 这次我们需求更明确,需要用到另外两个核心参数:
values='销售额': 指定我们只关心“销售额”这一列的聚合结果。aggfunc='sum': 指定聚合函数为求和 ('sum'),而不是默认的求均值。
4. 数据透视|多方法
- 题目: 制作各省「销售总额」与「平均销售额」的数据透视表。
- 答案:
1
2pivot_table_multi_func = pd.pivot_table(df, index='省/自治区', values='销售额', aggfunc=['sum', 'mean'])
print(pivot_table_multi_func) - 解题过程:
aggfunc参数可以接收一个函数列表。当你想对同一个values列应用多种聚合方法时,只需将这些方法的名称字符串放到一个列表中传给它即可。- Pandas 会自动为每种聚合方法生成一列。
5. 数据透视|多指标
- 题目: 制作各省市「销售总额」与「利润总额」的数据透视表。
- 答案:
1
2pivot_table_multi_values = pd.pivot_table(df, index='省/自治区', values=['销售额', '利润'], aggfunc='sum')
print(pivot_table_multi_values) - 解题过程:
values参数同样可以接收一个列名列表。当你想同时对多个指标进行聚合时,将它们的列名放到一个列表中传给values。aggfunc='sum'会分别应用到values列表中的每一列。
6. 数据透视|多索引
- 题目: 制作「各省市」与「不同类别」产品「销售总额」的数据透视表。
- 答案:
1
2pivot_table_multi_index = pd.pivot_table(df, index=['省/自治区', '类别'], values='销售额', aggfunc='sum')
print(pivot_table_multi_index) - 解题过程:
index参数也可以接收一个列名列表。这会创建一个**多级行索引 (MultiIndex)**。- 结果表会先按
'省/自治区'分组,再在每个省内按'类别'分组,清晰地展示了更细粒度的交叉数据。
7. 数据透视|多层
- 题目: 制作各省市「不同类别」产品的「销售总额」透视表。
- 答案:
1
2pivot_table_multi_level = pd.pivot_table(df, index='省/自治区', columns='类别', values='销售额', aggfunc='sum')
print(pivot_table_multi_level) - 解题过程:
columns='类别': 这是透视表的另一个核心参数。columns参数可以将指定列中的唯一值“提升”为新表的列标签。- 这个操作将原本在“类别”列中的“办公用品”、“家具”、“技术”变成了表的列,使得数据更加扁平化,一目了然。这就是“透视”的核心所在。
8. 数据透视|综合
- 题目: 制作「各省市」、「不同类别」产品「销售量与销售额」的「均值与总和」的数据透视表,并在最后追加一行『合计』。
- 答案:
1
2
3
4
5
6
7
8
9comprehensive_pivot = pd.pivot_table(
df,
index=['省/自治区', '类别'], # 多级行索引
values=['数量', '销售额'], # 多个聚合值
aggfunc=['mean', 'sum'], # 多个聚合函数
margins=True, # 添加合计行/列
margins_name='合计' # 自定义合计名称
)
print(comprehensive_pivot) - 解题过程:
- 这是一个展示
pivot_table强大功能的综合案例,它组合了多个参数: index,values,aggfunc都使用了列表,创建了一个多维交叉表。margins=True: 这个参数会自动在结果表的最后添加一行和一列,计算所有数据的总计(All)。margins_name='合计': 用于自定义这个总计行/列的名称。
- 这是一个展示
9. 数据透视|筛选
- 题目: 在上一题的基础上,查询 「类别」 等于 「办公用品」 的详情。
- 答案:
1
2
3
4
5# 先生成上一题的透视表
comprehensive_pivot = pd.pivot_table(df, index=['省/自治区', '类别'], values=['数量', '销售额'], aggfunc=['mean', 'sum'], margins=True, margins_name='合计')
# 使用 query 方法筛选
office_supplies_detail = comprehensive_pivot.query("类别 == '办公用品'")
print(office_supplies_detail) - 解题过程:
pivot_table的结果是一个标准的 DataFrame,因此所有 DataFrame 的筛选方法都适用。query(): 由于透视表的结果是多级索引,使用query()方法进行筛选非常方便。你可以直接在查询字符串中指定索引层级的名称(如'类别')和条件。
10. 数据透视|逆透视
- 题目: 将第 5 题的透视表进行逆透视,其中不需要转换的列为『数量』列。
- 答案:
1
2
3
4
5
6
7
8
9
10
11
12# 先生成第五题的表 (多指标)
pivot_multi_values = pd.pivot_table(df, index='省/自治区', values=['销售额', '利润','数量'], aggfunc='sum').reset_index()
# 进行逆透视 (melt)
melted_table = pd.melt(
pivot_multi_values,
id_vars=['省/自治区', '数量'], # 保持不变的标识列
value_vars=['销售额', '利润'], # 需要被“融化”到行的列
var_name='指标类型', # 新的变量列名
value_name='金额' # 新的值列名
)
print(melted_table.head()) - 解题过程:
pd.melt():melt是pivot的逆操作,它将“宽”格式的数据转换回“长”格式,这在某些数据处理或可视化场景中非常有用。id_vars=['省/自治区', '数量']: 标识变量,这些列在转换过程中保持不变,会为每个“融化”的行重复出现。value_vars=['销售额', '利润']: 值变量,这些列的列名会被“融化”到一个新的列中(由var_name指定),它们对应的值会被“融化”到另一个新列中(由value_name指定)。
数据合并 (concat)
concat 用于沿着一个轴(行或列)将多个 DataFrame 对象拼接在一起。
准备数据
首先,我们执行代码生成本节所需的 df1, df2, df3, df4。
1 | |
11. concat|默认拼接
- 题目: 拼接 df1 和 df2。
- 答案:
1
2concatenated_df = pd.concat([df1, df2])
print(concatenated_df) - 解题过程:
pd.concat()的基本用法是接收一个 DataFrame 对象的列表[df1, df2, ...]。- 默认情况下,
concat沿着axis=0(即行)进行拼接,将第二个 DataFrame 的行追加到第一个的末尾。
12. concat|拼接多个
- 题目: 垂直拼接
df1、df2、df3。 - 答案:
1
2concatenated_multi = pd.concat([df1, df2, df3])
print(concatenated_multi) - 解题过程:
concat可以拼接任意多个 DataFrame,只需将它们都放到列表中即可。
13. concat|重置索引
- 题目: 垂直拼接 df1 和 df4,并按顺序重新生成索引。
- 答案:
1
2concat_ignore_index = pd.concat([df1, df4], ignore_index=True)
print(concat_ignore_index) - 解题过程:
ignore_index=True: 当拼接的 DataFrame 索引不连续或有重叠时,这个参数非常有用。它会忽略原始索引,并为拼接后的新 DataFrame 生成一个从 0 开始的连续索引。- 注意,当
df1和df4拼接时,df1中有而df4中没有的列(C列)和df4中有而df1中没有的列(F列),其缺失的部分会被NaN填充。
14. concat|横向拼接
- 题目: 横向拼接
df1、df4。 - 答案:
1
2concat_axis1 = pd.concat([df1, df4], axis=1)
print(concat_axis1) - 解题过程:
axis=1: 将axis参数设置为 1,可以实现按列(横向)拼接。- Pandas 会根据行索引来对齐数据。对于那些只有一个 DataFrame 中存在的索引行,另一个 DataFrame 对应的列值会用
NaN填充。
15. concat|横向拼接(取交集)
- 题目: 在上一题的基础上,只取结果的交集。
- 答案:
1
2concat_axis1_inner = pd.concat([df1, df4], axis=1, join='inner')
print(concat_axis1_inner) - 解题过程:
join='inner':join参数控制了在另一个轴上的对齐方式。join='outer'(默认): 取并集,保留所有索引。join='inner': 取交集。在横向拼接时,这意味着只保留那些在两个 DataFrame 中都存在的行索引。
16. concat|横向拼接(取指定)
- 题目: 在 14 题基础上,只取包含 df1 索引的部分。
- 答案:
1
2
3# 在pandas的新版本中,reindex 更为推荐和清晰
concat_reindex = pd.concat([df1, df4], axis=1).reindex(df1.index)
print(concat_reindex) - 解题过程:
- 旧版本的
join_axes参数已被弃用。现代 Pandas 的推荐做法是:
- 先正常进行外连接(
join='outer')横向拼接。 - 然后使用
.reindex(df1.index)方法,根据df1的索引来重新索引拼接后的结果。这会精确地只保留df1中存在的那些行,效果与旧的join_axes一致。
- 旧版本的
17. concat|新增索引
- 题目: 拼接
df1、df2、df3,同时新增一个索引(x、y、z)来区分不同的表数据来源。 - 答案:
1
2concat_with_keys = pd.concat([df1, df2, df3], keys=['x', 'y', 'z'])
print(concat_with_keys) - 解题过程:
keys=['x', 'y', 'z']:keys参数非常有用,它可以在拼接的同时,在最外层添加一个新的索引层级。- 列表
['x', 'y', 'z']中的元素会分别对应[df1, df2, df3],作为它们各自数据块的标识。这在需要追踪数据来源时尤其方便。
数据合并 (merge)
merge 实现了数据库风格的连接(join)操作,它根据一个或多个键(key)将不同 DataFrame 的行连接起来。
18. merge|按单键
- 题目: 根据
key连接left和right。 - 答案:
1
2
3
4
5left = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'], 'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3']})
right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']})
merged_on_key = pd.merge(left, right, on='key')
print(merged_on_key) - 解题过程:
pd.merge(left, right, ...):merge是一个顶级函数。on='key':on参数指定了用作连接依据的公共列名。merge会查找left和right表中key列值相同的行,并将它们合并。
19. merge|按多键
- 题目: 根据
key1和key2连接left和right。 - 答案:
1
2
3
4
5left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'], 'key2': ['K0', 'K1', 'K0', 'K1'], 'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3']})
right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'], 'key2': ['K0', 'K0', 'K0', 'K0'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']})
merged_on_multi_keys = pd.merge(left, right, on=['key1', 'key2'])
print(merged_on_multi_keys) - 解题过程:
- 当连接需要基于多个键时,
on参数可以接收一个键名列表。只有当列表中所有键的值都相同时,行才会被合并。
- 当连接需要基于多个键时,
20. merge|左外连接
- 题目: 保留左表全部键。
- 答案:
1
2merged_left_join = pd.merge(left, right, how='left', on=['key1', 'key2'])
print(merged_left_join) - 解题过程:
how='left':how参数定义了连接的方式。'left': 左外连接。以left表的键为基准,保留所有left表的行。如果在right表中找不到匹配的键,则right表的列值会用NaN填充。
21. merge|右外连接
- 题目: 保留右表全部键。
- 答案:
1
2merged_right_join = pd.merge(left, right, how='right', on=['key1', 'key2'])
print(merged_right_join) - 解题过程:
how='right': 右外连接。与左连接相反,以right表的键为基准,保留所有right表的行。
22. merge|全外连接
- 题目: 保留全部键。
- 答案:
1
2merged_outer_join = pd.merge(left, right, how='outer', on=['key1', 'key2'])
print(merged_outer_join) - 解题过程:
how='outer': 全外连接。取left和right表键的并集。对于只在一张表中存在的键,另一张表的列值会用NaN填充。
23. merge|内连接
- 题目: 保留交集。
- 答案:
1
2merged_inner_join = pd.merge(left, right, how='inner', on=['key1', 'key2'])
print(merged_inner_join) - 解题过程:
how='inner': 内连接(这是merge的默认行为)。只保留那些在left和right表中都存在的键。
24. merge|重复索引
- 题目: 重新产生数据并按下图所示进行连接。
- 答案:
1
2
3
4
5
6left = pd.DataFrame({'k': ['K0', 'K1', 'K2'], 'v': [1, 2, 3]})
right = pd.DataFrame({'k': ['K0', 'K0', 'K3'], 'v': [4, 5, 6]})
# suffixes 参数用于为重叠的列名添加后缀以区分
merged_suffixes = pd.merge(left, right, on='k', suffixes=('_left', '_right'))
print(merged_suffixes) - 解题过程:
- 当两个待合并的 DataFrame 中有除了连接键之外的同名列时(如此处的
'v'),直接合并会报错。 suffixes=('_left', '_right'): 这个参数可以解决该问题。它会为来自左表的重名列添加_left后缀,为来自右表的重名列添加_right后缀。
- 当两个待合并的 DataFrame 中有除了连接键之外的同名列时(如此处的
数据合并 (join)
join 是一个 DataFrame 的实例方法(即 left.join(right)),它主要用于基于索引来合并数据,可以看作是 merge 的一种便捷方式。
25. join|左对齐
- 题目: 合并 left 和 right,并按照 left 的索引进行对齐。
- 答案:
1
2
3
4
5left = pd.DataFrame({'A': ['A0', 'A1', 'A2'], 'B': ['B0', 'B1', 'B2']}, index=['K0', 'K1', 'K2'])
right = pd.DataFrame({'C': ['C0', 'C2', 'C3'], 'D': ['D0', 'D2', 'D3']}, index=['K0', 'K2', 'K3'])
joined_df = left.join(right)
print(joined_df) - 解题过程:
left.join(right)默认执行的是左连接 (how='left')。它会遍历left表的每一个索引,去right表中查找相同的索引,如果找到就合并,找不到则用NaN填充。
26. join|左对齐(外连接)
- 题目: 按下图所示进行连接。
- 答案:
1
2joined_outer = left.join(right, how='outer')
print(joined_outer) - 解题过程:
join方法同样有how参数。how='outer'表示进行全外连接,取两个表索引的并集。
27. join|左对齐(内连接)
- 题目: 按下图所示进行连接。
- 答案:
1
2joined_inner = left.join(right, how='inner')
print(joined_inner) - 解题过程:
how='inner'表示进行内连接,只保留两个表共有的索引。
28. join|按索引
- 题目: 重新产生数据并按下图所示进行连接(根据
key)。 - 答案:
1
2
3
4
5left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'], 'key': ['K0', 'K1', 'K0', 'K1']})
right = pd.DataFrame({'C': ['C0', 'C1'], 'D': ['D0', 'D1']}, index=['K0', 'K1'])
joined_on_key = left.join(right, on='key')
print(joined_on_key) - 解题过程:
join方法除了能基于索引连接,也可以使用on参数指定left表中的某一列去和right表的索引进行匹配连接。
29. join|按索引(多个)
- 题目: 重新产生数据并按下图所示进行连接(根据
key1和key2)。 - 答案:
1
2
3
4
5
6left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'], 'key1': ['K0', 'K0', 'K1', 'K2'], 'key2': ['K0', 'K1', 'K0', 'K1']})
index = pd.MultiIndex.from_tuples([('K0', 'K0'), ('K1', 'K0'), ('K2', 'K0'), ('K2', 'K1')])
right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']}, index=index)
joined_on_multi_keys = left.join(right, on=['key1', 'key2'])
print(joined_on_multi_keys) - 解题过程:
on参数同样可以接收一个列名列表。这表示left表需要用key1和key2两列组合起来的值,去匹配right表的多级索引。
7.数据透视与合并
https://blog.wyyy.dpdns.org/2025/7-数据透视与合并/