如何绘制许多不均匀分布的value_counts?

11
假设我有以下数据:
s2 = pd.Series([1,2,3,4,5,2,3,333,2,123,434,1,2,3,1,11,11,432,3,2,4,3,3,3,54,34,24,2,223,2535334,3,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30000, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2])
s2.value_counts(normalize=True).plot()

我想展示出只有少数数字占据了大多数情况。问题是这些数字将会出现在图表的最左侧,而其他类别的柱状图则会很短。

在真实数据中,x轴将是大约18000种类别的分类变量,其中4%的计数约为10000,然后其余的计数将下降到约为50。

更新:请参见@unutbu的回答。

更新代码时,当尝试使用元组时,我遇到了关于qcut的错误。

TypeError: unsupported operand type(s) for -: 'tuple' and 'tuple'

df = pd.DataFrame({'s1':[1,0,1,0], 's2':[1,0,1,1], 's3':[1,0,1,1], 's4':[0,0,0,1]})
perms = df.apply(tuple, axis=1)
prob = perms.value_counts(normalize=True).reset_index(drop='True')
category_classes = pd.qcut(prob, q=[0, .25, 0.95, 1.], 
                 labels=['bottom 25%', 'mid 70%', 'top 5%'])
prob_groups = prob.groupby(category_classes).sum()
prob_groups.plot(kind='bar')
plt.xticks(rotation=0)
plt.show()
2个回答

27
您可以保持归一化值计数高于某个阈值。然后将低于阈值的值相加并聚合在一起,放入一个称为"其他"的类别中。
选择足够高的阈值,您将能够显示对总体概率分布最重要的贡献者,同时仍然显示以"其他"标记的条中尾部的大小:
import matplotlib.pyplot as plt
import pandas as pd

s2 = pd.Series([1,2,3,4,5,2,3,333,2,123,434,1,2,3,1,11,11,432,3,2,4,3,3,3,54,34,24,2,223,2535334,3,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30000, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2])
prob = s2.value_counts(normalize=True)
threshold = 0.02
mask = prob > threshold
tail_prob = prob.loc[~mask].sum()
prob = prob.loc[mask]
prob['other'] = tail_prob
prob.plot(kind='bar', rot=25)
plt.show()

enter image description here


在柱状图上显示合理数量的分类标签是有限制的。对于一个普通大小的图表来说,3000个标签是远远过多的。此外,期望观众从3000个标签中获取任何含义也可能是不合理的。

图表应该总结数据。而主要观点似乎是4或5%的类别构成了大部分案例。因此,为了强调这一点,可以使用pd.qcut将案例分类到简单的类别中,例如bottom 25%mid 70%top 5%

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

N = 18000
categories = np.arange(N)
np.random.shuffle(categories)
M = int(N*0.04)
prob = pd.Series(np.concatenate([np.random.randint(9000, 11000, size=M),
                      np.random.randint(0, 100, size=N-M), ]), index=categories)
prob /= prob.sum()
category_classes = pd.qcut(prob, q=[0, .25, 0.95, 1.], 
                 labels=['bottom 25%', 'mid 70%', 'top 5%'])
prob_groups = prob.groupby(category_classes).sum()
prob_groups.plot(kind='bar', rot=0)
plt.show()

enter image description here


它们是由二进制数字组成的元组,我正在计算排列。例如(1,0,0,1)。 - user3139545
它是一个52位长的二进制字符串,因此可以有很多种类。 - user3139545
这很完美,但是当列包含元组时,我无法让它正常工作。有什么想法可以让它与元组一起工作吗? - user3139545
更新了代码,加入了最后一部分的拼图,但是无法使用元组来运行qcut。 - user3139545
prob 的定义中,将 .reset_index() 更改为 .reset_index(drop=True)。这将删除索引,使得 prob 仍然是一个 Series 而不是转换成 DataFrame。然后,pd.qcut 将仅应用于概率,而不是也应用于元组。 - unutbu
显示剩余2条评论

-2

只需记录轴(我没有熊猫,但应该类似):

import numpy as np
import matplotlib.pyplot as plt

s2 = np.log([1,2,3,4,5,2,3,333,2,123,434,1,2,3,1,11,11,432,3,2,4,3,3,3,54,34,24,2,223,2535334,3,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30000, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2])
plt.plot(s2)
plt.show()

s2.map(lambda x: str(x)).value_counts(normalize=True).plot(logx=True) - user3139545
你是指Pandas吗? - WY Hsu
1
@WeiYuangHsu 是的,谢谢! - BrutalGames
这不是对所问问题的答案。 - Trenton McKinney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接