NumPy supporta una varietà di tipi numerici maggiore rispetto a Python, perciò è importante comprendere appieno quali sono i tipi di dati e come vengono definiti, per poter lavorare al meglio con questa libreria.
In questa lezione vedremo quindi l’oggetto dtype alla base della definizione dei tipi di dati in NumPy e i principali tipi di dati definiti. Faremo alcuni semplici esempi pratici.
L’oggetto dtype
Un data type (dtype
) object, istanzanziato tramite la classe numpy.dtype
, definisce come devono essere interpretati i byte corrispondenti a un elemento dell'array. Descrive inoltre i seguenti aspetti dei dati.
Aspetto | Descrizione |
---|---|
tipi dei dati | come integer , float , Python Object, ecc. Ci sono diversi tipi scalari forniti da NumPy, come numpy.int_ e numpy.floatl_ per la definizione di interi e numeri in virgola mobile, rispettivamente. Cionostante, i tipi scalari non sono oggetti dtype , anche se possono essere usati al posto di uno di questi ogni volta che è necessaria una specifica del tipo di dati in NumPy. |
la dimensione del dato | come il numero di byte di un float |
l’ordine dei byte | L'ordine dei byte viene deciso anteponendo < o > al tipo di dati dove:
|
il tipo di dato è structured |
un tipo di dato creato dall’utente e che può includere array e dtypes , o un aggregato di altri tipi di dati. In particolare, i tipi di dati structured vengono formati creando un tipo di dati il cui campo contiene altri tipi di dati. Ogni campo ha un nome con il quale è possibile accedervi. |
il tipo di dato è un sotto-array | può descrivere elementi che sono essi stessi matrici di elementi di un altro tipo di dati e che devono avere una dimensione fissa ed un tipo di dato specifico |
Un oggetto dtype
può essere costruito utilizzando il costruttore numpy.dtype()
. Ad esempio, se volessimo definire un oggetto dtype
basato sullo scalare int32
basterà scrivere quanto segue
dt_int32 = np.dtype('int32')
o in modo equivalente utilizzando al posto della stringa 'int32'
l’oggetto np.int32
dt_int32 = np.dtype(np.int32)
stampando la variabile otterremo
dtype('int32')
Questa classe offre inoltre diversi attributi come ad esempio numpy.dtype.isbuiltin
che permette di sapere se quel dtype
con cui si sta lavorando è predefinito nella libreria o meno.
Per esempio, per la nostra variabile dt_int32
avremo
dt_int32.isbuiltin
1
dove il valore 1
indica che il nostro dtype
è predefinito nella libreria. Per ulteriori informazioni sugli attributi di questa classe, si rimanda alla documentazione ufficiale.
I Tipi
Come anticipato all’inizio di questa lezione, NumPy supporta una varietà maggiore di tipi numerici rispetto a Python. Di seguito è riportata una semplice tabella riassuntiva che mostra il parallelo tra i tipi di dati in NumPy e quelli in C
Tipo di dato in NumPy | Tipo di dato in C | Descrizione |
---|---|---|
numpy.bool_ |
bool |
Valore booleano (True|False ) memorizzato come byte |
numpy.byte |
signed char |
definito dalla piattaforma |
numpy.ubyte |
unsigned char |
definito dalla piattaforma |
numpy.short |
short |
definito dalla piattaforma |
numpy.ushort |
unsigned short |
definito dalla piattaforma |
numpy.intc |
int |
definito dalla piattaforma |
numpy.uintc |
unsigned int |
definito dalla piattaforma |
numpy.int_ |
long |
definito dalla piattaforma |
numpy.uint |
unsigned long |
definito dalla piattaforma |
numpy.longlong |
long long |
definito dalla piattaforma |
numpy.ulonglong |
unsigned long long |
definito dalla piattaforma |
numpy.half / numpy.float16 |
- | float a metà della precisione |
numpy.single |
float |
definito dalla piattaforma |
numpy.double |
double |
definito dalla piattaforma |
numpy.longdouble |
long double |
definito dalla piattaforma |
numpy.csingle |
float complex |
rappresentazione dei numeri complessi, composti da una parte reale e immaginaria con una rappresentazione float |
numpy.cdouble |
double complex |
rappresentazione dei numeri complessi, composti da una parte reale e immaginaria con una rappresentazione double |
numpy.clongdouble |
long double complex |
rappresentazione dei numeri complessi, composti da una parte reale e immaginaria con una precisione long double |
Poiché molti di questi hanno definizioni dipendenti dalla piattaforma, viene fornito un set di alias a dimensione fissa come ad esempio:
numpy.int32
numpy.int64
numpy.float32
numpy.float64 / numpy.float_
numpy.complex64
I tipi di dati possono essere usati come funzioni per convertire i numeri Python in scalari di array (vedere la sezione scalare degli array per una spiegazione), sequenze di numeri Python in array di quel tipo o come argomenti per la parola chiave dtype
che molte funzioni o metodi numpy accettano. Vediamo qualche esempio.
Conversione di un int
in float
x = np.float32(1)
1.0
Conversione di un array di int
in un array di float
floatarray = np.float_([1,2,4])
array([1., 2., 4.])
Creazione di un array di tre elementi di tipo complex64
array_dtype_complex64 = np.arange(3, dtype=np.complex64)
array([0.+0.j, 1.+0.j, 2.+0.j], dtype=complex64)
Definizione dei tipi tramite stringa
Per semplificare il più possibile la definizione dei dtype
è possibile anche sfruttare la nomenclatura basata sul singolo carattere o su una stringa composta da due o più caratteri dove:
- il primo carattere specifica il tipo di dato;
- i caratteri rimanenti specificano il numero di byte per elemento.
In quest’ultimo caso, l’unica eccezione è per il tipo unicode
, dove i caratteri successivi al primo vengono interpretati come il numero di caratteri della stringa.
La nomenclatura per il primo carattere è la seguente.
Stringa | Tipo |
---|---|
'?' |
boolean |
'b' |
(signed) byte |
'B' |
unsigned byte |
'i' |
(signed) integer |
'u' |
unsigned integer |
'f' |
floating-point |
'c' |
complex-floating point |
'm' |
timedelta |
'M' |
datetime |
'O' |
oggetto Python |
Grazie a questa rappresentazione è possibile definire più velocemente un dtype
o array di elementi. Vediamo qualche esempio.
Per definire un dtype di tipo int32 basterà
dt = np.dtype('i4')
dove i
sta per int
e 4
è il numero di byte per elemento. Stampando la variabile otterremo:
dt
dtype('int32')
Per creare un array composto da tre valori di tipo complex128 possiamo definire
complex_array = np.arange(3, dtype=np.dtype('c16'))
il cui valore sarà
array([0.+0.j, 1.+0.j, 2.+0.j])
ed il suo tipo
complex_array.dtype
dtype('complex128')
Gli esempi di questa lezione sono disponibili su GitHub.