我正在使用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
所以我的问题是:是什么原因导致此警告?我如何人为地诱发它?
答案 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)效率很低。它还将返回数据的副本,而不是视图:
根据它们,您可能需要确保索引正确排序。