提问人:endive1783 提问时间:11/13/2023 更新时间:11/13/2023 访问量:49
将 .loc 与 DataFrame 的级别子集一起使用
Using .loc with on subset of levels from a DataFrame with MultIndex
问:
给定一个具有 3 个多索引级别的数据帧:
import pandas as pd
df = pd.concat({'a': pd.Series([1,2,3,1]),
'b': pd.Series([5,4,3,5]),
'c': pd.Series(range(9,13)),
'd': pd.Series(range(13,17))}, axis=1).set_index(['a', 'b', 'c'])
>>> d
a b c
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16
我想将 loc 与前 2 个级别的索引列表一起使用:
idx = pd.MultiIndex.from_arrays([[1, 2], [5, 4]], names=('a', 'b'))
>>> MultiIndex([(1, 5),
(2, 6)],
names=['a', 'b'])
我尝试将 .loc 与单个索引一起使用:
df.loc[idx[0]]
>>> d
c
9 13
12 16
df.loc[idx[1]]
>>> d
c
10 14
我希望返回与df.loc[idx]
pd.concat([df.loc[i] for i in idx])
>>> d
c
9 13
12 16
10 14
但我回来了df.loc[idx]
ValueError: operands could not be broadcast together with shapes (2,2) (3,) (2,2)
还有什么比获得预期结果更干净的吗?pd.concat([df.loc[i] for i in idx])
答:
3赞
mozway
11/13/2023
#1
具有 MultiIndex 的 loc
需要相同的级别,解决方法是将额外的级别临时设置为列:
levels = df.index.names.difference(idx.names)
out = df.reset_index(levels).loc[idx].set_index(levels, append=True)
或加入
:
out = df.join(pd.DataFrame(index=idx), how='right')
输出:
d
a b c
1 5 9 13
12 16
2 4 10 14
如果您想在此过程中删除/中:a
b
levels = df.index.names.difference(idx.names)
out = df.reset_index(levels).loc[idx].set_index(levels)
艺术
out = df.join(pd.DataFrame(index=idx), how='right').droplevel(idx.names)
输出:
d
c
9 13
12 16
10 14
评论
0赞
endive1783
11/13/2023
我尝试了第一个技巧,发现它很丑,但我喜欢加入选项,谢谢!
1赞
sammywemmy
11/13/2023
#2
将索引视为元组列表并传递给 janitor.select:
# pip install pyjanitor
import janitor
# index sorting is done here
# to avoid performance warning
df.sort_index().select(rows=list(idx))
d
a b c
1 5 9 13
12 16
2 4 10 14
另一种选择是使用字典:
# a safer option would be to use get_level_values
# instead of levels
rows=dict(zip(idx.names, idx.levels))
df.select(rows=rows)
d
a b c
1 5 9 13
12 16
2 4 10 14
另一个选项是:pd.xs
df = df.sort_index()
selected = [df.xs(key=tup, drop_level=False) for tup in idx]
pd.concat(selected)
d
a b c
1 5 9 13
12 16
2 4 10 14
下一个:使用元组进行多索引
评论