4

Ich muss ein 2D-Array erstellen, in dem jede Zeile mit einer anderen Nummer beginnen und enden kann. Nehmen wir an, dass das erste und das letzte Element jeder Zeile angegeben ist und alle anderen Elemente nur entsprechend der Länge der Zeilen interpoliert werden. In einem einfachen Fall möchte ich ein 3X3-Array mit demselben Anfang bei 0, aber unterschiedlichem Ende mit W unten erstellen:Vectorized NumPy linspace für mehrere Start- und Stoppwerte

array([[ 0., 1., 2.], 
     [ 0., 2., 4.], 
     [ 0., 3., 6.]]) 

gibt es einen besseren Weg, dies als das zu tun, folgende:

D=np.ones((3,3))*np.arange(0,3) 
D=D/D[:,-1] 
W=np.array([2,4,6]) # last element of each row assumed given 
Res= (D.T*W).T 
+1

Wenn Sie Pandas verwenden möchten: 'pd.Series (W) .apply (Lambda e: np.linspace (0, e, 3))' – Boud

+0

Grundsätzlich haben Sie zwei Vektoren (erste und letzte Spalten Ihrer Matrix) , richtig? Und Sie möchten dann für jede Zeile einige Werte interpolieren. – Kartik

+1

@dayum Wenn Sie die Anfangspositionen ändern möchten, ist es die gleiche Vorgehensweise, aber Sie erstellen ein DF mit zwei Vektoren starten und stoppen, und Sie rufen erneut mit dem Lambda-Argument df.start, df.end, 3 – Boud

Antwort

4

Hier ist ein Ansatz broadcasting mit -

def create_ranges(start, stop, N, endpoint=True): 
    if endpoint==1: 
     divisor = N-1 
    else: 
     divisor = N 
    steps = (1.0/divisor) * (stop - start) 
    return steps[:,None]*np.arange(N) + start[:,None] 

Sampl e run -

In [22]: # Setup start, stop for each row and no. of elems in each row 
    ...: start = np.array([1,4,2]) 
    ...: stop = np.array([6,7,6]) 
    ...: N = 5 
    ...: 

In [23]: create_ranges(start, stop, 5) 
Out[23]: 
array([[ 1. , 2.25, 3.5 , 4.75, 6. ], 
     [ 4. , 4.75, 5.5 , 6.25, 7. ], 
     [ 2. , 3. , 4. , 5. , 6. ]]) 

In [24]: create_ranges(start, stop, 5, endpoint=False) 
Out[24]: 
array([[ 1. , 2. , 3. , 4. , 5. ], 
     [ 4. , 4.6, 5.2, 5.8, 6.4], 
     [ 2. , 2.8, 3.6, 4.4, 5.2]]) 
+0

Warum nicht "linspace" nutzen? – Boud

+0

@Boud Ich bin mir nicht sicher, funktioniert es auf '2D'? – Divakar

+0

@Divakar Ich meinte etwas wie [dies] (http://stackoverflow.com/a/16887295/624829) – Boud

1

Wie der diese Verwendung des OP von linspace nimmt der Start ist 0 für alle Zeilen.

x=np.linspace(0,1,N)[:,None]*np.arange(0,2*N,2) 

(bearbeiten - das ist die transponierte, was ich bekommen sollte, entweder es umsetzen oder die Verwendung von [:,None] wechseln)

Für N = 3000, ist es deutlich schneller als @Divaker's Lösung. Ich bin mir nicht ganz sicher warum.

In [132]: timeit N=3000;x=np.linspace(0,1,N)[:,None]*np.arange(0,2*N,2) 
10 loops, best of 3: 91.7 ms per loop 
In [133]: timeit create_ranges(np.zeros(N),np.arange(0,2*N,2),N) 
1 loop, best of 3: 197 ms per loop 
In [134]: def foo(N): 
    ...:  D=np.ones((N,N))*np.arange(N) 
    ...:  D=D/D[:,-1] 
    ...:  W=np.arange(0,2*N,2) 
    ...:  return (D.T*W).T 
    ...: 
In [135]: timeit foo(3000) 
1 loop, best of 3: 454 ms per loop 

============

Mit startet und stoppt ich verwenden könnte:

In [201]: starts=np.array([1,4,2]); stops=np.array([6,7,8]) 
In [202]: x=(np.linspace(0,1,5)[:,None]*(stops-starts)+starts).T 
In [203]: x 
Out[203]: 
array([[ 1. , 2.25, 3.5 , 4.75, 6. ], 
     [ 4. , 4.75, 5.5 , 6.25, 7. ], 
     [ 2. , 3.5 , 5. , 6.5 , 8. ]]) 

Mit den zusätzlichen Berechnungen, dass es langsamer etwas macht als create_ranges .

In [208]: timeit N=3000;starts=np.zeros(N);stops=np.arange(0,2*N,2);x=(np.linspace(0,1,N)[:,None]*(stops-starts)+starts).T 
1 loop, best of 3: 227 ms per loop 

Alle diese Lösungen sind nur Variationen der Idee, eine lineare Interpolation zwischen den starts und stops zu tun.

+0

Da die Frage besagt, dass "das erste und das letzte Element jeder Zeile angegeben wird", wie würden Sie die Start- und Stopp-Werte für jede Zeile in die'inspace'-basierte Lösung integrieren? – Divakar

Verwandte Themen