【问题标题】:Pandas bar plot with binned range带有分箱范围的 Pandas 条形图
【发布时间】:2017-08-17 17:51:04
【问题描述】:

有没有办法将连续数据分箱成预定义的间隔来创建条形图?例如,

In[1]: df
Out[1]: 
0      0.729630
1      0.699620
2      0.710526
3      0.000000
4      0.831325
5      0.945312
6      0.665428
7      0.871845
8      0.848148
9      0.262500
10     0.694030
11     0.503759
12     0.985437
13     0.576271
14     0.819742
15     0.957627
16     0.814394
17     0.944649
18     0.911111
19     0.113333
20     0.585821
21     0.930131
22     0.347222
23     0.000000
24     0.987805
25     0.950570
26     0.341317
27     0.192771
28     0.320988
29     0.513834

231    0.342541
232    0.866279
233    0.900000
234    0.615385
235    0.880597
236    0.620690
237    0.984375
238    0.171429
239    0.792683
240    0.344828
241    0.288889
242    0.961686
243    0.094402
244    0.960526
245    1.000000
246    0.166667
247    0.373494
248    0.000000
249    0.839416
250    0.862745
251    0.589873
252    0.983871
253    0.751938
254    0.000000
255    0.594937
256    0.259615
257    0.459916
258    0.935065
259    0.969231
260    0.755814

而不是简单的直方图:

df.hist()

我需要创建一个条形图,其中每个条形图将计算预定义范围内的实例数。 例如,下面的图应该有三个条形图,点数分别为:[0 0.35]、[0.35 0.7] [0.7 1.0]

编辑

非常感谢您的回答。另一个问题,如何订购垃圾箱? 例如,我得到以下结果:

In[349]: out.value_counts()
Out[349]:  
[0, 0.001]      104
(0.001, 0.1]     61
(0.1, 0.2]       32
(0.2, 0.3]       20
(0.3, 0.4]       18
(0.7, 0.8]        6
(0.4, 0.5]        6
(0.5, 0.6]        5
(0.6, 0.7]        4
(0.9, 1]          3
(0.8, 0.9]        2
(1, 1.001]        0

如您所见,最后三个 bin 没有排序。如何根据“类别”或我的垃圾箱对数据框进行排序?

编辑 2

刚刚找到解决方法,只需使用'reindex()'即可:

In[355]: out.value_counts().reindex(out.cat.categories)
Out[355]: 
[0, 0.001]      104
(0.001, 0.1]     61
(0.1, 0.2]       32
(0.2, 0.3]       20
(0.3, 0.4]       18
(0.4, 0.5]        6
(0.5, 0.6]        5
(0.6, 0.7]        4
(0.7, 0.8]        6
(0.8, 0.9]        2
(0.9, 1]          3
(1, 1.001]        0

【问题讨论】:

    标签: python pandas histogram bar-chart


    【解决方案1】:

    您可以使用pd.cut 将值划分到与每个区间对应的箱中,然后使用pd.value_counts 获取每个区间的总计数。稍后绘制条形图,另外将 X 轴刻度标签替换为该特定刻度所属的类别名称。

    out = pd.cut(s, bins=[0, 0.35, 0.7, 1], include_lowest=True)
    ax = out.value_counts(sort=False).plot.bar(rot=0, color="b", figsize=(6,4))
    ax.set_xticklabels([c[1:-1].replace(","," to") for c in out.cat.categories])
    plt.show()
    


    如果您希望 Y 轴显示为相对百分比,请将频率计数归一化并将该结果乘以 100。

    out = pd.cut(s, bins=[0, 0.35, 0.7, 1], include_lowest=True)
    out_norm = out.value_counts(sort=False, normalize=True).mul(100)
    ax = out_norm.plot.bar(rot=0, color="b", figsize=(6,4))
    ax.set_xticklabels([c[1:-1].replace(","," to") for c in out.cat.categories])
    plt.ylabel("pct")
    plt.show()
    

    【讨论】:

    • 如果我需要标准化情节? (垂直轴应该是百分比而不是频率。类似于 .hist() 中的 'normed=True'
    • 我得到 TypeError: 'pandas._libs.interval.Interval' object is not subscriptable 尝试更改刻度标签时
    • @famargar:如果您使用的版本 >= 0.20.0,那么旧的切片方式将无法使用,因为它现在已成为 IntervalIndex,它有自己的 dtype 并且不支持索引。因此,最好的做法是利用属性(左/右)来定义 X 轴刻度标签的间隔。
    • 感谢您的回答。对上述代码稍作改动 -> str(c)[1:-1].replace(...)
    【解决方案2】:

    你可以使用 pd.cut

    bins = [0,0.35,0.7,1]
    df = df.groupby(pd.cut(df['val'], bins=bins)).val.count()
    df.plot(kind='bar')
    

    【讨论】:

      【解决方案3】:

      您可以考虑使用 matplotlib 绘制直方图。与 pandas 的 hist 函数不同,matplotlib.pyplot.hist 接受一个数组作为 bin 的输入。

      import numpy as np; np.random.seed(0)
      import matplotlib.pyplot as plt
      import pandas as pd
      
      x = np.random.rand(120)
      df = pd.DataFrame({"x":x})
      
      bins= [0,0.35,0.7,1]
      plt.hist(df.values, bins=bins, edgecolor="k")
      plt.xticks(bins)
      
      plt.show()
      

      【讨论】:

      • 这个方法在这里不那么冗长,应该作为主要答案。
      • 当前 pandas 1.3.3 和可能更旧的 pandas.hist() 确实接受 bin 序列:(...)如果 bins 是一个序列,则给出 bin 边缘,包括第一个 bin 的左边缘和右边缘最后一个 bin 的边缘。在这种情况下,bins 原封不动地返回。
      • 可能是一个菜鸟问题:pandas 中的默认模式不是使用 mathplotlib 吗?
      猜你喜欢
      • 2020-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 2021-08-12
      • 2021-09-19
      • 2017-03-18
      相关资源
      最近更新 更多