Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Creazione e manipolazione base degli array

Impariamo come creare e manipolare gli array per il calcolo numerico sfruttando il modulo NumPy di Python.
Impariamo come creare e manipolare gli array per il calcolo numerico sfruttando il modulo NumPy di Python.
Link copiato negli appunti

Nelle lezioni precedenti, abbiamo esplorato le potenzialità di Numpy familiarizzando con i tipi di dati offerti e gestiti da questo framework e prendendo un po’ di confidenza con la principale struttura dati, gli ndarray.

In questa lezione, vedremo come effettuare delle semplici ma estremamente utili operazioni di creazione e manipolazione degli ndarray, che torneranno utili non solo a livello di calcolo matematico ma anche quando vorrete utilizzare i tensori con framework di machine learning, come scikit learn, e di deep learning, come TensorFlow o PyTorch.

Creazione di un ndarray

Numpy offre diversi metodi per la creazione di nuovi ndarray. Vediamoli insieme.

Per la creazione di una matrice composta da soli zeri, è possibile invocare il metodo np.zeros().

zeros_matrix = np.zeros((3,4))
zeros_matrix
array([[0., 0., 0., 0.],
           [0., 0., 0., 0.],
           [0., 0., 0., 0.]])

Come possiamo vedere dall’output, la matrice risultante sarà composta da elementi di tipo float64, ma è possibile modificarne il tipo specificando il valore della keyword dtype.

In modo analogo, è possibile creare una matrice composta da soli uno tramite il metodo np.ones().

ones_matrix = np.ones((3,2))
ones_matrix
array([[1., 1.],
      [1., 1.],
      [1., 1.]])

Come nel caso precedente, anche in questo avremo una matrice i cui elementi sono di tipo float64.

Se invece è necessario inizializzare una matrice ad uno specifico valore è possibile impiegare il metodo np.full().

full_matrix = np.full((2,3), 5)
full_matrix
array([[5, 5, 5],
       [5, 5, 5]])

In questo caso specifico, è stato sufficiente specificare la shape della matrice sotto forma di tupla e il valore per popolarla. In questo caso, la matrice generata ha elementi di tipo int64 ma, come per i precedenti metodi, è possibile modificarne il valore tramite la definizione della keyword dtype.

Spesso, nei calcoli matriciali, è però necessario lavorare anche con le matrici di identità, che ricordiamo sono matrici NxN la cui diagonale è composta da soli uno. Per crearla, è sufficiente utilizzare il metodo np.eye() specificando la dimensione della matrice. Ad esempio, per creare una matrice di identità 3x3:

identity_matrix = np.eye(3)
identity_matrix
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

La matrice risultante avrà valori di tipo float64.

Qualora invece fosse necessario definire una matrice diagonale, ossia una matrice quadrata in cui solamente i valori della diagonale principale possono essere diversi da 0, è possibile usare np.diag() specificando i valori desiderati sulla diagonale.

diagonal_matrix = np.diag([1,2,3,4])
diagonal_matrix
array([[1, 0, 0, 0],
        [0, 2, 0, 0],
        [0, 0, 3, 0],
        [0, 0, 0, 4]])

Altri due approcci estremamente utili per creare vettori con elementi che ricadono in uno specifico intervallo sono np.arange() e np.linspace().

La funzione np.arange() può prendere in input uno o più argomenti che ne modificano l’output finale. Ad esempio, con un solo argomento di tipo numerico, N, creerà un ndarray che va nel range [0, N-1.

vect1 = np.arange(10)
vect1
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

Diversamente, specificando due input, con il primo minore del secondo, verrà creato un ndarray nell’intervallo di valori specificato. Vediamo un esempio.

vect2 = np.arange(4, 9)
vect2
array([4, 5, 6, 7, 8])

Come si può facilmente intuire l’estremo superiore, 9, non è incluso nella creazione del vettore.

Infine, questo metodo permette anche di definire un passo che identifica la distanza tra due valori adiacenti.

vect = np.arange(1,14,3)
vect
array([ 1,  4,  7, 10, 13])

Nonostante l’utilità di np.arange(), spesso è opportuno utilizzare la funzione np.linspace() per la sua precisione dei valori in virgola mobile. Vediamo un esempio.

vect3 = np.linspace(0,25,10)
vect3
array([ 0.        ,  2.77777778,  5.55555556,  8.33333333, 11.11111111,
        13.88888889, 16.66666667, 19.44444444, 22.22222222, 25.        ]

In questo caso abbiamo definito un vettore di tipo float64 con 10 valori nell’intervallo [0, 25] opportunamente distanziati.

Infine, Numpy offre la possibilità di creare vettori e matrici in modo randomico sfruttando il modulo random. Ad esempio, se volessimo creare una matrice quadrata 3x3 composta da valori float64, basterà usare il metodo random():

rand_matrix = np.random.random((3,3))
rand_matrix
array([[0.38092162, 0.22859676, 0.96004006],
        [0.6855616 , 0.70534742, 0.05605433],
        [0.72397115, 0.40938473, 0.94926686]])

Invece, se volessimo una matrice quadrata 3x3 di soli valori interi in un dato intervallo, useremmo il metodo randint() come segue.

rand_matrix = np.random.randint(4, 13, (3,3))
rand_matrix
array([[ 6,  9,  8],
        [11, 11,  6],
        [12,  4,  6]])

Se ancora volessimo creare un ndarray che definisca un particolare tipo di distribuzione, come ad esempio una distribuzione normale gaussiana, possiamo usare metodi come normal().

X = np.random.normal(0, 0.1, size=(1000,1000))

In questo caso, viene creata una matrice 1000x1000 con valori randomici in virgola mobile che rappresentano una distribuzione Gaussiana con media nulla e deviazione standard di 0.1.

Quanto riportato finora è solo una rappresentazione dei principali metodi offerti da Numpy per la creazione di ndarray.

Modifica della shape

Quando si lavora con gli ndarray, è spesso necessario modificarne la forma (shape) per poter fare determinate elaborazioni. Le modifiche più semplici riguardano la conversione di un vettore di N elementi in una matrice. Per farlo, è necessario ricorrere alla funzione np.reshape(). Vediamo un esempio:

vector = np.arange(20)
vect2matrix = np.reshape(vector, (4,5))
vect2matrix
array([[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]])

Al contrario, se volessimo trasformare una matrice in un vettore, basterebbe usare il metodo flatten() proprio della classe ndarray, come mostrato di seguito.

vect2matrix.flatten()
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])

In questo caso, abbiamo convertito la matrice in un vettore concatenando le righe tra loro. Se volessimo fare la conversione concatenando le colonne, basterebbe specificare l’ordine tramite la keyword order e la lettera F.

vect2matrix.flatten(order='F')
array([ 0,  5, 10, 15,  1,  6, 11, 16,  2,  7, 12, 17,  3,  8, 13, 18,  4, 9, 14, 19])

Aggiunta e rimozione di elementi

Quando si lavora con gli ndarray, è spesso necessario aggiungere o rimuovere elementi. Vediamo come, definendo un vettore e una matrice di esempio.

vect = np.array([1, 2, 3, 4, 5])
matrix = np.array([[1,2,3],[4,5,6],[7,8,9]])

Iniziamo con la rimozione di un elemento da un vettore tramite il metodo np.delete(), specificando il vettore e la lista di indici in cui si trovano gli elementi che vogliamo rimuovere dal vettore.

np.delete(vect, [0,2])
array([2, 4, 5])

In questo caso, abbiamo rimosso dal vettore gli elementi in posizione 0 e 2.

Con le matrici il discorso si complica leggermente, in quanto va specificato se deve essere cancellata una riga o una colonna tramite l’utilizzo della keyword axis.

Per cancellare, ad esempio, la prima riga della nostra matrice basterà:

np.delete(matrix, [0,0], axis=0)
array([[4, 5, 6],
        [7, 8, 9]])

Mentre, per cancellare la prima colonna, sarà sufficiente impostare il valore di axis=1.

Per quanto riguarda l’aggiunta di dati a un ndarray, ci sono due possibilità:

  • l’operazione di appending, che aggiunge in coda a un ndarray i nuovi dati;
  • l’operazione di inserting, che aggiunge in un punto qualsiasi di un ndarray i valori di interesse.

Partiamo dall’operazione di appending, che può essere eseguita tramite la funzione np.append(). Ad esempio, per aggiungere un valore in coda a un vettore, basta passare in input il vettore e il nuovo dato.

np.append(vect, 6)
array([1, 2, 3, 4, 5, 6])

Per aggiungere nuovi dati a una matrice, è necessario specificare non solo la matrice e i dati, ma anche se aggiungerli sulle righe o sulle colonne. Ad esempio, per aggiungere una nuova riga:

np.append(matrix, [[10, 11, 12]], axis=0)
array([[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9],
        [10, 11, 12]])

Spesso però, si ha l’esigenza di inserire dei nuovi dati in un ndarray in una determinata posizione. Per farlo, il modulo numpy offre il metodo np.insert().

Ad esempio, se volessimo aggiungere al nostro vettore i valori 10 e 11 in posizione 2, basterebbe passare i seguenti input al metodo insert().

np.insert(vect, 2, [10, 11])
array([ 1,  2, 10, 11,  3,  4,  5])

Se il nostro ndarray è invece una matrice, come sempre dovremo specificare se aggiungere quei valori sulle righe o sulle colonne tramite la keyword axis. Ad esempio, se volessimo aggiungere dopo la prima riga il vettore [10,11,12] basterebbe:

np.insert(matrix,1,[10,11,12], axis=0)
array([[ 1,  2,  3],
        [10, 11, 12],
        [ 4,  5,  6],
        [ 7,  8,  9]])

Il codice di questa lezione, con alcuni esempi in più, è disponibile su GitHub.

Ti consigliamo anche