我有一组数据,并希望对其进行直方图。我需要这些箱子具有相同的尺寸,我的意思是它们必须包含相同数量的对象,而不是具有等间距<的更常见(numpy.histogram)问题/ em>箱子。 这自然会出现在箱子宽度的费用上,这可能 - 并且通常会 - 不同。
我将指定所需的二进制数和数据集的数量,获得返回的二进制数边缘。
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)是不同的。
有两个限制: - 如果一组数据相同,则包含它们的bin可能更大。 - 如果有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)
答案 0 :(得分:12)
使用您的示例案例(2个点,6个总数据点):
from scipy import stats
bin_edges = stats.mstats.mquantiles(data, [0, 2./6, 4./6, 1])
>> array([1. , 1.24666667, 2.05333333, 2.12])
答案 1 :(得分:3)
我还要提到pandas.qcut
的存在,它以非常有效的方式完成了人口密集的分箱。在你的情况下,它会像
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)
答案 2 :(得分:2)
偏斜发行版的更新:
我遇到了与@astabada相同的问题,想要创建每个包含相同数量样本的箱子。在应用@ aganders3提出的解决方案时,我发现它对于偏斜的分布并没有特别好的效果。在偏斜数据的情况下(例如具有大量零的东西),对于预定数量的分位数stats.mstats.mquantiles
将不保证每个区间中的样本数量相等。您将获得如下所示的bin边缘:
[0. 0. 4. 9.]
在这种情况下,第一个bin将为空。
为了处理偏斜的情况,我创建了一个调用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
答案 3 :(得分: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])