Pandas & NumPy Academy · 课时

按索引连接

使用 DataFrame.join(),并在 merge() 中设置 left_index/right_index=True,将按索引对齐的 DataFrames 合并起来。

第 4 / 4 课13 个步骤

按索引连接 是 CoddyKit 上的免费 Pandas & NumPy Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Pandas & NumPy Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Pandas & NumPy Academy 课程共包含 4 节课。

基于索引的 join

到目前为止,您一直通过匹配常规列中的值来合并 DataFrame。但有时,您要匹配的信息存储在 DataFrame 的索引中,而不是列中。Pandas 支持基于索引的 join,既可以使用 DataFrame.join(),也可以在 pd.merge() 中使用 left_index=True 或 right_index=True 参数。

DataFrame.join() 方法

DataFrame.join(other) 是一种便捷方法,默认根据两个 DataFrame 的索引执行 join。它等价于调用 pd.merge() 并设置 left_index=True, right_index=True。默认 join 类型是 'left',不同于默认使用 'inner' 的 pd.merge()。两个 DataFrame 必须具有有意义的、可相互对应的索引标签,join 才能生成正确结果。

import pandas as pd

profiles = pd.DataFrame(
    {'age': [25, 30, 22]},
    index=['alice', 'bob', 'carol']
)

scores = pd.DataFrame(
    {'score': [88, 95, 70]},
    index=['alice', 'carol', 'dave']
)

# join: left join on index (default)
result = profiles.join(scores)
print(result)
#        age  score
# alice   25   88.0
# bob     30    NaN   <- bob has no score
# carol   22   95.0

在 join() 中控制 join 类型

向 join() 传入 how 参数,可以控制保留哪些行,其作用与 pd.merge() 相同。可选值包括 'left'(默认值)、'right'、'inner' 和 'outer'。例如,how='inner' 只保留同时出现在两个 DataFrames 中的索引;如果 alice 这一行在右表中没有匹配的索引,就会被丢弃。

# Inner join on index: only rows present in BOTH indices
print(profiles.join(scores, how='inner'))
#        age  score
# alice   25     88
# carol   22     70

# Outer join: all indices from both
print(profiles.join(scores, how='outer'))
#        age  score
# alice  25.0   88.0
# bob    30.0    NaN
# carol  22.0   70.0
# dave    NaN   95.0

同时连接多个 DataFrames

与 pd.merge() 相比,join() 的一大优势是接受由多个 DataFrames 组成的列表,并在一次调用中将它们全部连接到当前对象上。所有 DataFrames 必须按索引对齐。当您有许多都使用同一键(例如用户 ID 或日期)作为索引的特征表,并希望将它们组装成一个宽 DataFrame 时,这一功能非常方便。

emails = pd.DataFrame({'email': ['a@x.com', 'b@x.com', 'c@x.com']},
                      index=['alice', 'bob', 'carol'])
city  = pd.DataFrame({'city': ['NY', 'LA', 'SF']},
                     index=['alice', 'bob', 'carol'])

# Join multiple DataFrames at once
result = profiles.join([emails, city])
print(result)
#        age    email city
# alice   25  a@x.com   NY
# bob     30  b@x.com   LA
# carol   22  c@x.com   SF

在一个表的列与另一个表的索引上连接

pd.merge() 可以通过 left_on/right_index 或 left_index/right_on,混合使用基于列和基于索引的匹配。当一个 DataFrame 将键存储在列中,而另一个将其用作索引时,这一功能非常有用。仅使用 join() 无法实现这种连接。

# orders has customer_id as a column; customers is indexed by customer_id
customers_indexed = pd.DataFrame(
    {'name': ['Alice', 'Bob', 'Carol']},
    index=[101, 102, 103]
)
orders = pd.DataFrame({
    'order_id': [1, 2, 3],
    'customer_id': [101, 102, 101]
})

result = pd.merge(orders, customers_indexed,
                  left_on='customer_id', right_index=True)
print(result)
#    order_id  customer_id   name
# 0         1          101  Alice
# 2         3          101  Alice
# 1         2          102    Bob

在 merge() 中使用 left_index 和 right_index

当两个 DataFrames 都将键设为索引时,请使用 pd.merge(left, right, left_index=True, right_index=True)。这与 join() 等价,但默认连接类型是 'inner',并且参数表达得更明确。此外,您还可以使用 suffixes 和 indicator 等所有其他 pd.merge() 参数。

# Both DataFrames indexed by user_id
demog = pd.DataFrame({'age': [25, 30]}, index=[1, 2])
behav = pd.DataFrame({'clicks': [10, 5]}, index=[1, 2])

# Equivalent joins
result1 = demog.join(behav)  # left join
result2 = pd.merge(demog, behav, left_index=True, right_index=True)  # inner join

print(result1)
print(result2)

为什么使用基于索引的连接

当 DataFrames 天然以有意义的标识符作为键(例如用户 ID、产品 SKU 或日期)时,优先使用基于索引的连接。使用索引进行连接可以避免在 DataFrame 中堆积重复的键列,而且可能更快,因为 Pandas 会维护经过排序的索引结构,以便进行 O(log n) 查找。在时间序列数据中,这种方式尤其常见,因为 DatetimeIndex 是天然的连接键。

# Time series example: join temperature and humidity by date index
import numpy as np
dates = pd.date_range('2024-01-01', periods=5)
temp = pd.DataFrame({'temp_c': [10, 12, 9, 11, 13]}, index=dates)
humid = pd.DataFrame({'humidity': [65, 70, 60, 75, 68]}, index=dates)

weather = temp.join(humid)
print(weather.head())

处理重叠的列名

当两个 DataFrames 包含同名列(键列除外)时,如果未提供 lsuffix 和 rsuffix 参数,join() 默认会引发 ValueError。这些参数的作用类似于 pd.merge() 中的 suffixes,会分别将字符串追加到左侧和右侧 DataFrames 的重叠列名后。

df_a = pd.DataFrame({'value': [1, 2]}, index=['x', 'y'])
df_b = pd.DataFrame({'value': [10, 20]}, index=['x', 'y'])

# Without suffixes: raises ValueError
# result = df_a.join(df_b)

# With suffixes: disambiguate column names
result = df_a.join(df_b, lsuffix='_left', rsuffix='_right')
print(result)
#    value_left  value_right
# x           1           10
# y           2           20

连接前使用 set_index

一种常见工作流是在连接前将某列设为索引,这样就可以使用 join() 语法。连接后,reset_index() 会将键还原为普通列。这种模式读起来很自然:将键提升为索引,执行连接,再将键降回普通列,从而让代码意图对后续阅读者一目了然。

orders_col = pd.DataFrame({'order_id': [1,2,3], 'customer_id': [10,20,10], 'amount': [100,200,150]})
cust_col = pd.DataFrame({'customer_id': [10,20], 'name': ['Alice','Bob']})

result = (
    orders_col.set_index('customer_id')
    .join(cust_col.set_index('customer_id'), how='left')
    .reset_index()
)
print(result)

将 Series 对齐到 DataFrame 索引

Series 同样具有索引,您可以通过赋值将其添加为 DataFrame 的新列——Pandas 会自动将 Series 的值与匹配的索引标签对齐。这是一种轻量级的基于索引的连接方式,适用于从 Series 添加单列,而无需调用 merge() 或 join()。

df = pd.DataFrame({'sales': [100, 200, 150]}, index=['A', 'B', 'C'])
tax_rate = pd.Series({'A': 0.1, 'B': 0.2, 'C': 0.15})

# Index alignment: Series aligns to DataFrame index automatically
df['tax'] = df['sales'] * tax_rate
print(df)
#    sales   tax
# A    100  10.0
# B    200  40.0
# C    150  22.5

索引连接性能

在已排序的索引上连接比在普通列上连接更快,因为 Pandas 会在已排序的索引上使用二分查找。如果要反复使用同一个键进行连接,请在数据处理流程开始时就将该键设为索引。这一点在时间序列工作流中尤其重要,因为您可能需要在许多文件之间基于 DatetimeIndex 连接数千次。

# Sort index before repeated joins for speed
left = left.sort_index()
right = right.sort_index()

# Both sorted -> Pandas uses merge path with binary search
result = left.join(right, how='inner')

# Check if index is sorted
print('Left sorted:', left.index.is_monotonic_increasing)
print('Right sorted:', right.index.is_monotonic_increasing)

快速检查

检验您对本课基于索引连接内容的理解。

课程回顾

在本课中,您学习了:DataFrame.join() 默认基于索引执行左连接;使用 left_index=True/right_index=True 的 pd.merge() 提供了更多控制;向 join() 传入列表可以一次连接多个 DataFrames;使用已排序的索引可以提升连接性能。接下来,我们将学习如何使用 pivot_table 重塑 DataFrames。

免费开始

用 AI 导师学习 Python — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
30
课程
120

常见问题解答

「按索引连接」课时是免费的吗?

是的 — 「按索引连接」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Pandas & NumPy Academy 课程的其余内容,请升级到 CoddyKit PRO。 Pandas & NumPy Academy 课程共包含 4 节课。

「按索引连接」这节课中我会学到什么?

使用 DataFrame.join(),并在 merge() 中设置 left_index/right_index=True,将按索引对齐的 DataFrames 合并起来。 你通过在浏览器中直接运行的动手代码来练习 Pandas & NumPy Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Pandas & NumPy Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Pandas & NumPy Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「按索引连接」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Pandas & NumPy Academy 课中编写并运行代码吗?

能。每节 Pandas & NumPy Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 pd.concat 堆叠 DataFrames
  2. pd.merge:内连接与外连接
  3. 左连接与右连接
  4. 按索引连接
← 返回 Pandas & NumPy Academy