Python:相对于列索引级别1,保留pandas.multiindex的最后n列

问题描述

我有一个pd.DataFrame,其中包含两级列。我需要保留n的最后level 1列并删除所有以前的列。 level 0的所有列中的列数不一定相等。

df = pd.DataFrame(np.random.randint(low=1,high=5,size=(4,12)))
df.columns = pd.MultiIndex.from_product([[1,2,3],['A','B','C','D']])
df.drop((2,'A'),axis = 1,inplace = True)
df.drop((3,'C'),inplace = True)

   1           2        3   
   A  B  C  D  B  C  D  B  D
0  3  1  4  3  4  2  4  4  4
1  4  1  4  1  1  2  4  1  1
2  3  4  3  2  3  4  3  3  1
3  2  4  4  1  4  1  1  2  3

预期结果:

   1     2     3   
   C  D  C  D  B  D
0  4  3  2  4  4  4
1  4  1  2  4  1  1
2  3  2  4  3  3  1
3  4  1  1  1  2  3

解决方法

ascending=False的{​​{3}}与MultiIndex的反面计数器一起使用,并过滤GroupBy.cumcount中的最后2列,同样cumcount失败,且水平为列,因此添加了DataFrame.loc

df = df.loc[:,df.columns.to_frame().groupby(level=0).cumcount(ascending=False) < 2]
print (df)
   1     2     3   
   C  D  C  D  B  D
0  4  4  2  1  3  3
1  1  1  2  1  4  2
2  1  1  2  3  4  2
3  4  3  1  3  4  4

详细信息

print (df.columns.to_frame().groupby(level=0).cumcount(ascending=False))
1  A    3
   B    2
   C    1
   D    0
2  B    2
   C    1
   D    0
3  B    1
   D    0
dtype: int64

print (df.columns.to_frame().groupby(level=0).cumcount(ascending=False) < 2)
1  A    False
   B    False
   C     True
   D     True
2  B    False
   C     True
   D     True
3  B     True
   D     True
dtype: bool

另一个方法是过滤最后一列,然后按MultiIndex.to_frame进行过滤:

df = df.loc[:,df.columns.isin(df.columns.to_frame().groupby(level=0).tail(2).index)]
print (df)
   1     2     3   
   C  D  C  D  B  D
0  3  1  3  2  1  1
1  3  2  4  2  3  1
2  2  4  3  3  1  3
3  1  3  4  1  3  3
,

遍历各列以仅保留所需的列:

from collections import defaultdict
from itertools import chain

d = defaultdict(list)
for k,v in df.columns:
    d[k].append((k,v))

#assumption is you need the last two columns,so negative indexing :
columns = list(chain.from_iterable(value[-2:] for key,value in d.items()))

df.loc[:,columns]

        1       2       3
    C   D   C   D   B   D
0   4   3   2   4   4   4
1   4   1   2   4   1   1
2   3   2   4   3   3   1
3   4   1   1   1   2   3