给出像这样的熊猫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
)涉及循环并且效率较低
比我喜欢。
答案 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