attribuer des points à bacs
Question
Qu'est-ce qu'un bon moyen de valeurs numériques dans une poubelle certaine plage? Par exemple, supposons que j'ai une liste de valeurs et je veux les bin dans des bacs N par leur gamme. En ce moment, je fais quelque chose comme ceci:
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))
où min_index retourne l'indice de la valeur minimale. L'idée est que vous pouvez trouver le bac le point tombe dans en voyant ce bac, il a la plus petite différence avec.
Mais je pense que cela a des cas de pointe étranges. Ce que je cherche est une bonne représentation des bacs, idéalement ceux qui sont à moitié fermée à moitié ouverte (pour qu'il n'y ait aucun moyen d'attribuer un point à deux bacs), i.e..
bin1 = [x1, x2)
bin2 = [x2, x3)
bin3 = [x3, x4)
etc...
ce qui est une bonne façon de le faire en Python, en utilisant numpy / scipy? Je ne suis préoccupé par ici avec binning valeurs entières.
Merci beaucoup pour votre aide.
La solution
numpy.histogram()
fait exactement ce que vous voulez.
La signature de la fonction est la suivante:
numpy.histogram(a, bins=10, range=None, normed=False, weights=None, new=None)
Nous sommes surtout intéressés a
et bins
. a
est les données d'entrée qui doit être mis en cellule. bins
peut être un certain nombre de casiers (votre num_bins
), ou il peut être une séquence de scalaires, qui représentent les bords bin (moitié ouvert).
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
Tout sauf le dernier (le plus droite) bin est semi-ouvert. En d'autres termes, si
bins
est:[1, 2, 3, 4]
alors le premier bac est
[1, 2)
(y compris 1, mais à l'exclusion 2) et le second[2, 3)
. Le dernier bac, cependant, est[3, 4]
, qui comprend 4.
Modifier : Vous voulez connaître l'index dans vos bacs de chaque élément. Pour cela, vous pouvez utiliser numpy.digitize()
. Si vos bacs vont être intégrés, vous pouvez utiliser numpy.bincount()
ainsi.
>>> 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])
Depuis l'intervalle est ouvert sur la limite supérieure, les indices sont corrects:
>>> (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
Autres conseils
Ceci est assez simple en utilisant la diffusion numpy - (. Sans compter deux premières lignes pour créer des bacs et des points de données, qui bien sûr fourni ordinaire) mon exemple ci-dessous est quatre lignes de code
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 » est un tableau 1D d'indices comprenant des valeurs entières de 0 à 4, correspondant aux cinq bacs -. Les affectations de casiers pour chacun des 30 points d'origine dans la matrice « données » ci-dessus