Pillole di Python 2

Logging

Per avere un log del nostro programma possiamo usare il modulo logging fornito da Python. Nell'immagine sottostante vediamo come inserire i messaggi del log solo in un file.

Methods

Per usare i metodi all'interno di una class ci sono 2 diversi modi di operarare come si evince dalle immagini sottostanti, uno è quello di dichiarare il metodo con il decoratore @staticmethod oppure passare il parametro self al metodo stesso altrimenti abbiamo l'errore riprodotto nella Figura 1.

Figura 1

Python Methods
Figura 2

Python Methods Se all'interno di una class definiamo un metodo come @staticmethod poi possiamo richiamarlo senza dover istanziare la class. Con il metodo possiamo richiamare il metodo che viene visto come una funzione e passando il context ctx e non self. Vediamo un esempio :
class metodo:

@staticmethod
def metodo1( a):
print(a)
def metodo2( b):
print(b)

class tesT:
def run(a):
return metodo.metodo1(a)
def run2(b):
return metodo.metodo2(b)


tesT.run(5)

DEBUGGER

Con PDB vediamo come è possibile sapere il valore dei qualsiasi variabile all'interno del programma ed è possibile interrompere e far ripartire l'esecuzione dello stesso. PDB fa parte della libreria di python. Inserire questa riga di comando nel punto in cui si vuole interrompere programma ed entrare in modalità debugger.


import pdb; pdb.set_trace()


Dalla versione Python 3.7 è possibile fare la stessa cosa inserendo solo

breakpoint()


Mentre da CLI si può inserire il comando

python -m pdb nome_programma.py [argument1 argument2 ....]



Di seguito i principali comandi disponibili :

> riga di comando già eseguita
-> riga di comando di prossima esecuzione
b breakpoint
b arguments - setta un nuovo breakpoint
cl argument - cancella il breakpoint
enable 1 - riabilita breakpoint 1
disable - disabilita breakpoint
c continua fino a raggiungere un breakpoint
p nome variabile - print contenuto variabile
pp nome variabile - print contenuto variabile
display nome variabile - print contenuto variabile
n - step - va avanti nei comandi ma solo all'interno della funzione corrente
s - step - prosegue esecuzione anche all'interno di una funzione chiamata
unt - esecuzione continua si ferma se la line è maggiore di quella in esecuzione
unt numero - esecuzione continua si ferma se la line è maggiore o uguale di quella in esecuzione
q uscire

#!/usr/bin/env python3

import pdb;
msg = "Hello World"
pdb.set_trace()
print(f'messaggio = { msg}')
msg = "Hi everyone"
breakpoint()
print(f'messaggio = { msg}')


Ora vediamo l'esecuzione del programma sopra riportato:

xxxxx:~$ ./provapdb.py
> /home/mecbar/provapdb.py(6)()
-> print(f'messaggio = { msg}')
(Pdb) p msg
'Hello World'
(Pdb) c
messaggio = Hello World
> /home/mecbar/provapdb.py(9)()
-> print(f'messaggio = { msg}')
(Pdb) p msg
'Hi everyone'
(Pdb) c
messaggio = Hi everyone
xxxxx:~$

PANDAS

Con la libreria Pandas possiamo utilizzare le proprietà dei Dataframe per manipolare ed elaborare i dati che possono essere importati anche da file ad esempio i file csv.
La prima struttura che analizziamo sono le Series(one-dimensional labeled array) che possono contenere ogni tipo di dato.

SERIES :

serie1 = pd.Series(data, index=index)
data può essere dictionary, scalar o ndarray
Nell'esempio sottostante inseriamo un ndarray in una serie.

import pandas as pd
import numpy as np
myarray = np.array([1,2,3,4,5])
serie1 = pd.Series(myarray, index=['a', 'b', 'c', 'd', 'e'])


serie1 è uguale :
a 1
b 2
c 3
d 4
e 5
dtype: int64

dict1 = {'b': 2, 'a': 1, 'c': 3, 'd':4,'e':5}

pd.Series(dict1)

b 2
a 1
c 3
d 4
e 5
dtype: int64

SERIES FROM SCALAR :

serie2 = pd.Series((100,200,300,400,500), index=['a', 'b', 'c', 'd', 'e'])

Out:
a 100
b 200
c 300
d 400
e 500
dtype: int64

SLICING :

serie2[0] Out 100
serie2['c'] Out[: 300
serie2['c'] = 350
serie2[:4]


Out:
a 100
b 200
c 350
d 400
dtype: int64

'b' in serie2 Out: True

serie2[serie2 > serie2.mean()]

Out:
c 350
d 400
e 500
dtype: int64

serie3 = serie2 * 3

Out:
a 300
b 600
c 1050
d 1200
e 1500
dtype: int64

serie3 = serie3[:2] + serie2[:2]

Out:
a 400
b 800
dtype: int64


DATAFRAME:

Un Dataframe è un 2-dimensional labeled data structure e può contenere :
Dictionary of 1D ndarrays, lists, dictionary o Series
2-D numpy.ndarray
Structured or record ndarray
un altro DataFrame

Vediamo degli esempi di cosa possiamo fare:

DATAFRAME FROM SERIES

df1= {'one': serie1,
'two': serie2,
'tre': serie3}

df = pd.DataFrame(df1)

Out:
one two three
a 1 100 400.0
b 2 200 800.0
c 3 350 NaN
d 4 400 NaN
e 5 500 NaN


DATAFRAME FROM DICTIONARY :

df_from_dict = [{'alfa': 1, 'beta': 2,'a3':3 }, {'alfa': 100, 'beta': 101, 'gamma': 105}]
df = pd.DataFrame(df_from_dict)

Out:
alfa beta a3 gamma
0 1 2 3.0 Nan
1 100 101 Nan 105.0

DATAFRAME FROM FILE :

df = pd.read_csv('path/nome_file')

Out:
alfa gamma beta
0 1 12 33
1 2 1 33
2 3 12 33
3 4 1 1
4 5 12 2

SELECT DATA FROM COLUMN:

df1=df['alfa'] // otteniamo una series

Out:
0 1
1 2
2 3
3 4
4 5
Name: alfa, dtype: int64

SELECT DATA FROM ROW:

Prima carico i dati da file con indice presente nel file csv.
df = pd.read_csv('/path/data.csv', index_col='index')

index alfa gamma beta
a 1 12 33
b 2 1 33
c 3 12 33
d 4 1 1
e 5 12 2

s1 = df.loc['a'] //loc[label row] out = Series

Out:
alfa 1
gamma 12
beta 33
Name: a, dtype: int64

s2 = df.iloc[2] //iloc[number row] out = Series

Out:
alfa 3
gamma 12
beta 33
Name: c, dtype: int64

df4 = df[2:4] //slice out = DataFrame

Out:
index alfa gamma beta
c 3 12 33
d 4 1 1

QUERY:

Select con diversi parametri e con il metodo query

df5 = df[(df['gamma'] > 10)] //select by parameter out = DataFrame

Out:
index alfa gamma beta
a 1 12 33
c 3 12 33
e 5 12 2

Select con parametri multipli:

df6 = df[(df['alfa'] == 1) & (df['gamma'] == 12)] //select multiple parameter

Out:
index alfa gamma beta
a 1 12 33

df.query('(alfa == 1) & (gamma == 12)')

Out:
index alfa gamma beta
a 1 12 33

df[::3]

Out:
index alfa gamma beta
a 1 12 33
d 4 1 1

df[1:3] //da 1 a 3

Out:
index alfa gamma beta
b 2 1 33
c 3 12 33

df3 & df2

Out:
alfa 1
gamma 12
beta 33
dtype: int64

df3 | df2

Out:
alfa 3
gamma 12
beta 33
dtype: int64

OPERAZIONI MATEMATICHE NEI DATAFRAME:

df - df.loc['a']

index alfa gamma beta
a 0 0 0
b 1 -11 0
c 2 0 0
d 3 -11 -32
e 4 0 -31

df + df.iloc[3]

index alfa gamma beta
a 5 13 34
b 6 2 34
c 7 13 34
d 8 2 2
e 9 13 3

Principali metodi applicabili ad un DataFrame :

'abs', 'add', 'add_prefix', 'add_suffix', 'agg', 'aggregate', 'alfa', 'align', 'all', 'any', 'append', 'apply', 'applymap', 'asfreq', 'asof', 'assign', 'astype', 'at', 'at_time', 'attrs', 'axes', 'beta', 'between_time', 'bfill', 'bool', 'boxplot', 'clip', 'columns', 'combine', 'combine_first', 'convert_dtypes', 'copy', 'corr', 'corrwith', 'count', 'cov', 'cummax', 'cummin', 'cumprod', 'cumsum', 'describe', 'diff', 'div', 'divide', 'dot', 'drop', 'drop_duplicates', 'droplevel', 'dropna', 'dtypes', 'duplicated', 'empty', 'eq', 'equals', 'eval', 'ewm', 'expanding', 'explode', 'ffill', 'fillna', 'filter', 'first', 'first_valid_index', 'floordiv', 'from_dict', 'from_records', 'gamma', 'ge', 'get', 'groupby', 'gt', 'head', 'hist', 'iat', 'idxmax', 'idxmin', 'iloc', 'index', 'infer_objects', 'info', 'insert', 'interpolate', 'isin', 'isna', 'isnull', 'items', 'iteritems', 'iterrows', 'itertuples', 'join', 'keys', 'kurt', 'kurtosis', 'last', 'last_valid_index', 'le', 'loc', 'lookup', 'lt', 'mad', 'mask', 'max', 'mean', 'median', 'melt', 'memory_usage', 'merge', 'min', 'mod', 'mode', 'mul', 'multiply', 'ndim', 'ne', 'nlargest', 'notna', 'notnull', 'nsmallest', 'nunique', 'pct_change', 'pipe', 'pivot', 'pivot_table', 'plot', 'pop', 'pow', 'prod', 'product', 'quantile', 'query', 'radd', 'rank', 'rdiv', 'reindex', 'reindex_like', 'rename', 'rename_axis', 'reorder_levels', 'replace', 'resample', 'reset_index', 'rfloordiv', 'rmod', 'rmul', 'rolling', 'round', 'rpow', 'rsub', 'rtruediv', 'sample', 'select_dtypes', 'sem', 'set_axis', 'set_index', 'shape', 'shift', 'size', 'skew', 'slice_shift', 'sort_index', 'sort_values', 'squeeze', 'stack', 'std', 'style', 'sub', 'subtract', 'sum', 'swapaxes', 'swaplevel', 'tail', 'take', 'to_clipboard', 'to_csv', 'to_dict', 'to_excel', 'to_feather', 'to_gbq', 'to_hdf', 'to_html', 'to_json', 'to_latex', 'to_markdown', 'to_numpy', 'to_parquet', 'to_period', 'to_pickle', 'to_records', 'to_sql', 'to_stata', 'to_string', 'to_timestamp', 'to_xarray', 'transform', 'transpose', 'truediv', 'truncate', 'tshift', 'tz_convert', 'tz_localize', 'unstack', 'update', 'values', 'var', 'where', 'xs']

APPEND:

df.append(df,ignore_index = True) //append altro DataFrame senza tener conto degli indici

Out:
index alfa gamma beta
0 1 12 33
1 2 1 33
2 3 12 33
3 4 1 1
4 5 12 2
5 1 12 33
6 2 1 33
7 3 12 33
8 4 1 1
9 5 12 2

dfapp = df.append(df,ignore_index = False) //append altro DataFrame mantenendo indici

Out:
index alfa gamma beta
a 1 12 33
b 2 1 33
c 3 12 33
d 4 1 1
e 5 12 2
a 1 12 33
b 2 1 33
c 3 12 33
d 4 1 1
e 5 12 2


TRASFORMARE DATAFRAME IN ARRAY:

array1 = np.asarray(dfapp) //creo array con i dati del DataFrame

Out:
array([[ 1, 12, 33],
[ 2, 1, 33],
[ 3, 12, 33],
[ 4, 1, 1],
[ 5, 12, 2],
[ 1, 12, 33],
[ 2, 1, 33],
[ 3, 12, 33],
[ 4, 1, 1],
[ 5, 12, 2]])


SAVE DATAFRAME AS CSV:

nome_dataFrame.to_csv('path/output.csv', index=False, header=False)

Si può gestire con i parametri se salvare indici e/o header

NUMPY

Numpy è una libreria molto importante di Python utile per elaborare tramite gli array i dati per il machine learning. Innanzi tutto importiamo la libreria:
import numpy as np

CREAZIONE ARRAY


a = np.ones((3,4),dtype=np.int8) //creare array di tutti 1
array([[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]], dtype=int8)
a[1,1] = 2 //modifichiamo il valore dell'elemento con coordinate 1,1
array([[1, 1, 1, 1], [1, 2, 1, 1], [1, 1, 1, 1]], dtype=int8)
b = np.zeros((3,3,2),dtype=np.int) //crea array di tutti 0
array([[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]])
c = np.random.random((3,3))
array([[0.51958235, 0.97222284, 0.05322551], [0.75779435, 0.14079785, 0.87762524], [0.88294465, 0.18826504, 0.78701276]])
d = np.linspace(0,5,10) //crea array con 10 elementi con valori da 0 a 5
array([0. , 0.55555556, 1.11111111, 1.66666667, 2.22222222, 2.77777778, 3.33333333, 3.88888889, 4.44444444, 5. ])
e = np.arange(1,10,2) //crea array con values da start a stop e step
array([1, 3, 5, 7, 9])
f = np.empty(4) //crea array vuoto ma il vengono assegnati valori random
array([5., 0., 0., 2.])
g = np.full((3,3),'a') //crea array pieno con valore assegnato
array([['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']], dtype='U1')
h = np.eye(5) //crea Identity matrix
array([[1., 0., 0., 0., 0.], [0., 1., 0., 0., 0.], [0., 0., 1., 0., 0.], [0., 0., 0., 1., 0.], [0., 0., 0., 0., 1.]])
I = np.identity(2) //crea Identity matrix
array([[1., 0.], [0., 1.]])
mat = np.array([[5,7],[3,2]])
array([[5, 7], [3, 2]])
Nmat = mat * I //moltiplicazione con Identity matrix
array([[5., 0.], [0., 2.]])
CARATTERISTICHE ARRAY:

DIMENSIONE:
len(Nmat) : 2

Nmat.ndim : 2 //n.ro dimwnsioni

Nmat.size : 4 //size

Nmat.shape : 2, 2 //shape

Nmat.flags :

C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
WRITEABLE : True
ALIGNED : True
WRITEBACKIFCOPY : False
UPDATEIFCOPY : False

Nmat.itemsize : 8

Nmat.nbytes : 32
SLICE e SELEZIONE :

ns = Nmat[1,1]
2.0
ns2 = Nmat[1:]
array([[0., 2.]])
ns3 = Nmat[:1]
array([[5., 0.]])
ns4 = Nmat > 3
array([[ True, False], [False, False]])
ns5 = Nmat < 1
array([[False, True], [ True, False]])
ns6 = (Nmat > 3) | (Nmat == 0 )
array([[ True, True], [ True, False]])
MODIFICARE UN ARRAY:

MODIFICARE TYPE DATI

Nmat.astype(int) //da float a int
array([[5, 0], [0, 2]])
RESHAPE

array a con shape 3 x 4

array([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], dtype=int8)
res = a.reshape(4,3)
array([[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]], dtype=int8)
RESIZE

a.resize(3,3, refcheck=False)
array([[1, 1, 1], [1, 1, 1], [1, 1, 1]], dtype=int8)
RAVEL -- flatten array

aa = a.ravel()
array([1, 1, 1, 1, 1, 1, 1, 1, 1], dtype=int8)
INSERT

np.insert(a, 1, 5,axis=0)
array([[1, 1, 1], [5, 5, 5], [1, 1, 1], [1, 1, 1]], dtype=int8)
DELETE

aa = np.delete(aa,[1], axis=1)
array([[1, 1], [5, 5], [1, 1], [1, 1]], dtype=int8)
CARICARE DATI DA FILE IN UN ARRAY

CARICAMENTO CON SPACCHETTAMENTO
alfa, gamma, beta = np.loadtxt('path/data.csv', skiprows=1,delimiter=',', unpack=True)
alfa array([1., 2., 3., 4., 5.]) gamma array([12., 1., 12., 1., 12.]) beta array([33., 33., 33., 1., 2.])
CARICAMENTO SENZA SPACCHETTAMENTO
arrayfromtext= np.loadtxt('path/data.csv', skiprows=1,delimiter=',', unpack=False)
array([[ 1., 12., 33.], [ 2., 1., 33.], [ 3., 12., 33.], [ 4., 1., 1.], [ 5., 12., 2.]])
CARICARE ARRAY CON DATI DA FILE

Nella Tabella sottostante i dati contenuti nel file

alfa gamma beta
1 12 33
2 1 33
3 12
4 1 1
12 2


CARICARE ARRAY CON DATI DA FILE E DOVE NON CI SONO VALORI INSERIAMO 0
(altrimenti ci sarebbero dei NaN)
arrayfromtext2 = np.genfromtxt('path/data.csv', skip_header=1,delimiter=',', filling_values=0)
array([[ 1., 12., 33.], [ 2., 1., 33.], [ 3., 12., 0.], [ 4., 1., 1.], [ 0., 12., 2.]])
arrayfromtext2[0,1] = 50
array([[ 1., 50., 33.], [ 2., 1., 33.], [ 3., 12., 33.], [ 4., 1., 1.], [ 5., 12., 2.]])
head = np.array([['alfa' ,'gamma','beta']])

arrayfromtext2 =np.append(head, arrayfromtext2 ,axis=0)

arrayflatten =np.append(head, arrayfromtext2 )
array(['alfa', 'gamma', 'beta', '1.0', '50.0', '33.0', '2.0', '1.0', '33.0', '3.0', '12.0', '33.0', '4.0', '1.0', '1.0', '5.0', '12.0', '2.0'], dtype='U32')
SALVATAGGIO ARRAY IN UN FILE

np.savetxt('path/data.csv', arrayfromtext2, fmt='%s', delimiter=',')

np.save('path/data', arrayfromtext2) //save file binary .npy

np.savez('path/data', arrayfromtext2) //save file binary non compresso .npz

np.savez_compressed('path/dataz', arrayfromtext2) //save file binary compresso .npz

ALGEBRA LINEARE CON NUMPY

Iniziamo con caricare i dati di un vettore v = [1,3,5,7,9] ed uno scalare sca = 5 e moltiplichiamo il vettore per lo scalare.
v = np.array([1,3,5,7,9])
sca = 5
vsca = v * sca
ed otteniamo
array([ 5, 15, 25, 35, 45])
Ora vediamo la somma e la differenza tra i vettori già definiti v e vsca
sommav = vsca + v
sottv = abs(v - vsca)
con i relativi risultati
array([ 6, 18, 30, 42, 54])
array([ 4, 12, 20, 28, 36])
La moltiplicazione o divisione sono le 2 operazioni seguenti seguita dal prodotto scalare che riporta coma risultato uno scalare
mol = v * vsca
div = mol / v
pscal = np.dot(v, vsca) //prodotto scalare
array([ 5, 45, 125, 245, 405]) //mol
array([ 5., 15., 25., 35., 45.]) //div
825 //pscal
MATRICI

Vediamo ora il prodotto tra matrici (linee per colonne) caricando prima la mat1 e mat2 La 2 matrici devono essere compatibili n.ro colonne mat1 == n.ro righe mat2. In questo caso abbiamo mat1 2 colonne e mat2 2 righe ed otteniamo una nuova mattrice con shape 2X3
mat1 = np.array([[1,2],[3,4]])
mat2 = np.array([[5,6,7],[8,9,10]])

mat3 = np.dot(mat1,mat2)
//Prodotto tra matrici riga x colonna mat3.shape
array([[21, 24, 27],
[47, 54, 61]])
(2, 3) //mat3 shape
Con la funzione dot è possibile anche ottenere il prodotto tra vettori e tra metrice e vettore sempre tra linee e colonne

Proseguiamo nell'analisi della algebra lineare con Numpy e vediamo le funzioni e metodi che ci mette a disposizione

alg = np.linalg
dir(alg)
Lista funzioni e metodi

'absolute_import', 'cholesky', 'cond', 'det', 'division', 'eig', 'eigh', 'eigvals', 'eigvalsh', 'inv', 'lapack_lite', 'linalg', 'lstsq', 'matrix_power', 'matrix_rank', 'multi_dot', 'norm', 'pinv', 'print_function', 'qr', 'slogdet', 'solve', 'svd', 'tensorinv', 'tensorsolve', 'test'
Vediamone alcuni in azione

inv - calcola la matrice inversa
det - calcola il determinante di una matrice
eigvals - calcola il valore Eigenvalue di una matrice quadrata
solve - risolve un sistema lineare di equazioni

Per questi esempi prendiamo i dati da un esercizio svolto alla pagina di Algebra Lineare al seguente link Algebra Lineare

Esempio di come trovare 3 incognite di un sistema lineare di equazioni con solve

M = np.array([[-1,3,1],[2,3,1],[3,2,1]] )
b= np.array([3.54515,5.59135,5.19768 ])
var = alg.solve(M,b)
Vediamo i risultati ottenuti
array([[-1, 3, 1], //matrice con coefficienti equazioni
[ 2, 3, 1],
[ 3, 2, 1]])

array([3.54515, 5.59135, 5.19768]) //b risultato equazioni

array([0.68206667, 1.07573667, 1.00000667]) //risultato x=0.68, y=1.07, z=1
Ora vediamo per la matrice M il calcolo del valore Eigenvalue poi sempre della stessa matrice troviamo il determinante e la matrice inversa
eigenv = alg.eigvals(M) //calcolo Eigenvalue
deter = alg.det(M) //calcolo Determinante
inv = alg.inv(M) //calcolo matrice inversa
array([ 5.19767753, -2.43473828, 0.23706074]) //Eigenvalue

-3.0000000000000004 //determinante

array([[-0.33333333, 0.33333333, 0. ], //matrice inversa
[-0.33333333, 1.33333333, -1. ],
[ 1.66666667, -3.66666667, 3. ]])