Pandas多层DataFrame索引lexsort警告差异原因及无排序消警方案
关于Pandas多级列索引的性能警告问题
背景
通过以下代码创建带多级列索引的Pandas DataFrame:
import numpy as np import pandas as pd N = 3 rangeN = list(range(1, N + 1)) index = pd.MultiIndex.from_product( [rangeN, rangeN], names=["level1", "level2"] ) columns = [ ("col_B", "col_B.1"), ("col_B", "col_B.2"), ] components = range(1, 3) columns += [("col_A", "col_A.1", f"col_A.1.{c}") for c in components] columns += [("col_A", "col_A.2", f"col_A.2.{c}") for c in components] columns = pd.MultiIndex.from_tuples(columns) df = pd.DataFrame(np.random.randint(0, 9, size=(9, 6)), columns=columns, index=index) # df.loc[:, ("col_B", "col_B.2",)] = 7 # Warning # df.loc[:, ("col_B", "col_B.2", slice(None))] = 7 # No warning print("The whole df:\n", df) # No warning print("A subset of the df:\n", df.loc[:, ("col_A")]) # No warning print("A subsubset of the df:\n", df.loc[:, ("col_A", "col_A.1")]) # Warning
运行后发现:索引高层级列df.loc[:, ("col_A")]无警告,而索引更深层级df.loc[:, ("col_A", "col_A.1")]触发PerformanceWarning: indexing past lexsort depth may impact performance。
问题
- 为何部分层级索引触发lexsort警告,部分层级却不?
- 因需保留当前列顺序,无法对数组排序,有无无需排序的消警方法?若没有,是否可通过临时排序再恢复原列顺序的技巧消除警告?
解答
1. 警告触发的差异原因
Pandas的多级索引依赖字典序排序来提升查询效率,如果索引未按字典序排序,当查询的层级深度超过了索引已排序的层级数(即lexsort depth),就会触发性能警告:
- 查询
df.loc[:, ("col_A")]时,只需要匹配第一层级的col_A,Pandas无需跨层级做复杂排序检查,直接遍历第一层级即可完成匹配,因此不会触发警告。 - 查询
df.loc[:, ("col_A", "col_A.1")]时,需要同时匹配前两个层级。由于你的列索引整体未按字典序排列(col_B列在col_A列之前,而字典序中col_A应优先于col_B),Pandas无法利用排序后的索引结构快速定位,只能遍历所有列逐一匹配,因此触发性能警告。
2. 消警方法
无需排序的消警方法
直接通过warnings模块过滤该性能警告,完全保留原列顺序:
import warnings from pandas.errors import PerformanceWarning # 关闭特定的性能警告 warnings.filterwarnings("ignore", category=PerformanceWarning)
临时排序再恢复原顺序的技巧
如果不想关闭警告,可以临时对列索引排序,完成查询后再恢复原顺序:
# 保存原始列顺序 original_columns = df.columns.copy() # 临时对列索引按字典序排序 df_sorted = df.sort_index(axis=1) # 执行查询,此时不会触发警告 target_subset = df_sorted.loc[:, ("col_A", "col_A.1")] # 恢复原DataFrame的列顺序 df = df[original_columns] # 如果需要子集保持原列顺序,筛选原始顺序中属于该子集的列 subset_original_order = [col for col in original_columns if col[:2] == ("col_A", "col_A.1")] target_subset = target_subset[subset_original_order]
内容的提问来源于stack exchange,提问作者Tfovid
相关产品推荐
相关产品推荐

