# Introduzione a Pandas¶

Pandas è una libreria Python per l'analisi e l'esplorazione dei dati.

Pandas fornisce strutture dati e funzioni di manipolazione dati di facile accesso, grazie ad un'indicizzazione integrata.

Le due principali strutture dati fornite da Pandas sono le Series e i DataFrame. Le `Series` rappresentano dei vettori (unidimensionali) indicizzabili. I `DataFrame` rappresentano dati tabellari (bidimensionali) indicizzabili.

Le principali funzionalità offerte da Pandas sono:

- Generazione di statistiche e grafici
- Pulizia dei dati
- Selezione, filtraggio, inserimento, cancellazione ed aggregazione dei dati
- Importazione/esportazione dei dati da file in vari formati

Per qualunque ulteriore approfondimento è sempre utile consultare la documentazione ufficiale Pandas (sempre accessibile dal menu Help di Jupyter o scrivendo `?nome_di_funzione`).

## Importare il modulo Pandas¶

In [1]:

    import pandas as pd
    %matplotlib inline

# Esempio: Caricamento del dataset `Advertising`¶

In [2]:

    df = pd.read_csv('data/Advertising.csv')

In [3]:

    df

Out[3]:

| Unnamed: 0 | TV | radio | newspaper | sales
--- | --- | --- | --- | --- | ---
0 | 1 | 230.1 | 37.8 | 69.2 | 22.1
1 | 2 | 44.5 | 39.3 | 45.1 | 10.4
2 | 3 | 17.2 | 45.9 | 69.3 | 9.3
3 | 4 | 151.5 | 41.3 | 58.5 | 18.5
4 | 5 | 180.8 | 10.8 | 58.4 | 12.9
... | ... | ... | ... | ... | ...
195 | 196 | 38.2 | 3.7 | 13.8 | 7.6
196 | 197 | 94.2 | 4.9 | 8.1 | 9.7
197 | 198 | 177.0 | 9.3 | 6.4 | 12.8
198 | 199 | 283.6 | 42.0 | 66.2 | 25.5
199 | 200 | 232.1 | 8.6 | 8.7 | 13.4

200 rows × 5 columns

La prima colonna (`Unnamed: 0`) è inutile. Rimuoviamola per nome:

In [4]:

    df = df.drop('Unnamed: 0', axis=1)

L'opzione `axis=1` indica che vogliamo rimuovere una colonna. (Con `axis=0` avremmo rimosso una riga).

In [5]:

    df

Out[5]:

| TV | radio | newspaper | sales
--- | --- | --- | --- | ---
0 | 230.1 | 37.8 | 69.2 | 22.1
1 | 44.5 | 39.3 | 45.1 | 10.4
2 | 17.2 | 45.9 | 69.3 | 9.3
3 | 151.5 | 41.3 | 58.5 | 18.5
4 | 180.8 | 10.8 | 58.4 | 12.9
... | ... | ... | ... | ...
195 | 38.2 | 3.7 | 13.8 | 7.6
196 | 94.2 | 4.9 | 8.1 | 9.7
197 | 177.0 | 9.3 | 6.4 | 12.8
198 | 283.6 | 42.0 | 66.2 | 25.5
199 | 232.1 | 8.6 | 8.7 | 13.4

200 rows × 4 columns

In [6]:

    df.info()

    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 200 entries, 0 to 199
    Data columns (total 4 columns):
     #   Column     Non-Null Count  Dtype
    ---  ------     --------------  -----
     0   TV         200 non-null    float64
     1   radio      200 non-null    float64
     2   newspaper  200 non-null    float64
     3   sales      200 non-null    float64
    dtypes: float64(4)
    memory usage: 6.4 KB

In [7]:

    df.describe().transpose()

Out[7]:

| count | mean | std | min | 25% | 50% | 75% | max
--- | --- | --- | --- | --- | --- | --- | --- | ---
TV | 200.0 | 147.0425 | 85.854236 | 0.7 | 74.375 | 149.75 | 218.825 | 296.4
radio | 200.0 | 23.2640 | 14.846809 | 0.0 | 9.975 | 22.90 | 36.525 | 49.6
newspaper | 200.0 | 30.5540 | 21.778621 | 0.3 | 12.750 | 25.75 | 45.100 | 114.0
sales | 200.0 | 14.0225 | 5.217457 | 1.6 | 10.375 | 12.90 | 17.400 | 27.0

In [8]:

    df['TV'].hist(bins=50);

In [9]:

    df.boxplot(['TV', 'radio', 'newspaper']);

Interpretazione di un box plot:

- La linea verde rappresenta la mediana (50% percentile o secondo quartile, Q2)
- Il rettangolo (box) delimita il primo e terzo quartile, Q1 e Q3 (25% e 75% percentili)
- I "baffi" (whiskers) sono ottenuti calcolando la distanza interquantile IQR = Q3 - Q1 e considerando il range R = [Q1 - 1.5 IQR, Q3 + 1.5 IQR]
- Il baffo superiore rappresenta la massima osservazione che rientra nel range R
- Il baffo inferiore rappresenta la minima osservazione che rientra nel range R
- I cerchietti rappresentano osservazioni al di fuori del range R (gli outlier)

### Esploriamo le correlazioni tra le variabili¶

In [10]:

    df.plot.scatter('TV', 'sales', alpha=0.5, figsize=(12, 8));

Il coefficiente di correlazione di Pearson tra due vettori di osservazioni $x$ e $y$ è definito come:

$$ \rho_{xy} = \frac{\sum_{i=1}^m (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum_{i=1}^m (x_i - \bar{x})^2} \cdot \sqrt{\sum_{i=1}^m (y_i - \bar{y})^2}} $$

dove $\bar{x}$ è la media degli $x_i$ e $\bar{y}$ la media degli $y_i$.

E' un valore tra -1 e +1, pari a +1 se le variabili sono perfettamente correlate, a 0 se sono scorrelate e a -1 se sono perfettamente anticorrelate.

Calcoliamo il coefficiente di correlazione tra `TV` e `sales`:

In [11]:

    df['TV'].corr(df['sales'])

Out[11]:

    0.7822244248616061

In [12]:

    from pandas.plotting import scatter_matrix
    scatter_matrix(df, figsize=(20, 15), hist_kwds={'bins':50});