python - 是什么导致 Pandas 出现 "indexing past lexsort depth"警告?

标签 python pandas

我正在使用 df.loc[(key1, key2)] 为大型多索引 Pandas 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

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

最佳答案

TL;DR:您的索引未排序,这会严重影响性能。

使用 df.sort_index() 对 DataFrame 的索引进行排序解决警告并提高性能。


实际上,我已经在我的文章中详细介绍了这一点: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))]

如果你的索引不是唯一的,先添加一个cumcounted级别,

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)

关于python - 是什么导致 Pandas 出现 "indexing past lexsort depth"警告?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54307300/

相关文章:

python - Pandas:如何根据多列的条件将值替换为 np.nan

python - 按字母顺序排序数据框的索引

python - 查找具有非 na 值的列,并使用非 na 列的名称创建第三列填充值

python - 为什么 Python 不使用工作目录以及如何修复它?

Python 和 Beautifulsoup 网页抓取 - 选择具有特定子标签的段落

python - Django 模型分组依据

python - JAX/JIT 与标准 Numpy 性能 : where I am wrong?

python - 无限打印在后台进行异步轮询

python - 将一个数据框附加到另一个具有相同列的数据框的右侧

python - 如何解析 "ValueError: Shape of passed values is (228, 1), indices imply (228, 7)"