2016-07-26 6 views
3

Also ich habe eine 2-Säule numpy Array von ganzen Zahlen erhalten, sagen:Wie auf 1 Spalte searchsorted bisect einen Bereich von 2 Werten numpy und min-Wert in der 2. Spalte

tarray = array([[ 368, 322], 
     [ 433, 420], 
     [ 451, 412], 
     [ 480, 440], 
     [ 517, 475], 
     [ 541, 503], 
     [ 578, 537], 
     [ 607, 567], 
     [ 637, 599], 
     [ 666, 628], 
     [ 696, 660], 
     [ 726, 687], 
     [ 756, 717], 
     [ 785, 747], 
     [ 815, 779], 
     [ 845, 807], 
     [ 874, 837], 
     [ 905, 867], 
     [ 934, 898], 
     [ 969, 928], 
     [ 994, 957], 
     [1027, 987], 
     [1057, 1017], 
     [1086, 1047], 
     [1117, 1079], 
     [1148, 1109], 
     [1177, 1137], 
     [1213, 1167], 
     [1237, 1197], 
     [1273, 1227], 
     [1299, 1261], 
     [1333, 1287], 
     [1357, 1317], 
     [1393, 1347], 
     [1416, 1377]]) 

ich np.searchsorted zu verwende bisect unteren und oberen Bereiche der Werte in der Spalte 0, dh kann beide Male 241.361 zB bisect in das Array.

ranges = [array([241, 290, 350, 420, 540, 660, 780, 900]), 
array([ 361, 410, 470, 540, 660, 780, 900, 1020])] 

zB: np.searchsorted (tarray [: 0], reicht)

Dies ergibt dann:

array([[ 0, 0, 0, 1, 5, 9, 13, 17], 
     [ 0, 1, 3, 5, 9, 13, 17, 21]]) 

wo jede Position in den beiden resultierenden Arrays ist der Bereich der Werte. Was ich dann machen möchte, ist die Position des Minimalwerts in Spalte 1 der resultierenden Schicht. zB hier ist das, was ich einfach über Iteration in Python bedeuten (wenn das Ergebnis von searchsorted 2 Spalte Array 'f'):

f = array([[ 0, 0, 0, 1, 5, 9, 13, 17], 
     [ 0, 1, 3, 5, 9, 13, 17, 21]]) 

for i,(x,y) in enumerate(zip(*f)): 
    if y - x: 
     print ranges[1][i], tarray[x:y] 

das Ergebnis:

410 [[368 322]] 
470 [[368 322] 
[433 420] 
[451 412]] 
540 [[433 420] 
[451 412] 
[480 440] 
[517 475]] 
660 [[541 503] 
[578 537] 
[607 567] 
[637 599]] 
780 [[666 628] 
[696 660] 
[726 687] 
[756 717]] 
900 [[785 747] 
[815 779] 
[845 807] 
[874 837]] 
1020 [[905 867] 
[934 898] 
[969 928] 
[994 957]] 

nun zu erklären, was ich will: innerhalb der geschnittenen Bereiche möchte ich die Zeile, die den Mindestwert in Spalte 1.

e.g 540 [[433 420] 
[451 412] 
[480 440] 
[517 475]] 

I das Endergebnis (wie in [451 412]) zu 412

01.235.164 hat wollen

beispiels

for i,(x,y) in enumerate(zip(*f)): 
    if y - x: 
     print ranges[1][i], tarray[:,1:2][x:y].min() 

410 322 
470 322 
540 412 
660 503 
780 628 
900 747 
1020 867 

Grundsätzlich möchte ich dies vektorisieren, so kann ich ein Array zurück und nicht müssen laufen, da es für meine Bedürfnisse nicht performant ist. Ich mag den Minimalwert in Spalte 1 für einen halbierten Wertebereich auf Spalte 0

Ich hoffe, ich bin klar zu sein!

Antwort

1

Dies scheint Ihre angestrebten Ziele zu erreichen, das numpy_indexed Paket mit (Disclaimer: Ich bin sein Autor):

import numpy_indexed as npi 
# to vectorize the concatenation of the slice ranges, we construct all indices implied in the slicing 
counts = f[1] - f[0] 
idx = np.ones(counts.sum(), dtype=np.int) 
idx[np.cumsum(counts)[:-1]] -= counts[:-1] 
tidx = np.cumsum(idx) - 1 + np.repeat(f[0], counts) 

# combined with a unique label tagging the output of each slice range, this allows us to use grouping to find the minimum in each group 
label = np.repeat(np.arange(len(f.T)), counts) 
subtarray = tarray[tidx] 
ridx, sidx = npi.group_by(label).argmin(subtarray[:, 0]) 

print(ranges[1][ridx]) 
print(subtarray[sidx, 1]) 
+0

Gute Arbeit! Ich dachte in die gleiche Richtung und dachte, dass Pandas Groupby verwendet werden könnte. – Divakar

+0

ja, es war eine interessante Frage; das Konstruieren der Indizes aus einer Sequenz von Slices war komplizierter als ich es mir vorgestellt hatte; Ich habe immer noch das Gefühl, dass mir etwas viel Einfacheres fehlen könnte. –

+1

Hmm Sie könnte so etwas wie 'id_arr = np.ones tun (counts.sum(), dtype = int); id_arr [np.append (0, zählt [- 1] .cumsum())] = np.append (0, f [0,1:] - f [1 - 1] + 1) 'und dann 'tidx' wäre' id_arr.cumsum() - 1'. Wenn Sie die ungültigen herausgefiltert haben, z.B. der erste Eintrag von 'f', würden Sie vermeiden, dass' '-1' tidx' zu bekommen. Ich denke, der einzige Vorteil wäre, 'np.repeat' zu vermeiden, nicht sicher, ob es sich aber lohnt. Für die Performance wäre es außerdem sinnvoll, sie in zwei Schritte aufzuteilen, um zu vermeiden, dass der erste und der Rest der Einträge getrennt angehängt und indiziert werden. – Divakar

Verwandte Themen