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

NumPy array object

Scopriamo come gestire gli array in NumPy, modulo Python per il calcolo scientifico, parte integrante di molti progetti di data science.
Scopriamo come gestire gli array in NumPy, modulo Python per il calcolo scientifico, parte integrante di molti progetti di data science.
Link copiato negli appunti

Nella lezione precedente, abbiamo visto e analizzato la classe dtype, i principali tipi di dati e come definirli per poter lavorare al meglio con questa libreria e per fare conversioni di dati e calcoli matematici in modo semplice ed efficace.

In questa lezione, invece, ci concentreremo sulla principale struttura dati alla base di questo framework: gli n-dimensional array.

Gli n-dimensional array

Un n-dimensional array (ndarry) è un tipo di struttura dati che ha reso Numpy la libreria Python perfetta per il calcolo matematico, ottimizzando le performance in termini di costo computazionale e velocità.

Volendo utilizzare la definizione offerta dalla documentazione ufficiale, un ndarry rappresenta un array multidimensionale e omogeneo di elementi di dimensioni fisse. Un tipo di dato associato all’oggetto array descrive il formato di ogni elemento presente in esso, tra cui:

  • il suo ordine di byte;
  • quanti byte occupa in memoria;
  • se è un numero intero, un numero in virgola mobile o altro.

Possiamo definire più semplicemente un ndarray come un contenitore multidimensionale di elementi dello stesso tipo e dimensione. In particolare, il numero di dimensioni ed elementi in un array è definito dal suo attributo shape, che è rappresentato tramite una tupla di N numeri interi e non negativi, che specificano le dimensioni di ciascuna dimensione.

Il tipo di elementi di questa particolare struttura dati è specificato da un dtype associato all’intero ndarray. Vediamo un semplice esempio.

Per creare un ndarry bidimensionale, ossia una matrice, composto da 3 righe e 3 colonne di float, basterà utilizzare il metodo array del modulo numpy.

import numpy as np
matrix = np.array([[1.2, 2.4, 3.1], [4.5, 5.2, 6.9], [7.2, 8.8, .9]], np.float32)

La variabile matrix è quindi un ndarray, come facilmente ricavabile dall’utilizzo della funzione type.

type(matrix)
numpy.ndarray

A questo punto, per conoscerne la dimensione basterà utilizzare l’attributo shape come segue.

matrix.shape
(3, 3)

Invece, per verificarne il tipo, basterà usare l’attributo dtype.

matrix.dtype
dtype('float32')

Infine, se vogliamo conoscere il numero di elementi e il numero di dimensioni che compongono l’oggetto matrix, possiamo usare l’attributo size e ndim, rispettivamente, ottenendo.

print(f'matrix dimension: {matrix.ndim} - total elements: {matrix.size}')
matrix dimension: 2 - total elements: 9

Quelli visti fin qui sono solo alcuni degli attributi offerti dall’oggetto ndarray, ve ne sono altri come imag o real per ottenere la parte immaginaria o reale dell’array. Per maggiori informazioni, si rimanda alla documentazione ufficiale.

Come con altre strutture dati offerte da Python, con gli ndarray è possibile:

  • accedere al contenuto di un ndarray;
  • modificare il contenuto di un ndarray tramite l’operazione di indexing;
  • modificare un ndarray tramite l’operazione slicing o tramite i metodi e gli attributi offerti dalla classe stessa.

Ad esempio, per accedere ad uno specifico elemento della matrice, basterà indicare l’indice per la riga e per la colonna della posizione a cui si vuole accedere.

matrix[1,2]
6.9

Nelle prossime lezioni, vedremo nelle specifico le diverse operazioni che possono essere compiute sugli ndarray.

Gestione della memoria interna di un ndarray

A un'istanza della classe ndarray viene assegnato un segmento continuo nella memoria. In particolare, si ha che:

  • l'allocazione della memoria insieme allo schema di indicizzazione mappa quindi N-interi su un elemento del blocco dell'array;
  • il range di variazione dell'indice è dato dalla forma dell'array e viceversa;
  • il tipo di dato viene utilizzato per definire quanti byte richiederà ogni elemento dell’ndarray;
  • il tipo di dato permette di definire come verranno inferiti i byte. Ad esempio, ogni elemento int16 ha una dimensione di 16 bit, cioè 16/8 = 2 byte.

Infine, un altro aspetto interessante degli ndarray è che diversi ndarray possono condividere gli stessi dati, in modo che le modifiche apportate in un ndarray possano essere visibili in un altro. In questo caso, si parla di view e di base, dove:

  • un base ndarray è l’oggetto che definisce i dati;
  • un view ndarray è un ndarray creato a partire dal base ndarray con cui condivide le celle di memoria.

Una qualsiasi modifica fatta su un base o un view ndarray verrà vista sull’altro.

Per creare una view, è possibile usare il metodo view() di ndarray e per sapere se effettivamente due ndarray condividono la memoria, è possibile usare il metodo shares_memory() del modulo numpy. Vediamo un semplice esempio:

base = np.array([1, 2, 3, 4, 5])
view = base.view()
view[0] = 42
print(f'base: {base}')
print(f'view: {view}')
print(f'shared memory: {np.shares_memory(base, view)}')
# results
base: [42  2  3  4  5]
view: [42  2  3  4  5]
shared memory: True

ndarray vs list

Erroneamente, si tende a pensare che gli ndarray siano simili alle list in Python, ma le differenze sono notevoli. In Python un oggetto list:

  • è definito inserendo uno o più elementi tra parentesi quadre;
  • è ordinato mostrando i dati in un ordine specifico;
  • è mutabile;
  • non deve essere dichiarato;
  • non può gestire direttamente le operazioni matematiche.

Contrariamente gli ndarray:

  • devono essere dichiarati
  • vengono creati tramite l’apposita funzione array() del modulo numpy;
  • possono definire un solo tipo di dato;
  • possono memorizzare i dati in modo compatto, risultando efficienti per l’archiviazione di grandi quantità di dati;
  • sono ottimi per le operazioni matematiche.

Ad esempio, si può dividere ogni elemento di un array per lo stesso numero con una sola riga di codice.

array = np.array([3, 6, 9, 12])
division = array/3
print(division)
[1. 2. 3. 4.]
print (type(division))
<class 'numpy.ndarray'>

Se provassimo a fare lo stesso con una list, otterremmo un errore.

list = [3, 6, 9, 12]
division = list/3
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-18-f127235414b2> in <module>()
      1 list = [3, 6, 9, 12]
----> 2 division = list/3
TypeError: unsupported operand type(s) for /: 'list' and 'int'

Ti consigliamo anche