如何避免多列索引DataFrame调用merge(indicator=True)时的警告
场景复现
我有一个带二级列索引的DataFrame,示例代码如下:
import pandas as pd letters_df = pd.DataFrame([ ['a', 'A'], ['b', 'B'], ['c', 'C'], ['d', 'D'], ['e', 'E'], ['f', 'F'] ], columns=['lower', 'upper']) letters_df.columns = pd.MultiIndex.from_product([['letter'], letters_df.columns]) display(letters_df)
对应的DataFrame结构:
| letter | ||
|---|---|---|
| lower | upper | |
| 0 | a | A |
| 1 | b | B |
| 2 | c | C |
| 3 | d | D |
| 4 | e | E |
| 5 | f | F |
另有一个单级列索引的DataFrame需要合并:
vowels_df = pd.DataFrame([ [True], [False], [False], [False], [True], [False] ], columns=['is_vowel']) display(vowels_df)
结构如下:
| is_vowel | |
|---|---|
| 0 | True |
| 1 | False |
| 2 | False |
| 3 | False |
| 4 | True |
| 5 | False |
直接合并会触发警告:
UserWarning: merging between different levels can give an unintended result (2 levels on the left,1 on the right)
于是我给vowels_df添加了虚拟二级索引:
vowels_df.columns = pd.MultiIndex.from_product([vowels_df.columns, ['dummy']]) display(vowels_df)
结构变为:
| is_vowel | |
|---|---|
| dummy | |
| 0 | True |
| 1 | False |
| 2 | False |
| 3 | False |
| 4 | True |
| 5 | False |
执行合并操作:
merged = letters_df.merge(vowels_df, left_index=True, right_index=True, indicator=True) display(merged)
合并后结构:
| letter | is_vowel | _merge | ||
|---|---|---|---|---|
| lower | upper | dummy | ||
| 0 | a | A | True | both |
| 1 | b | B | False | both |
| 2 | c | C | False | both |
| 3 | d | D | False | both |
| 4 | e | E | True | both |
| 5 | f | F | False | both |
但合并时触发了性能警告:
PerformanceWarning: dropping on a non-lexsorted multi-index without a level parameter may impact performance.
我没有手动调用drop方法,推测是merge内部操作导致的。尝试对两个DataFrame调用sort_index无效,且实际场景需要用outer join并保留indicator列,请问如何消除该警告?
解决方案
方法1:确保列多级索引按字典序排序
警告的核心是多级列索引未按字典序(lexsorted)排序,merge内部处理时会触发性能警告。可以手动对两个DataFrame的列索引进行排序:
# 对letters_df的列索引排序 letters_df = letters_df.sort_index(axis=1) # 对vowels_df的列索引排序 vowels_df = vowels_df.sort_index(axis=1) # 执行outer join合并 merged = letters_df.merge(vowels_df, left_index=True, right_index=True, indicator=True, how='outer')
排序后,多级索引满足lexsorted要求,merge内部的drop操作就不会触发警告了。
方法2:用concat替代merge(适用于按索引合并场景)
如果是按索引进行outer join,也可以用pd.concat替代merge,绕开merge内部的drop逻辑:
# 合并两个DataFrame merged = pd.concat([letters_df, vowels_df], axis=1, join='outer') # 手动添加indicator列,模拟merge的indicator功能 merged['_merge'] = 'both' # 标记仅存在于左表的行 merged.loc[letters_df.index.difference(vowels_df.index), '_merge'] = 'left_only' # 标记仅存在于右表的行 merged.loc[vowels_df.index.difference(letters_df.index), '_merge'] = 'right_only'
方法3:临时屏蔽特定警告
如果上述方法都不适用,可以临时屏蔽该PerformanceWarning,不影响其他警告输出:
import warnings with warnings.catch_warnings(): warnings.filterwarnings('ignore', category=pd.errors.PerformanceWarning) merged = letters_df.merge(vowels_df, left_index=True, right_index=True, indicator=True, how='outer')
注意:此方法仅隐藏警告,未解决潜在性能问题,仅推荐在确认性能无影响的场景下使用。
内容的提问来源于stack exchange,提问作者Gary McGill

