在 Pandas 中绘制带有非常重尾数据的直方图

Posted

技术标签:

【中文标题】在 Pandas 中绘制带有非常重尾数据的直方图【英文标题】:Plotting a histogram in Pandas with very heavy-tailed data 【发布时间】:2014-10-08 19:09:43 【问题描述】:

我经常处理具有非常“长尾”的数据。我想绘制直方图来总结分布,但是当我尝试使用 pandas 时,我最终会得到一个条形图,其中有一个巨大的可见条,而其他所有内容都是不可见的。

这是我正在使用的系列的一个示例。因为它很长,所以我使用了 value_counts(),所以它适合这个页面。

In [10]: data.value_counts.sort_index()

Out[10]:
0          8012
25         3710
100       10794
200       11718
300        2489
500        7631
600          34
700         115
1000       3099
1200       1766
1600         63
2000       1538
2200         41
2500        208
2700       2138
5000        515
5500        201
8800         10
10000        10
10900       465
13000         9
16200        74
20000       518
21500        65
27000        64
53000        82
56000         1
106000       35
530000        3

我猜测答案涉及以某种方式将不太常见的结果分成更大的组(53000、56000、106000 和 53000 到一组 >50000 等),并且还更改 y 索引以表示百分比出现次数而不是绝对次数。但是,我不明白我将如何自动执行此操作。

【问题讨论】:

【参考方案1】:
import pandas as pd
from matplotlib import pyplot as plt
import numpy as np


mydict = 0: 8012,25: 3710,100: 10794,200: 11718,300: 2489,500: 7631,600: 34,700: 115,1000: 3099,1200: 1766,1600: 63,2000: 1538,2200: 41,2500: 208,2700: 2138,5000: 515,5500: 201,8800: 10,10000: 10,10900: 465,13000: 9,16200: 74,20000: 518,21500: 65,27000: 64,53000: 82,56000: 1,106000: 35,530000: 3
mylist = []

for key in mydict:
for e in range(mydict[key]):
    mylist.insert(0,key)

df = pd.DataFrame(mylist,columns=['value'])
df2 = df[df.value <= 5000]

绘制为条形:

fig = df.value.value_counts().sort_index().plot(kind="bar")
plt.savefig("figure.png")

作为直方图(限制为 5000 及以下的值 > 97% 的数据): 我喜欢使用 linspace 来控制存储桶。

df2 = df[df.value <= 5000]
df2.hist(bins=np.linspace(0,5000,101))
plt.savefig('hist1')

编辑:将 np.linspace(0,5000,100) 更改为 np.linspace(0,5000,101) 并更新直方图。

【讨论】:

我不完全确定我是如何偶然发现只是在 value_counts() 上尝试了一个普通的条形图。我想我会把这个归档在“试图超越自己”下。谢谢。【参考方案2】:

使用 cumsum() 方法是过滤尾部的一种有点自动化的方法。 这样您就可以通过编程方式找到仅出现少量观察的索引:

from io import StringIO
import pandas as pd

data=("""0          8012
25         3710
100       10794
200       11718
300        2489
500        7631
600          34
700         115
1000       3099
1200       1766
1600         63
2000       1538
2200         41
2500        208
2700       2138
5000        515
5500        201
8800         10
10000        10
10900       465
13000         9
16200        74
20000       518
21500        65
27000        64
53000        82
56000         1
106000       35
530000        3
""")
d=StringIO(data)

df = pd.read_csv(d,sep='\s+',names=['value','count'],index_col='value')
total=df['count'].sum()
df2 = df[ df['count'].cumsum()/total < 0.98 ]
print(df2)

这会留下 89% 的值并丢弃其余的值。

输出是:

       count
value       
0       8012
25      3710
100    10794
200    11718
300     2489
500     7631
600       34
700      115
1000    3099
1200    1766
1600      63
2000    1538
2200      41
2500     208
2700    2138
5000     515
5500     201
8800      10
10000     10

然后你可以用你喜欢的任何方式进行绘图。

【讨论】:

以上是关于在 Pandas 中绘制带有非常重尾数据的直方图的主要内容,如果未能解决你的问题,请参考以下文章

绘制一个非常大的 pyspark 列的直方图

如何在 Pandas 中使用预聚合数据绘制直方图?

想要将 Pandas 数据框绘制为具有 log10 比例 x 轴的多个直方图

分别绘制所有 pandas 数据框列

Python中Pandas/Matplotlib中直方图和密度的叠加

使用 matplotlib 在一个子图中绘制来自 pandas DataFrame 的两个直方图