2010-01-27 98 views
11

將數值分類到一定範圍內的好方法是什麼?例如,假設我有一個值列表,並且我想按它們的範圍將它們分成N個bin。現在,我做這樣的事情:將點分配給垃圾桶

from scipy import * 
num_bins = 3 # number of bins to use 
values = # some array of integers... 
min_val = min(values) - 1 
max_val = max(values) + 1 
my_bins = linspace(min_val, max_val, num_bins) 
# assign point to my bins 
for v in values: 
    best_bin = min_index(abs(my_bins - v)) 

其中min_index返回最小值的索引。這個想法是,你可以通過查看它與之之間的最小差異來確定點落入的點。

但我認爲這有奇怪的邊緣情況。我所尋找的是垃圾桶的良好表現,理想的那些被半閉半開(這樣沒有指定一個點兩個塊的方式),即

bin1 = [x1, x2) 
bin2 = [x2, x3) 
bin3 = [x3, x4) 
etc... 

什麼是一個好辦法在Python中使用numpy/scipy來做到這一點?我只關心分箱整數值。

非常感謝您的幫助。

+0

作爲一個方面說明:除了scipy/numpy,如果它具有此功能,我更願意使用matplotlib。我想像'hist'這樣的函數必須做這樣的事情,除了這裏我不想要任何繪圖。 – user248237dfsf 2010-01-27 03:55:58

回答

21

numpy.histogram()完全符合你的要求。

函數簽名是:

numpy.histogram(a, bins=10, range=None, normed=False, weights=None, new=None) 

我們在abins最感興趣。 a是需要分箱的輸入數據。 bins可以是多個分檔(您的num_bins),或者它可以是表示分檔邊緣(半開放)的一系列標量。

import numpy 
values = numpy.arange(10, dtype=int) 
bins = numpy.arange(-1, 11) 
freq, bins = numpy.histogram(values, bins) 
# freq is now [0 1 1 1 1 1 1 1 1 1 1] 
# bins is unchanged 

引述documentation

除了最後(右側最)斌是半開。換句話說,如果bins是:

[1, 2, 3, 4] 

然後第一二進制值是[1, 2)(包括1,但不包括2)和第二[2, 3)。最後一個垃圾桶,但是,是[3, 4],其中包括 4.

編輯:你想知道你的每一個元素的箱索引。爲此,您可以使用numpy.digitize()。如果您的箱子將不可或缺,您也可以使用numpy.bincount()

>>> values = numpy.random.randint(0, 20, 10) 
>>> values 
array([17, 14, 9, 7, 6, 9, 19, 4, 2, 19]) 
>>> bins = numpy.linspace(-1, 21, 23) 
>>> bins 
array([ -1., 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 
     10., 11., 12., 13., 14., 15., 16., 17., 18., 19., 20., 
     21.]) 
>>> pos = numpy.digitize(values, bins) 
>>> pos 
array([19, 16, 11, 9, 8, 11, 21, 6, 4, 21]) 

由於間隔是在上限開,指數是正確的:

>>> (bins[pos-1] == values).all() 
True 
>>> import sys 
>>> for n in range(len(values)): 
...  sys.stdout.write("%g <= %g < %g\n" 
...    %(bins[pos[n]-1], values[n], bins[pos[n]])) 
17 <= 17 < 18 
14 <= 14 < 15 
9 <= 9 < 10 
7 <= 7 < 8 
6 <= 6 < 7 
9 <= 9 < 10 
19 <= 19 < 20 
4 <= 4 < 5 
2 <= 2 < 3 
19 <= 19 < 20 
+1

感謝您的回答 - 但我認爲直方圖仍然與我想要的不同。我對任何垃圾箱的頻率都不感興趣,我只想知道每個點都屬於哪個垃圾箱。似乎直方圖不會返回這些信息,對吧? – user248237dfsf 2010-01-27 04:07:26

+7

哦,那你應該看看'numpy.digitize()'。 – 2010-01-27 04:12:11

1

此使用廣播是相當簡單的在numpy的 - 我下面的例子是四行代碼(不計前兩行以創建二進制位和數據點,這將當然通常提供。)

import numpy as NP 
# just creating 5 bins at random, each bin expressed as (x, y, z) although, this code 
# is not limited by bin number or bin dimension 
bins = NP.random.random_integers(10, 99, 15).reshape(5, 3) 
# creating 30 random data points 
data = NP.random.random_integers(10, 99, 90).reshape(30, 3) 
# for each data point i want the nearest bin, but before i can generate a distance 
# matrix, i need to 'conform' the array dimensions 
# 'broadcasting' is an excellent and concise way to do this 
bins = bins[:, NP.newaxis, :] 
data2 = data[NP.newaxis, :, :] 
# now i can calculate the distance matrix 
dist_matrix = NP.sqrt(NP.sum((data - bins)**2, axis=-1)) 
bin_assignments = NP.argmin(dist_matrix, axis=0) 

「bin_assignments」是指數的一維數組從包括整數值的0到4,對應於上面的'數據'矩陣中的30個原始點中的每一個的倉位分配。

+0

我無法理解這個答案,你能解釋得更好嗎? – 2016-11-23 09:55:19