比 'query' 到 select MultiIndexed 行更方便的方法,通过索引级别的名称指定部分标签?
A more convenient way, than 'query', to select MultiIndexed rows, designating partial labels by the name of their index levels?
假设您有很多命名的索引级别——我将在此处显示 4 个,但发挥您的想象力:
midx = pd.MultiIndex.from_product([['A0','A1'], ['B0','B1'],['C0','C1'],['D0','D1']],names=['quack','woof','honk','snarf'])
dfmi = pd.DataFrame(np.arange(32).reshape((len(midx), len(columns))),index=midx, columns=columns)
dfmi
foo bar
quack woof honk snarf
A0 B0 C0 D0 0 1
D1 2 3
C1 D0 4 5
D1 6 7
B1 C0 D0 8 9
D1 10 11
C1 D0 12 13
D1 14 15
A1 B0 C0 D0 16 17
D1 18 19
C1 D0 20 21
D1 22 23
B1 C0 D0 24 25
D1 26 27
C1 D0 28 29
D1 30 31
然后,在这条线上的某个地方,您忘记了名称 'snarf' 与哪个级别相关联,甚至忘记了有多少级别,您想要执行以下操作:
dfmi[dfmi.snarf=='D1']
除了 DataFrame 很大所以保留另一个,reset_index
ed 副本会花费太多 space 而且它会很慢,而且,因为懒惰,你不想去查找它,并且您不想使用 query
:
深入研究另一种语法
dfmi.query('snarf'=='D1')
糟糕!
dfmi.query("'snarf'=='D1'")
再次糟糕!
dfmi.query("snarf=='D1'")
foo bar
quack woof honk snarf
A0 B0 C0 D1 2 3
C1 D1 6 7
B1 C0 D1 10 11
C1 D1 14 15
A1 B0 C0 D1 18 19
C1 D1 22 23
B1 C0 D1 26 27
C1 D1 30 31
终于!
不确定是否更方便,但是基于字符串的查询的一种替代方法是使用 index.get_level_values
:
dfmi[dfmi.index.get_level_values('snarf') == 'D1']
foo bar
quack woof honk snarf
A0 B0 C0 D1 2 3
C1 D1 6 7
B1 C0 D1 10 11
C1 D1 14 15
A1 B0 C0 D1 18 19
C1 D1 22 23
B1 C0 D1 26 27
C1 D1 30 31
如果我们要按名称在给定级别内查找相应的值(相等比较),那么 xs
可以工作:
dfmi.xs('D1', level='snarf', drop_level=False)
foo bar
quack woof honk snarf
A0 B0 C0 D1 2 3
C1 D1 6 7
B1 C0 D1 10 11
C1 D1 14 15
A1 B0 C0 D1 18 19
C1 D1 22 23
B1 C0 D1 26 27
C1 D1 30 31
您可以只保留索引的副本
inds = dfmi.index.to_frame()
dfmi[inds.snarf == "D1"]
# foo bar
# quack woof honk snarf
# A0 B0 C0 D1 2 3
# C1 D1 6 7
# B1 C0 D1 10 11
# C1 D1 14 15
# A1 B0 C0 D1 18 19
# C1 D1 22 23
# B1 C0 D1 26 27
# C1 D1 30 31
您还可以使用:
df = df[df.index.isin(['D1'], level='snarf')]
输出:
foo bar
quack woof honk snarf
A0 B0 C0 D1 2 3
C1 D1 6 7
B1 C0 D1 10 11
C1 D1 14 15
A1 B0 C0 D1 18 19
C1 D1 22 23
B1 C0 D1 26 27
C1 D1 30 31
假设您有很多命名的索引级别——我将在此处显示 4 个,但发挥您的想象力:
midx = pd.MultiIndex.from_product([['A0','A1'], ['B0','B1'],['C0','C1'],['D0','D1']],names=['quack','woof','honk','snarf'])
dfmi = pd.DataFrame(np.arange(32).reshape((len(midx), len(columns))),index=midx, columns=columns)
dfmi
foo bar
quack woof honk snarf
A0 B0 C0 D0 0 1
D1 2 3
C1 D0 4 5
D1 6 7
B1 C0 D0 8 9
D1 10 11
C1 D0 12 13
D1 14 15
A1 B0 C0 D0 16 17
D1 18 19
C1 D0 20 21
D1 22 23
B1 C0 D0 24 25
D1 26 27
C1 D0 28 29
D1 30 31
然后,在这条线上的某个地方,您忘记了名称 'snarf' 与哪个级别相关联,甚至忘记了有多少级别,您想要执行以下操作:
dfmi[dfmi.snarf=='D1']
除了 DataFrame 很大所以保留另一个,reset_index
ed 副本会花费太多 space 而且它会很慢,而且,因为懒惰,你不想去查找它,并且您不想使用 query
:
dfmi.query('snarf'=='D1')
糟糕!
dfmi.query("'snarf'=='D1'")
再次糟糕!
dfmi.query("snarf=='D1'")
foo bar
quack woof honk snarf
A0 B0 C0 D1 2 3
C1 D1 6 7
B1 C0 D1 10 11
C1 D1 14 15
A1 B0 C0 D1 18 19
C1 D1 22 23
B1 C0 D1 26 27
C1 D1 30 31
终于!
不确定是否更方便,但是基于字符串的查询的一种替代方法是使用 index.get_level_values
:
dfmi[dfmi.index.get_level_values('snarf') == 'D1']
foo bar
quack woof honk snarf
A0 B0 C0 D1 2 3
C1 D1 6 7
B1 C0 D1 10 11
C1 D1 14 15
A1 B0 C0 D1 18 19
C1 D1 22 23
B1 C0 D1 26 27
C1 D1 30 31
如果我们要按名称在给定级别内查找相应的值(相等比较),那么 xs
可以工作:
dfmi.xs('D1', level='snarf', drop_level=False)
foo bar
quack woof honk snarf
A0 B0 C0 D1 2 3
C1 D1 6 7
B1 C0 D1 10 11
C1 D1 14 15
A1 B0 C0 D1 18 19
C1 D1 22 23
B1 C0 D1 26 27
C1 D1 30 31
您可以只保留索引的副本
inds = dfmi.index.to_frame()
dfmi[inds.snarf == "D1"]
# foo bar
# quack woof honk snarf
# A0 B0 C0 D1 2 3
# C1 D1 6 7
# B1 C0 D1 10 11
# C1 D1 14 15
# A1 B0 C0 D1 18 19
# C1 D1 22 23
# B1 C0 D1 26 27
# C1 D1 30 31
您还可以使用:
df = df[df.index.isin(['D1'], level='snarf')]
输出:
foo bar
quack woof honk snarf
A0 B0 C0 D1 2 3
C1 D1 6 7
B1 C0 D1 10 11
C1 D1 14 15
A1 B0 C0 D1 18 19
C1 D1 22 23
B1 C0 D1 26 27
C1 D1 30 31