【Python系列课程】Pandas(三):DataFrame进阶操作——拼接、合并与索引操作
📊 阅读时长:18分钟 | 关键词:Pandas、concat拼接、merge合并、insert、reindex、drop
引言
前两篇文章我们学了 Series 和 DataFrame 的创建与访问,以及数据清洗的核心方法。但在实际数据分析中,数据往往分散在多个表格里——你需要把它们拼在一起、按某个字段关联、或者删除不需要的行列。这篇文章就来解决这些"进阶操作"。
一、DataFrame 常用属性速览
在进入具体操作之前,先熟悉一下 DataFrame 的常用属性。打印一下,心里有数:
import pandas as pd
import numpy as np
d = [['Tom', 17], ['Bob', 18], ['Linda', 26]]
df = pd.DataFrame(data=d, index=['p1', 'p2', 'p3'], columns=['name', 'age'])
print(df.T) # 转置:行列互换
print(df.dtypes) # 每一列的数据类型
print(df.shape) # 形状:(3, 2)
print(df.size) # 元素总数:6
print(df.index) # 行索引
print(df.columns) # 列索引
print(df.axes) # 以列表形式返回 [行索引, 列索引]
print(df.values) # 以 ndarray 形式返回数据
| 属性 | 描述 |
|---|---|
T |
转置(行列互换) |
dtypes |
返回每一列的数据类型 |
shape |
返回 DataFrame 的形状(行数, 列数) |
size |
返回元素总数量 |
index |
返回行索引 |
columns |
返回列索引 |
axes |
以列表形式返回 [行索引, 列索引] |
values |
以 ndarray 数组形式返回数据 |
二、insert() 插入新列
insert(loc, column, value) 可以在指定位置插入一列,而不是追加到最后。
d = {'name': ['Tom', 'Bob', 'Linda'], 'age': [17, 18, 26]}
df = pd.DataFrame(data=d, index=['p1', 'p2', 'p3'])
# 在索引为 2 的位置插入列 'weight'(即第 3 列)
df.insert(2, 'weight', [65, 75, 60])
print(df)
输出:
name age weight
p1 Tom 17 65
p2 Bob 18 75
p3 Linda 26 60
参数说明:
loc:整数,指定插入列的位置(列索引)column:新列的名称value:插入的数据,可以是标量、Series 或 array-like
💡 提示:insert() 是原地操作,直接修改原 DataFrame,没有返回值。
三、reindex() 重新索引
reindex() 不改变原数据,而是按你指定的标签"重新取值"。如果指定的标签不存在,默认填 NaN。
data = np.arange(12).reshape(3, 4)
df = pd.DataFrame(data, index=['n1', 'n2', 'n3'], columns=['a', 'b', 'c', 'd'])
print(df)
a b c d
n1 0 1 2 3
n2 4 5 6 7
n3 8 9 10 11
# 重新索引行标签
df2 = df.reindex(index=['n2']) # 只取 n2 行
print(df2)
df2 = df.reindex(index=['n2', 'n1', 'n4'], fill_value=3.14) # n4 不存在,填充 3.14
print(df2)
# 重新索引列标签
df2 = df.reindex(columns=['c']) # 只取 c 列
print(df2)
参数说明:
| 参数 | 说明 |
|---|---|
labels |
要获取的标签列表,与 axis 配合使用 |
axis |
0 为行,1 为列 |
index |
直接指定行标签 |
columns |
直接指定列标签 |
fill_value |
缺失位置的填充值,默认为 NaN |
💡 reindex() 返回新的 DataFrame,不修改原数据。
四、pd.concat() 拼接
当你有两个表格需要"上上下下"或"左左右右"拼起来时,就用 pd.concat()。
df1 = pd.DataFrame([[1, 2], [3, 4]], index=['p1', 'p2'], columns=list('AB'))
df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AC'))
print("df1:\n", df1)
print("df2:\n", df2)
df1:
A B
p1 1 2
p2 3 4
df2:
A C
0 5 6
1 7 8
# 默认 axis=0:上下拼接,列做并集,缺失值填 NaN
print(pd.concat([df1, df2]))
# join='inner':只保留共有的列
print(pd.concat([df1, df2], join='inner'))
# axis=1:左右拼接,行索引对齐
print(pd.concat([df1, df2], axis=1))
参数详解:
| 参数 | 说明 |
|---|---|
objs |
要拼接的 DataFrame 序列(列表) |
axis |
0 = 纵向拼接(默认),1 = 横向拼接 |
join |
'outer' 保留所有列(默认),'inner' 只保留共有列 |
ignore_index |
True 时忽略原索引,重新生成 0, 1, 2… |
一张图搞懂 concat:
axis=0(纵向) axis=1(横向)
+---+---+ +---+---+---+---+
| A | B | | A | B | A | C |
+---+---+ join='outer' +---+---+---+---+
| 1 | 2 | | 1 | 2 | 5 | 6 |
| 3 | 4 | +-----------> | 3 | 4 | 7 | 8 |
+---+---+ +---+---+---+---+
| A | C |
+---+---+
| 5 | 6 |
| 7 | 8 |
+---+---+
结果:列做并集,缺失填 NaN
五、pd.merge() 合并(重点!)
concat 是"物理拼接",merge 是"逻辑关联"——它像 SQL 的 JOIN,按某个共同的键(列)将两张表关联起来。
d1 = {'name': ['Tom', 'Bob', 'Jack'], 'age': [18, 17, 19], 'weight': [65, 66, 67]}
df1 = pd.DataFrame(data=d1)
d2 = {'name': ['Tom', 'Jack'], 'height': [168, 187], 'weight': [65, 68]}
df2 = pd.DataFrame(data=d2)
print("df1:\n", df1)
print("df2:\n", df2)
df1:
name age weight
0 Tom 18 65
1 Bob 17 66
2 Jack 19 67
df2:
name height weight
0 Tom 168 65
1 Jack 187 68
# 内连接(inner):只保留两表都有的 name
print(pd.merge(df1, df2, how='inner', on='name'))
# 左连接(left):以左表为准,右表没有的填 NaN
print(pd.merge(df1, df2, how='left', on='name'))
# 右连接(right):以右表为准,左表没有的填 NaN
print(pd.merge(df1, df2, how='right', on='name'))
# 外连接(outer):两表所有行都保留
print(pd.merge(df1, df2, how='outer', on='name'))
四种连接方式对比(一张表记住):
| 连接方式 | 说明 | 结果 |
|---|---|---|
inner |
取两表键的交集 | 只保留 key 同时存在的数据 |
left |
以左表为基准 | 右表匹配不上的填 NaN |
right |
以右表为基准 | 左表匹配不上的填 NaN |
outer |
取两表键的并集 | 匹配不上的都填 NaN |
inner 的结果(两表都有的 name = Tom, Jack):
name age weight_x height weight_y
0 Tom 18 65 168 65
1 Jack 19 67 187 68
⚠️ 注意:两表都有
weight列,merge 会自动加上后缀_x和_y区分。
left 的结果(Bob 在右表不存在,对应数据填 NaN):
name age weight_x height weight_y
0 Tom 18 65 168.0 65.0
1 Bob 17 66 NaN NaN
2 Jack 19 67 187.0 68.0
参数详解:
| 参数 | 说明 |
|---|---|
left / right |
左右两个 DataFrame |
how |
'inner' / 'left' / 'right' / 'outer' |
on |
连接键(列名),该键必须在两表中都存在 |
六、drop() 删除行或列
df = pd.DataFrame([[1, 2], [3, 4], [5, 6]],
index=['n1', 'n2', 'n3'], columns=['a', 'b'])
print(df)
a b
n1 1 2
n2 3 4
n3 5 6
# 删除行索引为 'n2' 的数据行
print(df.drop(index='n2'))
# 删除列索引为 'b' 的数据列
print(df.drop(columns='b'))
# 批量删除多行
print(df.drop(index=['n2', 'n1']))
# 批量删除多列
print(df.drop(columns=['a', 'b']))
# inplace=True 直接修改原数据
df.drop(index='n1', inplace=True)
print(df)
参数详解:
| 参数 | 说明 |
|---|---|
labels |
要删除的标签,与 axis 配合 |
axis |
0 = 删除行,1 = 删除列 |
index |
直接指定要删除的行标签 |
columns |
直接指定要删除的列标签 |
inplace |
True 直接修改原数据,返回 None |
小结
| 序号 | 知识点 | 一句话总结 |
|---|---|---|
| 1 | DataFrame 属性 | shape/dtypes/index/columns 快速了解数据轮廓 |
| 2 | insert() |
在指定位置插入新列 |
| 3 | reindex() |
按标签重新取值,不存在的填 NaN |
| 4 | pd.concat() |
上下或左右"物理拼接",join 控制保留策略 |
| 5 | pd.merge() |
按共同键"逻辑关联",how 控制 inner/left/right/outer |
| 6 | drop() |
按标签删除行或列,inplace=True 原地修改 |
下一篇文章,我们将学习 Pandas 的统计与聚合——describe()、groupby()、apply() 等,这些才是数据分析真正的"生产力工具"。
本文是「Python从入门到数据分析」系列的第 15 篇。关注我,不错过后续更新。
更多推荐
所有评论(0)