Un'analisi dell'attrattività turistica dell'Italia

Attività preliminari

L'analisi è condotta su dati UNWTO distribuiti da The World Bank e ottenuti attraverso Quandl. Iniziamo importando Pandas e Matplotlib e settando i grafici all'interno del Notebook.

In [26]:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
%pylab inline
Populating the interactive namespace from numpy and matplotlib

Importiamo il pacchetto Quandl, che ci permette di accedere nativamente alle API del servizio. L'accesso anonimo è limitato, la registrazione al sito permette di ottenere un TOKEN da utilizzare per ampliare il numero di richieste quotidiane.

In [27]:
import Quandl as Q
TOKEN = '*****' # Da sostituire con il TOKEN ottenuto alla registrazione su Quandl

Gli arrivi turistici internazionali

Volendo importare le serie storiche di più paesi, utilizziamo la funzione descritta in questo utile Notebook, che consente di estrarre i codici paesi dalla pagina web di Quandl. Dalla stessa pagina sono tratte le altre funzioni di dowload dei dati utilizzate, eventualmente riadattate modificando opportunamente le stringhe di richiesta.

In [28]:
import re
import urllib2

def get_quandl_country_code(url, pattern):
    """ Get the country code from an URL and a pattern.
    
    Suppose your pattern have the 'country' group name.
    """
    rawtext = urllib2.urlopen(url).read()
    regexp = re.compile(pattern)
    return [m.group('country') for m in regexp.finditer(rawtext)]

Limitiamo la nostra analisi ai paesi del G20: i dati sono disposibili per 382 nazioni, fino a Tuvalu, che è lo stato meno frequentato dai turisti (10.000 - 20.000 presenze all'anno).

In [29]:
URL = 'http://www.quandl.com/society/international-tourism-arrivals-all-countries'
PATTERN = r'WORLDBANK/(?P<country>[A-Z]+)_ST_INT_ARVL'
country_code = get_quandl_country_code(URL, PATTERN)[:20] # [:20] --> Paesi del G20
print 'Nb countries', len(country_code), ': ', country_code
Nb countries 20 :  ['USA', 'CHN', 'JPN', 'DEU', 'FRA', 'BRA', 'GBR', 'ITA', 'RUS', 'IND', 'CAN', 'AUS', 'ESP', 'MEX', 'KOR', 'IDN', 'TUR', 'SAU', 'ARG', 'ZAF']

Nuova formula per scaricare le serie storiche inserendo via via il codice del paese del G20.

In [30]:
def get_quandl_dataset(code, name=None):
    """ Get a Pandas DataFrame from the Quandl website according to the code.
    
    name: str or list
        The name(s) of the col label.
    """
    df = Q.get(code, authtoken=TOKEN)
    if name:
        name = [name] if isinstance(name, str) else name
        df.columns = pd.Index(name)
    return df

A questo punto, scarichiamo le 20 serie storiche degli arrivi turistici internazionali concatenandole in un unico dataframe.

In [31]:
code = PATTERN.replace(r"(?P<country>[A-Z]+)", "%s")
inbound = pd.concat([get_quandl_dataset(code % name, name) for name in country_code], axis=1)
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/USA_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/CHN_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/JPN_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/DEU_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/FRA_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/BRA_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/GBR_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/ITA_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/RUS_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/IND_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/CAN_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/AUS_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/ESP_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/MEX_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/KOR_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/IDN_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/TUR_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/SAU_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/ARG_ST_INT_ARVL
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/ZAF_ST_INT_ARVL

Diamo un'occhiata alla classifica degli arrivi in base agli ultimi dati disponibili, del 2011. Al primo posto la Francia, con oltre 81 milioni di presenze annue, seguita da Stati Uniti (63 milioni) e Cina (58 milioni). L'Italia è quinta (46 milioni), preceduta dalla Spagna (57 milioni); seguono Turchia e gli altri paesi fino a chiudere la classifica con il Brasile (5,4 milioni)

In [32]:
inbound.loc['2011-12-31', :].order(ascending=False)
Out[32]:
FRA    81411000
USA    62711000
CHN    57581000
ESP    56694000
ITA    46119000
TUR    34038000
GBR    29306000
DEU    28374000
RUS    24932000
MEX    23403000
SAU    17498000
CAN    16014000
KOR     9795000
ZAF     8339000
IDN     7650000
IND     6309000
JPN     6219000
AUS     5875000
ARG     5705000
BRA     5433000
Name: 2011-12-31 00:00:00, dtype: float64

Creiamo una funzione per disegnare un grafico a barre della serie degli arrivi internazionali 2011.

In [33]:
def bar_chart(series, title='', xlabel= '', ylabel=''):
    """ Plot a bar chart from a Pandas series. 
    
    title: str
        The title of the chart.
    xlabel: str
        The label of x-axis.
    ylabel: str
        The label of y-axis.
    """
    fig = plt.figure(figsize=(10,10))
    ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
    ax.set_title(title)
    x = np.arange(len(series.values))
    ax.bar(x, series.values)
    ax.set_xticks(x + 0.4)
    ax.set_xticklabels(series.index)
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
    plt.show()

Disegniamo ora il grafico.

In [34]:
bar_chart(inbound.loc['2011-12-31', :].order(ascending=False), title='Arrivi turistici internazionali 2011', ylabel='Decine milioni')

Variazione dei flussi turistici

Ora proviamo ad analizzare la variazione dei flussi turistici dal 1995 (primo dato disponibile sul DB The World Bank) al 2011. Spiccano i paesi emergenti: Arabia Saudita (+426%), Turchia (+381%), India (+197%), Cina (+187%). Tra le economie sviluppate, notevole il dato tedesco (+91%) e Giapponese (+86%). L'Europa, con gli Stati Uniti, segue: Spagna (+62%), Italia (+49%), USA (+44%), Francia (+36%), Gran Bretagna (+35%). Chiude la classifica il Canada, unico paese del G20 con una riduzione del flusso turistico (-5%).

In [35]:
(inbound.loc['2011-12-31', :] / inbound.loc['1995-12-31', :] - 1).order(ascending=False)
Out[35]:
SAU    4.262556
TUR    3.805591
IND    1.970339
CHN    1.874164
BRA    1.728780
KOR    1.609912
ARG    1.492355
RUS    1.422935
DEU    0.911093
JPN    0.859193
ZAF    0.858066
IDN    0.769195
ESP    0.623540
AUS    0.576758
ITA    0.485218
USA    0.441964
FRA    0.356104
GBR    0.349325
MEX    0.156218
CAN   -0.054217
dtype: float64

Disegniamo il grafico anche delle variazioni del flusso turistico.

In [36]:
bar_chart((inbound.loc['2011-12-31', :] / inbound.loc['1995-12-31', :] - 1).order(ascending=False), title='Arrivi turistici internazionali: variazione 1995 - 2011', ylabel='Variazione assoluta')

Il peso del turismo sulle esportazioni

Analizziamo ora il peso del turismo sul totale dell'export dei paesi del G20. I dati sono sempre UNWTO via The World bank, via Quandl.

In [37]:
URL2 = 'http://www.quandl.com/society/international-tourism-receipts-all-countries'
PATTERN2 = r'WORLDBANK/(?P<country>[A-Z]+)_ST_INT_RCPT_XP_ZS'
country_code = get_quandl_country_code(URL2, PATTERN2)[:20] # [:20] --> Paesi del G20
print 'Nb countries', len(country_code), ': ', country_code
Nb countries 20 :  ['USA', 'CHN', 'JPN', 'DEU', 'FRA', 'BRA', 'GBR', 'ITA', 'RUS', 'IND', 'CAN', 'AUS', 'ESP', 'MEX', 'KOR', 'IDN', 'TUR', 'SAU', 'ARG', 'ZAF']

Scarichiamo i relativi dati da Quandl.

In [38]:
code = PATTERN2.replace(r"(?P<country>[A-Z]+)", "%s")
inrecpt = pd.concat([get_quandl_dataset(code % name, name) for name in country_code], axis=1)
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/USA_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/CHN_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/JPN_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/DEU_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/FRA_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/BRA_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/GBR_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/ITA_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/RUS_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/IND_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/CAN_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/AUS_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/ESP_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/MEX_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/KOR_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/IDN_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/TUR_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/SAU_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/ARG_ST_INT_RCPT_XP_ZS
Token ***** activated and saved for later use.
Returning Dataframe for  WORLDBANK/ZAF_ST_INT_RCPT_XP_ZS

Verifichiamo i dati 2011. I paesi per i quali il turismo pesa di più sono Turchia e Spagna (15%), Australia (11%), Sudafrica, USA e Francia (8%-9%). Segue l'Italia (7%) e via via gli altri paesi fino a Brasile (2%) e Giappone (1%).

In [39]:
inrecpt.loc['2011-12-31', :].order(ascending=False)
Out[39]:
TUR    15.210521
ESP    15.115124
AUS    10.567434
ZAF     9.098325
USA     8.831108
FRA     8.103430
ITA     7.449589
ARG     6.098316
GBR     5.939283
IDN     4.223467
IND     4.011339
CAN     3.651600
MEX     3.359407
DEU     2.983771
RUS     2.969929
CHN     2.678157
KOR     2.665438
SAU     2.481500
BRA     2.321163
JPN     1.351666
Name: 2011-12-31 00:00:00, dtype: float64

E creiamo un grafico.

In [40]:
bar_chart(inrecpt.loc['2011-12-31', :].order(ascending=False), title='Peso entrate turistiche internazionali su esportazioni', ylabel='Percentuale')

I siti World Heritage dell'Unesco

Proviamo ora ad analizzare il peso del turismo correlandolo al numero di siti nazionali classificati come World Heritage dall'UNESCO. I dati sono reperibili nella pagina web della World Heritage Convention e limitiamo come prima il campo d'azione ai paesi del G20.

In [41]:
whc_dict = {'USA': 21, 'CHN': 45, 'JPN': 17, 'DEU': 38, 'FRA': 38, 'BRA': 19, 'GBR': 28, 'ITA': 49, 'RUS': 25, 'IND': 30, 'CAN': 17, 'AUS': 19, 'ESP': 44, 'MEX': 32, 'KOR': 10, 'IDN': 8, 'TUR': 11, 'SAU': 2, 'ARG': 8, 'ZAF': 8}
whc = pd.DataFrame.from_dict(whc_dict, orient='index')
whc.columns = ['WHC']
whc['WHC'].order(ascending=False)
Out[41]:
ITA    49
CHN    45
ESP    44
DEU    38
FRA    38
MEX    32
IND    30
GBR    28
RUS    25
USA    21
BRA    19
AUS    19
CAN    17
JPN    17
TUR    11
KOR    10
ARG     8
IDN     8
ZAF     8
SAU     2
Name: WHC, dtype: int64

Anche in questo caso, possiamo fare un grafico. L'Italia è la nazione con il maggior numero di siti tutelati dall'Unesco (49), seguita da Cina, Spagna, Germania e Francia. Il paese del G20 che chiude questa classifica è l'Arabia Saudita, con 2 siti.

In [42]:
bar_chart(whc['WHC'].order(ascending=False), title='Siti World Heritage per nazione', ylabel='# siti')

Un'analisi complessiva

Ora aggiungiamo qualche dato turistico al dataframe dei siti Unesco.

In [43]:
whc['Inbound'] = inbound.loc['2011-12-31', :]
whc['Ingrowth'] = (inbound.loc['2011-12-31', :] / inbound.loc['1995-12-31', :] - 1)
whc['Inreceipts'] = inrecpt.loc['2011-12-31', :]
whc
Out[43]:
WHC Inbound Ingrowth Inreceipts
SAU 2 17498000 4.262556 2.481500
FRA 38 81411000 0.356104 8.103430
USA 21 62711000 0.441964 8.831108
JPN 17 6219000 0.859193 1.351666
ZAF 8 8339000 0.858066 9.098325
TUR 11 34038000 3.805591 15.210521
ESP 44 56694000 0.623540 15.115124
DEU 38 28374000 0.911093 2.983771
CHN 45 57581000 1.874164 2.678157
ITA 49 46119000 0.485218 7.449589
IDN 8 7650000 0.769195 4.223467
AUS 19 5875000 0.576758 10.567434
GBR 28 29306000 0.349325 5.939283
CAN 17 16014000 -0.054217 3.651600
ARG 8 5705000 1.492355 6.098316
IND 30 6309000 1.970339 4.011339
RUS 25 24932000 1.422935 2.969929
KOR 10 9795000 1.609912 2.665438
MEX 32 23403000 0.156218 3.359407
BRA 19 5433000 1.728780 2.321163

20 rows × 4 columns

Creiamo un grafico a bolle per analizzare le relazioni tra questi dati. Riadattiamo a tale scopo le funzioni utilizzate in questo interessante post.

In [44]:
def bubble_chart(df, x=0, y=1, r=2, c=3, title='', xlabel='', ylabel=''):
    """ Plot a bubble chart.
    
    x: int
        Column of df for x data.
    y: int
        Column of df for y data.
    r: int
        Column of df for area data.
    c: int
        Column of df for color data.
    title: str
        The title of the chart.
    xlabel: str
        The label of x-axis.
    ylabel: str
        The label of y-axis.
    """
    fig = plt.figure(figsize=(10,10))
    ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
    ax.set_title(title)
    dx = df.iloc[:, x]
    dy = df.iloc[:, y]
    dr = df.iloc[:, r] * 2000 # La costante aggiusta l'area delle bolle in modo che sia chiaramente visibile
    dc = np.log(df.iloc[:, c]) # Il logaritmo serve per modificare la scala di colori riducendo le tonalità scure
    sct = ax.scatter(dx, dy, c=dc, s=dr)
    sct.set_alpha(0.3)
    for t in df.index:
        ax.text(df.loc[t, :].iloc[x], df.loc[t, :].iloc[y], t, ha='center', va='center')
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
    plt.show()    
    

Infine disegniamo il grafico. Sull'asse delle ascisse abbiamo il numero si siti classificati dall'Unesco come World Heritage, sull'asse delle ordinate gli arrivi internazionali del 2011, mentre l'area delle bolle è proporzionale alla variazione dei flussi turistici 1995 - 2011 e il colore rappresenta il peso sulle esportazioni (ordinato in senso crescente dai colori freddi ai colori caldi). In questo contesto l'Italia appare "sottovalutata" come meta turistica rispetto al patrimonio Unesco e caratterizzata da una crescita dei flussi turistici inferiore alla media, mentre il peso del turismo sulle esportazioni è superiore alla media. Altri paesi appaiono "sottovalutati", ma - ad eccezione del Regno Unito e soprattutto del Canada - presentano tassi di sviluppo ben superiori a quello italiano.

In [45]:
bubble_chart(whc, title='Analisi flussi turistici internazionali', xlabel='# Siti World Heritage Unesco', ylabel='Arrivi internazionali 2011 (decine milioni)')

Crediti

Parte delle funzioni e del codice utilizzato per l'interazione con le API di Quandl è stato preso o riadattato dal lavoro di Damien Garaud. Qui il blog post cui fa riferimento il suo Notebook.

Il grafico a bolle è stato ispirato dal codice di The Glowing Python.