2010-01-27 6 views
11

Что такое хороший способ численных значений bin в определенном диапазоне? Например, предположим, что у меня есть список значений, и я хочу, чтобы они помещали их в N бункеров по их диапазону. Прямо сейчас, я делаю что-то вроде этого:Назначение точек на ящики

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

как примечание стороны: я более чем готов использовать matplotlib в дополнение к scipy/numpy, если он имеет эту функциональность. Я думаю, что функции, такие как «hist», должны делать что-то подобное, за исключением того, что я не ищу никаких заговоров. – user248237dfsf

ответ

21

numpy.histogram() делает именно то, что вы хотите.

Функция подписи:

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

Мы в основном заинтересованы в a и bins. 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.

Edit: Вы хотите знать, индекс в ваших закромах каждого элемента. Для этого вы можете использовать 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

+7

О, тогда вы должны посмотреть на 'numpy.digitize()'. –

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» представляет собой 1d массив индексов состоит из целочисленных значений из 0 до 4, соответствующие пяти ячейкам - назначение бинов для каждого из 30 исходных точек в матрице «данных» выше.

+0

Я не могу понять этот ответ очень хорошо, вы можете объяснить это лучше? –