python 索引超过lexsort深度可能会影响排序索引的性能

xxhby3vn  于 2022-12-17  发布在  Python
关注(0)|答案(1)|浏览(150)

我有以下索引:

import pandas as pd  # version 1.5.2

idx = pd.MultiIndex.from_product(([str(i) for i in (1, 2, 10, 20, 100, 200)], list('ab'), list('X'))).swaplevel(0,2)
MultiIndex([('X', 'a',   '1'),
            ('X', 'b',   '1'),
            ('X', 'a',   '2'),
            ('X', 'b',   '2'),
            ('X', 'a',  '10'),
            ('X', 'b',  '10'),
            ('X', 'a',  '20'),
            ('X', 'b',  '20'),
            ('X', 'a', '100'),
            ('X', 'b', '100'),
            ('X', 'a', '200'),
            ('X', 'b', '200')],
           )

(this是一个最小的例子,真实的上在第一级也有多个值)
现在我使用idx_sorted = idx.sortlevel([0, 1], sort_remaining=False)[0]在前两个级别上对索引进行排序(最后一个级别保持未排序):

MultiIndex([('X', 'a',   '1'),
            ('X', 'a',   '2'),
            ('X', 'a',  '10'),
            ('X', 'a',  '20'),
            ('X', 'a', '100'),
            ('X', 'a', '200'),
            ('X', 'b',   '1'),
            ('X', 'b',   '2'),
            ('X', 'b',  '10'),
            ('X', 'b',  '20'),
            ('X', 'b', '100'),
            ('X', 'b', '200')],
           )

当我从排序后的索引中选择pd.DataFrame(index=idx_sorted).loc[('X', 'a')]时,会得到PerformanceWarning: indexing past lexsort depth may impact performance.
我的问题是:为什么当我使用一个在两个级别上排序的索引在这两个级别上进行索引时会收到警告?据我所知,我的索引没有超过lexsort深度。
当然,当排序所有三个级别,如idx.sortlevel([0,1], sort_remaining=True)或简单的idx.sortlevel()时,没有警告,但我需要最后一个级别未排序。

更新:注解为Jamiu's answer(注解太长):

较大 Dataframe 的计时:

idx = pd.MultiIndex.from_product(([str(i) for i in range(100)], list('abcde'), list('ABCDE'))).swaplevel(0,2)
df_unsorted =  pd.DataFrame(index=idx)
idx_sorted = idx.sortlevel([0, 1], sort_remaining=False)[0]
df_sorted = pd.DataFrame(index=idx_sorted)

df_sorted.loc[('A', 'a')]                 # 484 µs
df_unsorted.loc[('A', 'a')]               # 506 µs
df_sorted.xs(('A', 'a'), level=[0, 1])    # 907 µs
df_unsorted.xs(('A', 'a'), level=[0, 1])  # 869 µs
  • loc似乎比xs快,尽管有性能警告
  • 选择使用排序或未排序的索引需要相同的时间(无论是locxs)似乎有什么我完全错了吗?
ldfqzlk8

ldfqzlk81#

您看到的警告与panda处理MultiIndex对象上的索引的方式有关。当您将.loc索引器与MultiIndex一起使用时,panda需要对索引的级别进行排序才能执行选择。如果索引有许多级别,则此排序操作的计算开销会很大,因为它需要panda对索引执行完整排序。
若要避免此警告,可以尝试使用.xs方法而不是.loc索引器。.xs方法是专门为编制MultiIndex索引而构造的,它不执行索引的完整排序。

注:

.loc通常比.xs更快,内存效率更高,因为它直接从基础数据结构访问数据,而不是返回新对象,因此尽可能使用.loc是一个好主意。但是,在某些情况下,如果需要基于特定级别的MultiIndex对DataFrame进行切片,.xs可能会很有用。
同样值得注意的是,.loc.xs的相对性能取决于DataFrame的具体实现和数据结构,在某些情况下,.xs可能针对某些操作进行了优化,并且比.loc更快。
在这种情况下,您可能需要使用.xs方法来选择MultiIndex的第一级和第二级等于Xa的行。
示例:

df = pd.DataFrame(index=idx_sorted)
df_subset = df.xs(('X', 'a'), level=[0, 1])

我非常肯定query()方法可以帮助优化。有多大把握?我真的不知道。这取决于你的 Dataframe 的大小。但它可能值得一试。你可以使用query()通过布尔表达式从DataFrame中选择行。例如:

df_sorted.query('index[0] == "A" and index[1] == "a"')
df_unsorted.query('index[0] == "A" and index[1] == "a"')

相关问题