2016-09-08 4 views
4

Ich möchte eine Funktion, die eine Reihe und eine Reihe von Bins dauern kann, und im Grunde um die nächste Bin runden. Zum Beispiel:Python: Zuweisen von # Werten in einer Liste zu Bins, durch Abrunden

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] 

Dies scheint sehr nahe zu sein, was Numpy's Digitize tun soll, aber es erzeugt die falschen Werte (Sternchen für falsche Werte):

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

Der Grund, warum es falsch ist, ist aus der Dokumentation:

Jeder Index i zurückgeführt, so dass bins [i-1] = x < < bins [i] wenn bin s ist monoton steigend oder Bins [i-1]> x> = Bins [i] Wenn Bins monoton fallend ist. Wenn die Werte in x die Grenzen von Bins überschreiten, wird 0 oder len (Bins) entsprechend zurückgegeben. Wenn right True ist, dann ist das rechte Fach geschlossen, so dass der Index i so ist, dass bins [i-1] < x < = bins [i] oder bins [i-1]> = x> bins [i] `if bins ist monoton steigend bzw. abnehmend.

Ich kann Art näher kommen, was ich will, wenn ich in den Werten zu verringern und setzen Sie „rechts“ auf True ...

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

eingeben, aber dann werde ich von einem denken Methode, die niedrigste Nummernvergabe (1) mit der höchsten Nummernvergabe (3) grundsätzlich methodisch umzukehren. Es ist einfach, wenn es nur 3 Mülleimer gibt, aber es wird haariger, wenn die Anzahl der Mülleimer länger wird ... es muss eine elegantere Art und Weise sein, all dies zu tun.

+0

Wie wäre es mit 'np.digitize (a, bins, right = True) + 1' mit den Bins wie in der ursprünglichen Reihenfolge? – Divakar

+0

In einigen Fällen werden die Bins möglicherweise nicht um 1 inkrementiert, es könnte sich also um Bins wie [0,4,8,12, ...] handeln. Idealerweise würde sich die Antwort auch auf regelmäßige Intervalle zwischen den Intervallen erstrecken (wie [0,2,4,7,11,16]), aber das ist weniger wichtig. – Afflatus

+1

Ich meine, das ist, um die Indizes zu erhalten und die entsprechenden Bin-Werte zu erhalten, tun Sie etwas wie: 'np.take (bins, np.digitize (a, bins, rechts = True))'. Sollte auf unregelmäßige Abstände zwischen den Behältern achten. Wird das nicht funktionieren? – Divakar

Antwort

1

Wir können einfach verwenden np.digitize mit seinen right Option gesetzt als True, um die Indizes zu erhalten und dann die entsprechenden Elemente aus bins zu extrahieren, bringen Sie np.take, like so -

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

offizielle Antwort b/c es funktioniert besser bei größeren Serien. Wie in den Kommentaren zur Post erwähnt - für meinen speziellen Anwendungsfall dauert es 1/20 der Zeitaufwand als Christian's Antwort. Für kürzere Zeitreihen sind die Zeiten im selben Ballpark. – Afflatus

1

Ich glaube np.searchsorted wird tun, was Sie wollen:

Finden Sie die Indizes in einem sortierten Array a, so dass, wenn die entsprechenden Elemente in v vor den Indizes eingeführt wurden, die Reihenfolge der eine würde sein konserviert.

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] 

(Ab numpy 1.10.0 wird digitize in Bezug auf searchsorted implementiert.)

1

Eine andere Möglichkeit wäre:

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

Obwohl es für den Beispielfall funktioniert, funktioniert es nicht konsistent, vielleicht wegen einiger Rundungsprobleme mit entweder np.ciel() oder argmin(). Siehe Beispiel: bins = [100,200,300,400,500,600,700,800,900] my_series = [123,157,533,644,222,343] [find_nearest (bins, x) für x in my_series] ergibt [100 *, 200, 600, 600 *, 200 *, 300 *] – Afflatus

Verwandte Themen