pandas 将.loc用于带有MultIndex的DataFrame的级别子集

7hiiyaii  于 2023-11-15  发布在  其他
关注(0)|答案(2)|浏览(84)

给定一个具有3个级别的multiindex的框架:

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与前两个级别的索引列表:

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])更清晰的东西来获得预期的结果?

z9zf31ra

z9zf31ra1#

loc与MultiIndex期望相同的级别,解决方法可能是将额外的级别临时设置为列:

levels = df.index.names.difference(idx.names)

out = df.reset_index(levels).loc[idx].set_index(levels, append=True)

字符串
join

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

2g32fytz

2g32fytz2#

将索引视为元组列表并传递到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

相关问题