是什么原因导致Pandas中出现“索引超过lexsort深度”的警告?

时间:2019-01-22 11:29:31

标签: python pandas

我正在使用df.loc[(key1, key2)]为大型多索引熊猫df建立索引。有时,我得到了一个系列(如预期的那样),但其他时候,我得到了一个数据框。我正在尝试隔离导致后者的情况,但到目前为止,我所看到的只是与收到PerformanceWarning: indexing past lexsort depth may impact performance警告有关。

我想将其复制到此处,但是我无法生成另一种情况给我同样的警告。这是我的尝试:

def random_dates(start, end, n=10):
    start_u = start.value//10**9
    end_u = end.value//10**9
    return pd.to_datetime(np.random.randint(start_u, end_u, n), unit='s')

np.random.seed(0)
df = pd.DataFrame(np.random.random(3255000).reshape(465000,7))  # same shape as my data
df['date'] = random_dates(pd.to_datetime('1990-01-01'), pd.to_datetime('2018-01-01'), 465000)
df = df.set_index([0, 'date'])
df = df.sort_values(by=[3])  # unsort indices, just in case
df.index.lexsort_depth
> 0
df.index.is_monotonic
> False
df.loc[(0.9987185534991936, pd.to_datetime('2012-04-16 07:04:34'))]
# no warning

所以我的问题是:是什么原因导致此警告?我如何人为地诱发它?

2 个答案:

答案 0 :(得分:4)

我实际上已经在我的文章Select rows in pandas MultiIndex DataFrame(在“问题3”下)中对此进行了详细介绍。

要复制,

mux = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    list('tuvwtuvwtuvwtuvw')
], names=['one', 'two'])

df = pd.DataFrame({'col': np.arange(len(mux))}, mux)

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    u      5
    v      6
    w      7
    t      8
c   u      9
    v     10
d   w     11
    t     12
    u     13
    v     14
    w     15

您会注意到第二级未正确排序。

现在,尝试索引特定的横截面:

df.loc[pd.IndexSlice[('c', 'u')]]
PerformanceWarning: indexing past lexsort depth may impact performance.
  # encoding: utf-8

         col
one two     
c   u      9

您将看到与xs相同的行为:

df.xs(('c', 'u'), axis=0)
PerformanceWarning: indexing past lexsort depth may impact performance.
  self.interact()

         col
one two     
c   u      9

docs支持的this timing test I once did似乎表明处理未排序的索引会导致速度变慢—索引是O(N)时间,而它可能/应该是O(1)。

如果在切片之前对索引进行排序,您会注意到其中的区别:

df2 = df.sort_index()
df2.loc[pd.IndexSlice[('c', 'u')]]

         col
one two     
c   u      9


%timeit df.loc[pd.IndexSlice[('c', 'u')]]
%timeit df2.loc[pd.IndexSlice[('c', 'u')]]

802 µs ± 12.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
648 µs ± 20.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

最后,如果您想知道索引是否已排序,请使用MultiIndex.is_lexsorted检查。

df.index.is_lexsorted()
# False

df2.index.is_lexsorted()
# True

关于您如何引发这种行为的问题,仅对索引进行排列就足够了。如果您的索引是唯一的,这将起作用:

df2 = df.loc[pd.MultiIndex.from_tuples(np.random.permutation(df2.index))]

如果索引不是唯一的,请首先添加一个cumcount ed级别,

df.set_index(
    df.groupby(level=list(range(len(df.index.levels)))).cumcount(), append=True) 
df2 = df.loc[pd.MultiIndex.from_tuples(np.random.permutation(df2.index))]
df2 = df2.reset_index(level=-1, drop=True)

答案 1 :(得分:1)

根据pandas advanced indexing (Sorting a Multiindex)

  

在高维对象上,如果其他任何轴具有MultiIndex,则可以按级别对它们进行排序

还有:

  

即使数据没有排序,索引也会起作用,但是(并且会显示PerformanceWarning)效率很低。它还将返回数据的副本,而不是视图:

根据它们,您可能需要确保索引正确排序。