识别MultiIndex的运行长度

时间:2015-04-11 16:22:41

标签: python pandas

给出像这样的熊猫MultiIndex:

pd.Index([['A', 'A', 'A', 'B', 'B', 'C'],
          ['W', 'W', 'X', 'X', 'Y', 'Z']])

什么是识别每个级别的运行长度的有效方法?我期待的结果是:

('Level 1',     # Under level 1
    ('A', 3),   #   A is repeated thrice
    ('B', 2),   #   followed by B, twice
    ('C', 1),), #   and then by C, once
('Level 2',     # Under level 2
    ('W', 2),   #   W is repeated twice
    ('X', 1),   #   X is split between A (once)
    ('X', 1),   #   ... and B (once)
    ('Y', 1),   #   followed by Y, once
    ('Z', 1),   #   and then by Z, once
)

顺便提一下,这与Pandas何时格式化MultiIndex相同 呈现为HTML。但是,来源(core/format.py - HTMLFormatter._write_header)涉及循环并且效率较低 比我喜欢。

4 个答案:

答案 0 :(得分:2)

这是另一种方式,这可能是最简单的方法,可以轻松推广到更多维度:

idx = pd.Index([['A', 'A', 'A', 'B', 'B', 'C'],
                ['W', 'W', 'X', 'X', 'Y', 'Z']])

df = pd.DataFrame( np.ones(len(idx[0])), index=[idx[0],idx[1]] )

df.groupby(level=[0]).count()

   0
A  3
B  2
C  1

df.groupby(level=[0,1]).count()

     0
A W  2
  X  1
B X  1
  Y  1
C Z  1

答案 1 :(得分:1)

已编辑以处理唯一性方面)

与@Primer一样粗略的想法,我只是让它更简单一些。对于第一级,这应该和你一样高效,我想:

pd.Series(idx[0]).value_counts()

A    3
B    2
C    1

输出也是一个系列,所以你有很多选项可以显示或转换成字典等。

第二级有点难度(因为计数需要结合第一级来衡量唯一性)。这里的索引有点难看,但确实展示了两个层次如何结合在一起:

ser = pd.Series( [ i+j for i,j in zip( idx[0], idx[1] ) ] ).value_counts()

AW    2
CZ    1
BY    1
BX    1
AX    1

您可能更喜欢显示更多内容:

pd.Series( ser.values, index=ser.reset_index()['index'].str[1:] )

index
W    2
Z    1
Y    1
X    1
X    1

答案 2 :(得分:1)

尝试使用Counter。它非常有效。

第一行代码使用list comprehension创建每个级别的列表以及唯一元素及其计数: [[('A',3),('C',1),('B',2)],[('Y',1),('X',2),('Z',1 ),('W',2)]]

第二行在每个子列表的开头插入级别(从1开始而不是零)。

第三行将列表转换为元组以匹配您想要的输出。

from collections import Counter

result = [Counter(idx[i]).items() for i in range(len(idx))]

[result[i].insert(0, 'Level {0}'.format(i+1)) for i in range(len(idx))]

result = tuple(tuple(result[i]) for i in range(len(result)))

>>> result
(('Level 1', ('A', 3), ('C', 1), ('B', 2)),
 ('Level 2', ('Y', 1), ('X', 2), ('Z', 1), ('W', 2)))

计数器返回一个无序字典,然后将其转换为一个列表。根据您的需要,您可能需要对其进行排序。

如果是这样,请在步骤1和2之间插入:

[result[i].sort() for i in range(len(result))]

答案 3 :(得分:0)

这是一种方式:

ind = pd.MultiIndex.from_arrays([['A', 'A', 'A', 'B', 'B', 'C'],
          ['W', 'W', 'X', 'X', 'Y', 'Z']])
df = pd.DataFrame(index=ind).reset_index()
df.apply(pd.Series.value_counts).fillna(0)

产生:

   level_0  level_1
A        3        0
B        2        0
C        1        0
W        0        2
X        0        2
Y        0        1
Z        0        1