Python:如何使用大小相等的容器制作直方图

Python:如何使用大小相等的容器制作直方图,python,histogram,spacing,binning,Python,Histogram,Spacing,Binning,我有一组数据,想做一个柱状图。我需要垃圾箱具有相同的大小,这意味着它们必须包含相同数量的对象,而不是更常见的(numpy.histogram)等间距垃圾箱的问题。 这自然会以垃圾箱的宽度为代价,而这种宽度可能会有所不同 我将指定所需箱子的数量和数据集,以获得箱子的边缘 Example: data = numpy.array([1., 1.2, 1.3, 2.0, 2.1, 2.12]) bins_edges = somefunc(data, nbins=3) print(bins_edges)

我有一组数据,想做一个柱状图。我需要垃圾箱具有相同的大小,这意味着它们必须包含相同数量的对象,而不是更常见的(numpy.histogram)等间距垃圾箱的问题。 这自然会以垃圾箱的宽度为代价,而这种宽度可能会有所不同

我将指定所需箱子的数量和数据集,以获得箱子的边缘

Example:
data = numpy.array([1., 1.2, 1.3, 2.0, 2.1, 2.12])
bins_edges = somefunc(data, nbins=3)
print(bins_edges)
>> [1.,1.3,2.1,2.12]
因此,这些箱子都包含2个点,但它们的宽度(0.3、0.8、0.02)不同

有两个限制: -如果一组数据是相同的,那么包含它们的容器可能会更大。 -如果有N个数据且请求了M个存储箱,则如果N%M不是0,则将有N/M个存储箱加上一个存储箱

这段代码是我写过的一些粗制滥造的东西,对于小数据集来说非常有效。如果我有10**9+的分数,并且想要加快流程,该怎么办

  1 import numpy as np
  2 
  3 def def_equbin(in_distr, binsize=None, bin_num=None):
  4 
  5     try:
  6 
  7         distr_size = len(in_distr)
  8 
  9         bin_size = distr_size / bin_num
 10         odd_bin_size = distr_size % bin_num
 11 
 12         args = in_distr.argsort()
 13 
 14         hist = np.zeros((bin_num, bin_size))
 15 
 16         for i in range(bin_num):
 17             hist[i, :] = in_distr[args[i * bin_size: (i + 1) * bin_size]]
 18 
 19         if odd_bin_size == 0:
 20             odd_bin = None
 21             bins_limits = np.arange(bin_num) * bin_size
 22             bins_limits = args[bins_limits]
 23             bins_limits = np.concatenate((in_distr[bins_limits],
 24                                           [in_distr[args[-1]]]))
 25         else:
 26             odd_bin = in_distr[args[bin_num * bin_size:]]
 27             bins_limits = np.arange(bin_num + 1) * bin_size
 28             bins_limits = args[bins_limits]
 29             bins_limits = in_distr[bins_limits]
 30             bins_limits = np.concatenate((bins_limits, [in_distr[args[-1]]]))
 31 
 32         return (hist, odd_bin, bins_limits)
使用您的示例案例(2个点的箱子,共6个数据点):


歪斜分布的更新:

我遇到了与@astabada相同的问题,希望创建每个包含相同数量样本的箱子。当应用@aganders3提出的解决方案时,我发现它对倾斜分布的效果不是特别好。在倾斜数据的情况下(例如有大量零的数据),
stats.mstats.mquantiles
对于预定义数量的分位数,将不能保证每个存储单元中的采样数相等。您将获得如下所示的箱子边缘:

[0. 0. 4. 9.]
在这种情况下,第一个箱子将是空的

为了处理歪斜的情况,我创建了一个函数,该函数调用
stats.mstats.mquantiles
,然后如果样本在某个公差范围内不相等(示例代码中最小样本大小的30%),则动态修改箱子的数量。如果两个箱子之间的样本不相等,则代码将等距分位数的数量减少1,并再次调用
stats.mstats.mquantiles
,直到样本大小相等或只存在一个箱子

我在示例中硬编码了公差,但如果需要,可以将其修改为关键字参数

我还喜欢将等距分位数的数量作为函数的参数,而不是将用户定义的分位数作为
stats.mstats.mquantiles
的参数,以减少意外错误(例如
[0,0.25,0.7,1.]

代码如下:

import numpy as np 
from scipy import stats

def equibins(dat, binnum, **kwargs):
    numin = binnum
    while numin>1.:
        qtls = np.linspace(0.,1.0,num=numin,endpoint=False)
        ebins =stats.mstats.mquantiles(dat,qtls,alphap=kwargs['alpha'],betap=kwargs['beta'])
        allhist, allbin   = np.histogram(dat, bins = ebins)
        if (np.unique(ebins).shape!=ebins.shape or tolerence(allhist,0.3)==False) and numin>2:
            numin= numin-1
            del qtls, ebins
        else:
            numin=0
    return ebins

def tolerence(narray, percent):
    if percent>1.0:
        per = percent/100.
    else:
        per = percent
    lev_tol  = per*narray.min()
    tolerate = np.all(narray[1:]-narray[0]<lev_tol)
    return tolerate
将numpy导入为np
从scipy导入统计信息
def设备(dat、binnum、**kwargs):
numin=binnum
当numin>1时:
qtls=np.linspace(0,1.0,num=nummin,endpoint=False)
ebins=stats.mstats.mquantiles(dat,QTL,alphap=kwargs['alpha'],betap=kwargs['beta']))
allhist,allbin=np.直方图(dat,bins=EBIN)
如果(np.unique(ebins.shape)!=ebins.shape或公差(allhist,0.3)==False)且numin>2:
numin=numin-1
del qtls,ebins
其他:
numin=0
返回息税前利润
def耐受性(纳雷,百分比):
如果百分比>1.0:
per=百分比/100。
其他:
per=百分比
lev_tol=per*narray.min()

allow=np.all(narray[1:]-narray[0]只需对数据进行排序,并按长度将其划分为固定的存储箱!显然,如果样本数不完全除以存储箱数,则永远无法将其划分为完全相同的存储箱

import math
import numpy as np
data = np.array([2,3,5,6,8,5,5,6,3,2,3,7,8,9,8,6,6,8,9,9,0,7,5,3,3,4,5,6,7])
data_sorted = np.sort(data)
nbins = 3
step = math.ceil(len(data_sorted)//nbins+1)
binned_data = []
for i in range(0,len(data_sorted),step):
    binned_data.append(data_sorted[i:i+step])

我还想提到的存在,它以一种相当有效的方式进行了均衡填充装箱

data = np.array([1., 1.2, 1.3, 2.0, 2.1, 2.12])
# parameter q specifies the number of bins
qc = pd.qcut(data, q=3, precision=1)

# bin definition
bins  = qc.categories
print(bins)
>> Index(['[1, 1.3]', '(1.3, 2.03]', '(2.03, 2.1]'], dtype='object')

# bin corresponding to each point in data
codes = qc.codes
print(codes)
>> array([0, 0, 1, 1, 2, 2], dtype=int8)

我可能没有正确地理解这一点,但听起来你最终会遇到一个非常无聊的问题(例如完全扁平化)这样的直方图。你只是想找到数据的一些分位数吗?嗨,你理解得对。因为每个值都是一个星系的大小,所以我可以看看其他属性在每个单独的箱子中的行为。这听起来更像分位数而不是直方图。啊啊,太棒了!我不知道它们被称为分位数,所以我花了很多时间在谷歌上搜索“等间距垃圾箱”和此类似……非常感谢!当你学习一个新术语时,谷歌似乎突然又开始工作了,这不是很好吗?这种情况一直发生在我身上。@champe先生是最棒的。在最近的熊猫版本中,你需要使用
qc.categories
qc.codes
而不是
qc.cat.categories
data = np.array([1., 1.2, 1.3, 2.0, 2.1, 2.12])
# parameter q specifies the number of bins
qc = pd.qcut(data, q=3, precision=1)

# bin definition
bins  = qc.categories
print(bins)
>> Index(['[1, 1.3]', '(1.3, 2.03]', '(2.03, 2.1]'], dtype='object')

# bin corresponding to each point in data
codes = qc.codes
print(codes)
>> array([0, 0, 1, 1, 2, 2], dtype=int8)