为什么我在切片数据框中看到所有原始索引元素?
Why do I see all original index elements in a sliced dataframe?
我有一个像这样的多索引数据框:
import pandas as pd
import numpy as np
df = pd.DataFrame({'ind1': list('aaaaaaaaabbbbbbbbb'),
'ind2': list('cccdddeeecccdddeee'),
'ind3': list(range(3))*6,
'val1': list(range(100, 118)),
'val2': list(range(70, 88))})
df_mult = df.set_index(['ind1', 'ind2', 'ind3'])
val1 val2
ind1 ind2 ind3
a c 0 100 70
1 101 71
2 102 72
d 0 103 73
1 104 74
2 105 75
e 0 106 76
1 107 77
2 108 78
b c 0 109 79
1 110 80
2 111 81
d 0 112 82
1 113 83
2 114 84
e 0 115 85
1 116 86
2 117 87
我现在可以 select 使用 .loc
它的一个子集
df_subs = df_mult.loc[pd.IndexSlice['a', ['c', 'd'], :], :]
这给出了预期的
val1 val2
ind1 ind2 ind3
a c 0 100 70
1 101 71
2 102 72
d 0 103 73
1 104 74
2 105 75
当我打印时
df_subs.index
我明白了
MultiIndex(levels=[[u'a', u'b'], [u'c', u'd', u'e'], [0, 1, 2]],
labels=[[0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1], [0, 1, 2, 0, 1, 2]],
names=[u'ind1', u'ind2', u'ind3'])
为什么级别 0 中还有 b
而不仅仅是 a
?
如果我想将索引的元素用于其他用途,这可能会成为一个问题。然后
df_subs.index.levels[0]
给我
Index([u'a', u'b'], dtype='object', name=u'ind1')
然而,
df_subs.index.get_level_values('ind1').unique()
给我
Index([u'a'], dtype='object', name=u'ind1')
这在我看来不一致。
这是错误还是预期的行为?
有关于 GitHub 围绕此行为 here 的讨论。
简而言之,您看到的级别不是根据您实际观察到的 MultiIndex 中的值计算的 - 在您首次设置 MultiIndex 后,未观察到的级别将通过索引持续存在。这允许在所有视图和某些 MultiIndex 的副本之间共享级别索引,这在内存方面很好 - 即 df_mult
和 df_subs
在内存中共享相同的底层索引。
如果您想重新计算级别以删除未使用的级别并创建新的 MultiIndex,您可以使用 MultiIndex.remove_unused_levels()
.
你的情况
>>> df_subs.index.remove_unused_levels().levels[0]
Index(['a'], dtype='object', name='ind1')
我有一个像这样的多索引数据框:
import pandas as pd
import numpy as np
df = pd.DataFrame({'ind1': list('aaaaaaaaabbbbbbbbb'),
'ind2': list('cccdddeeecccdddeee'),
'ind3': list(range(3))*6,
'val1': list(range(100, 118)),
'val2': list(range(70, 88))})
df_mult = df.set_index(['ind1', 'ind2', 'ind3'])
val1 val2
ind1 ind2 ind3
a c 0 100 70
1 101 71
2 102 72
d 0 103 73
1 104 74
2 105 75
e 0 106 76
1 107 77
2 108 78
b c 0 109 79
1 110 80
2 111 81
d 0 112 82
1 113 83
2 114 84
e 0 115 85
1 116 86
2 117 87
我现在可以 select 使用 .loc
它的一个子集
df_subs = df_mult.loc[pd.IndexSlice['a', ['c', 'd'], :], :]
这给出了预期的
val1 val2
ind1 ind2 ind3
a c 0 100 70
1 101 71
2 102 72
d 0 103 73
1 104 74
2 105 75
当我打印时
df_subs.index
我明白了
MultiIndex(levels=[[u'a', u'b'], [u'c', u'd', u'e'], [0, 1, 2]],
labels=[[0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1], [0, 1, 2, 0, 1, 2]],
names=[u'ind1', u'ind2', u'ind3'])
为什么级别 0 中还有 b
而不仅仅是 a
?
如果我想将索引的元素用于其他用途,这可能会成为一个问题。然后
df_subs.index.levels[0]
给我
Index([u'a', u'b'], dtype='object', name=u'ind1')
然而,
df_subs.index.get_level_values('ind1').unique()
给我
Index([u'a'], dtype='object', name=u'ind1')
这在我看来不一致。
这是错误还是预期的行为?
有关于 GitHub 围绕此行为 here 的讨论。
简而言之,您看到的级别不是根据您实际观察到的 MultiIndex 中的值计算的 - 在您首次设置 MultiIndex 后,未观察到的级别将通过索引持续存在。这允许在所有视图和某些 MultiIndex 的副本之间共享级别索引,这在内存方面很好 - 即 df_mult
和 df_subs
在内存中共享相同的底层索引。
如果您想重新计算级别以删除未使用的级别并创建新的 MultiIndex,您可以使用 MultiIndex.remove_unused_levels()
.
你的情况
>>> df_subs.index.remove_unused_levels().levels[0]
Index(['a'], dtype='object', name='ind1')