2012-05-25 21 views
13

Sono sul mio viaggio di transizione da MATLAB a scipy (+ numpy) + matplotlib. Continuo ad avere problemi nell'implementare alcune cose. Voglio creare una semplice matrice vettoriale in tre parti differenti. In MATLAB vorrei fare qualcosa di simile:array numpy che crea con una sequenza

vector=[0.2,1:60,60.8]; 

Questo si traduce in una matrice monodimensionale di 62 posizioni. Sto cercando di implementarlo usando scipy. Il più vicino mi trovo ora è questo:

a=[[0.2],linspace(1,60,60),[60.8]] 

Tuttavia, questo crea un elenco, non un array, e quindi non posso rimodellare a un array di vettore. Ma poi, quando faccio questo, ottengo un errore

a=array([[0.2],linspace(1,60,60),[60.8]]) 
ValueError: setting an array element with a sequence. 

Credo che la mia principale ostacolo è che io non riesco a capire come tradurre questa semplice operazione in MATLAB:

a=[1:2:20]; 

a numpy . So come farlo per accedere alle posizioni in un array, anche se non quando si crea una sequenza. Qualsiasi aiuto sarà apprezzato, grazie!

risposta

13

Well NumPy implementa la funzione di MATLAB array creazione, vettore, utilizzando due funzioni invece di uno - ogni specifica implicitamente un asse particolare lungo il quale concatenazione dovrebbe verificarsi. Queste funzioni sono:

  • r_ (concatenazione row-saggio) e

  • c_ (colonna-saggio)


Così, per il tuo esempio , l'equivalente NumPy è:

>>> import numpy as NP 

>>> v = NP.r_[.2, 1:10, 60.8] 

>>> print(v) 
    [ 0.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 60.8] 

La controparte colonna-saggio è:

>>> NP.c_[.2, 1:10, 60.8] 

fetta notazione funziona come previsto [partenza: fermata: passo]:

>>> v = NP.r_[.2, 1:25:7, 60.8] 

>>> v 
    array([ 0.2, 1. , 8. , 15. , 22. , 60.8]) 

Anche se un numero immaginario di usato come terzo argomento, la notazione di slicing si comporta come linspace:

>>> v = NP.r_[.2, 1:25:7j, 60.8] 

>>> v 
    array([ 0.2, 1. , 5. , 9. , 13. , 17. , 21. , 25. , 60.8]) 


In caso contrario, si comporta come arange:

>>> v = NP.r_[.2, 1:25:7, 60.8] 

>>> v 
    array([ 0.2, 1. , 8. , 15. , 22. , 60.8]) 
+0

grazie doug! questo è estremamente bello, ed è a due caratteri di distanza per essere compatto come il MATLAB. grande! – lllllll

+0

@ vint-i-vuit nessun problema. Se la mia risposta ti è stata utile, contrassegnala come "accettata" facendo clic sul "segno di spunta", visibile quando passi il mouse sopra il punteggio nell'angolo in alto a sinistra della mia risposta. (O se un'altra risposta è stata più utile, ovviamente vorrai contrassegnarla invece). Sì, ci sono altri due caratteri, ma penso che ne valga la pena, quindi NumPy può avere una funzione per ciascuno dei due assi da concatenare insieme (r_ & c_). – doug

+0

non lo sapevo, sì!Ho imparato molto da tutti i post, funzionano tutti come volevo, ma forse il tuo è il più vicino a MATLAB. grazie a tutti! – lllllll

5

Si potrebbe provare qualcosa di simile:

a = np.hstack(([0.2],np.linspace(1,60,60),[60.8])) 
+0

true! anche questo funziona, grazie JoshAdel. Inoltre, linspace è l'unica opzione ogni volta che voglio fare qualcosa come a = [1: 2: 20]? Il che implica che non conosco la dimensione finale del vettore, solo il passo e i punti di inizio/fine. [bis] – lllllll

+1

L'ho trovato da solo grazie a mgilson. La risposta è range (start, stop, step). grande! – lllllll

+0

@ vint-i-vuit Si noti che la funzione dell'intervallo integrato python funziona solo con valori interi. Numpy fornisce 'arange' che farà la stessa cosa (anche con float se lo vuoi) restituendo un array, ma la documentazione afferma che' linspace' è una opzione migliore nella maggior parte dei casi da quando (a causa del roundoff), i risultati di 'arange' potrebbe non essere esattamente quello che ti aspetti. – mgilson

1

se ho capito bene il MATLAB, si potrebbe realizzare qualcosa di simile utilizzando:

a=np.array([0.2]+list(range(1,61))+[60.8]) 

Ma c'è probabilmente un modo migliore ... il list(range(1,61)) potrebbe essere solo range(1,61) se stai usando python 2.X.

Questo funziona creando 3 elenchi e quindi concatenandoli utilizzando l'operatore +.

Il motivo per il vostro originale tentativo non ha funzionato è perché

a=[ [0.2], np.linspace(1,60,60), [60.8] ] crea una lista di liste - in altre parole:

a[0] == [0.2] #another list (length 1) 
a[1] == np.linspace(1,60,60) #an array (length 60) 
a[2] == [60.8] #another list (length 1) 

La funzione array prevede un iterabile che è una sequenza, o una sequenza di sequenze della stessa lunghezza.

+0

ottimo mgilson! è probabilmente la più vicina alla sintassi MATLAB. Ancora non così compatto come a = [0.2,1: 60,60,8] ma fresco. grazie mille, ora lo vedo più chiaro – lllllll

+0

Penso che troverete che molte cose in 'numpy' sono altrettanto concise come in MATLAB (e un paio di cose leggermente più concise), ci sono alcune cose che non sono altrettanto concise - Tuttavia , In generale trovo il codice molto più intuitivo. – mgilson

+0

Fino ad ora, la flessibilità acquisita, specialmente nel tracciare, vale così tanto la "meno concisione" della sintassi, fino ad ora. :) – lllllll

3
np.concatenate([[.2], linspace(1,60,60), [60.8]]) 
+0

dannazione, vero! funziona, grazie a Larsmans. Inoltre, linspace è l'unica opzione ogni volta che voglio fare qualcosa come a = [1: 2: 20]? Il che implica che non conosco la dimensione finale del vettore, solo il passo e i punti di inizio/fine. – lllllll

+1

L'ho trovato da solo grazie a mgilson. La risposta è range (start, stop, step). grande! – lllllll

+1

Si potrebbe anche provare 'np.arange (1,20,2)' sebbene si faccia attenzione poiché questa operazione non include l'ultimo numero nell'intervallo (ad es. Array ([1, 3, 5, 7, 9, 11, 13, 15, 17, 19])). Ho dimenticato come lo gestisce Matlab e l'ho rimosso da tempo dalla mia macchina. – JoshAdel

2

ho un po 'come l'idea di costruire questi intervalli segmentati che hai menzionato. Se li usate molto, forse una piccola funzione come

import numpy as np 

def segrange(*args): 
    result = [] 
    for arg in args: 
     if hasattr(arg,'__iter__'): 
      result.append(range(*arg)) 
     else: 
      result.append([arg]) 
    return np.concatenate(result) 

che ti dà

>>> segrange(1., (2,5), (5,10,2)) 
[ 1. 2. 3. 4. 5. 7. 9.] 

sarebbe bello avere. Anche se probabilmente dovrei cercare la risposta usando concatenate/hstack.

+0

questa è una buona idea! Penso che cercherò di attenermi all'operatore '+' usato nella risposta di mgilson da adesso, poiché è quello che trovo più vicino a MATLAB, quindi meno impegno nel ricordare. Comunque vedrò se l'esecuzione di quel codice è più conveniente in alcuni casi :) – lllllll

+1

Correggetemi se ho torto, ma penso che 'isinstance (arg, list)' sia preferito su 'type (arg) is list'. Inoltre, potresti abbreviare l'intero se il blocco a 'hasattr (arg, '__ iter __')' (e catturare tutti i tipi di altri iterables mentre ci sei) – mgilson

+0

sì, il tuo mgilson giusto. ma la risposta di doug che porta su _r sostituisce tutto ^^ – pwuertz

1

Dai un'occhiata allo np.r_.È fondamentalmente equivalente a quello che tutti gli altri hanno suggerito, ma se provieni da matlab, è un po 'più intuitivo (e se provieni da qualsiasi altra lingua, è un po' contro-intuitivo).

Come esempio, vector=[0.2,1:60,60.8]; traduce:

vector = np.r_[0.2, 1:61, 60.8] 
1

Voglio solo sottolineare per tutte le altre persone che vanno da MATLAB per Numpy che è possibile costruire un array np.r_ con i due punti e quindi utilizzarlo per indicizzare

Ad esempio, se si dispone in MATLAB

arr_ones = ones(10,10) 

O in Numpy

arr_ones = np.ones([10,10]) 

Si potrebbe in Matlab prende solo le colonne da 1 a 5 e 7 in questo modo:

arr_ones(:,[1:5 7]) 

fare lo stesso in Numpy non è (almeno per me) intuitivo. Questo vi darà un errore di "sintassi non valida":

arr_ones[:,[1:5,7]] 

Tuttavia questo funziona:

inds = np.r[1:5,] 
arr_ones[:,inds] 

So che questo non è tecnicamente una nuova risposta, ma usando i due punti per costruire una matrice per l'indicizzazione in una matrice sembra così naturale in Matlab, sto scommettendo che molte persone che vengono in questa pagina vorranno sapere questo. (Sono venuto qui invece di fare una nuova domanda.)