2016-09-08 1 views
4

Je veux une fonction qui peut prendre une série et un ensemble de cases, et arrondir à la poubelle la plus proche. Par exemple:Python: Affectation de # valeurs dans une liste à des cases, en arrondissant

my_series = [ 1, 1.5, 2, 2.3, 2.6, 3] 
def my_function(my_series, bins): 
    ... 

my_function(my_series, bins=[1,2,3]) 
> [1,2,2,3,3,3] 

Cela semble être très proche de ce que Numpy's Digitize est destiné à faire, mais il produit les mauvaises valeurs (astérisques pour de mauvaises valeurs):

np.digitize(my_series, bins= [1,2,3], right=False) 
> [1, 1*, 2, 2*, 2*, 3] 

La raison pour laquelle il est faux est clairement de la documentation:

Chaque indice i revenu est tel que bacs [i-1] < = x < bacs [i] si bin s est en augmentation monotone, ou les cases [i-1]> x> = cases [i] si les cases décroissent de façon monotone. Si les valeurs dans x sont au-delà des limites des cases , 0 ou len (cases) est renvoyé comme approprié. Si le droit est vrai, alors la case de droite est fermée de telle sorte que l'index i est tel que les cases [i-1] < x < = les cases [i] ou les cases [i-1]> = x> les cases [i] `` si les casiers sont respectivement monotones ou décroissants.

Je sorte de se rapprocher de ce que je veux si je rentre dans les valeurs décroissantes et « droite » à vrai ...

np.digitize(my_series, bins= [3,2,1], right=True) 
> [3, 2, 2, 1, 1, 1] 

mais je vais devoir penser à un manière d'inverser de façon méthodique l'attribution de numéro la plus faible (1) avec l'attribution de numéro la plus élevée (3). C'est simple quand il n'y a que 3 bacs, mais ça va devenir plus poilu quand le nombre de bacs sera plus long ... il doit y avoir une façon plus élégante de faire tout ça.

+0

Que diriez-vous 'np.digitize (a, bacs, droite = true) + 1' avec les bacs comme dans l'ordre original? – Divakar

+0

Dans certains cas, les cases ne peuvent pas être incrémentées de 1, donc ce pourrait être des cases comme [0,4,8,12, ...]. Idéalement, la réponse devrait aussi s'étendre aux intervalles réguliers entre les intervalles (comme [0,2,4,7,11,16]), mais c'est moins important. – Afflatus

+1

Je veux dire que pour obtenir les indices et obtenir les valeurs bin correspondantes, faites quelque chose comme: 'np.take (bins, np.digitize (a, bins, right = True))'. Devrait prendre soin de l'espacement des bacs irréguliers. Est-ce que ça ne marchera pas? – Divakar

Répondre

1

Nous pouvons simplement utiliser np.digitize avec son right option définie comme True pour obtenir les indices, puis pour extraire les éléments correspondants bins, introduire np.take, comme si -

np.take(bins,np.digitize(a,bins,right=True)) 
+1

Sélection de ceci comme réponse officielle b/c il fonctionne mieux sur les grandes séries. Comme mentionné dans les commentaires à la poste - pour mon cas d'utilisation particulier, il faut 1/20e le temps comme réponse de Christian. Pour les séries chronologiques plus courtes, les temps sont dans le même parc à billes. – Afflatus

1

Je crois que np.searchsorted va faire ce que vous voulez:

Trouver les indices dans un tableau trié a de telle sorte que, si les éléments v ont été insérés avant les indices correspondants, l'ordre d'un serait être conservé.

In [1]: my_series = [1, 1.5, 2, 2.3, 2.6, 3] 

In [2]: bins = [1,2,3] 

In [3]: import numpy as np 

In [4]: [bins[k] for k in np.searchsorted(bins, my_series)] 
Out[4]: [1, 2, 2, 3, 3, 3] 

(Au numpy 1.10.0, digitize est mis en œuvre en termes de searchsorted.)

1

Une autre façon serait:

In [25]: def find_nearest(array,value): 
    ...:  idx = (np.abs(array-np.ceil(value))).argmin() 
    ...:  return array[idx] 
    ...: 

In [26]: my_series = np.array([ 1, 1.5, 2, 2.3, 2.6, 3]) 

In [27]: bins = [1, 2, 3] 

In [28]: [find_nearest(bins, x) for x in my_series] 
Out[28]: [1, 2, 2, 3, 3, 3] 
+0

Bien que cela fonctionne pour le cas de l'exemple, cela ne fonctionne pas, peut-être en raison de certains problèmes d'arrondi avec np.ciel() ou argmin(). Voir l'exemple: bins = [100,200,300,400,600,600,700,800,900] my_series = [123,157,533,644,222,343] [find_nearest (bins, x) pour x dans my_series] rendements [100 *, 200, 600, 600 *, 200 *, 300 *] – Afflatus