In [1]:
import pandas as pd
import geopandas as gpd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import os
from shapely import wkt
from jenkspy import jenks_breaks

plt.style.use('seaborn-v0_8-whitegrid')
sns.set_palette('viridis')

Energia verde e consumo di suolo¶

In [2]:
ilab_path = os.path.join(os.path.expanduser('~'),'ILAB_DATA')
work_path = os.path.join(ilab_path,'PATRIMONIO','DATA')
out_path = os.path.join(ilab_path,'PATRIMONIO','OUT')
In [3]:
resolution = 8
In [4]:
file_path = os.path.join(out_path, f"grid_{resolution:02}_adv.csv")
df = pd.read_csv(file_path)
print(f"Dataset caricato con {df.shape[0]} righe e {df.shape[1]} colonne")
Dataset caricato con 2286 righe e 336 colonne
In [5]:
# Conversione in geodataframe se possibile
if 'geometry' in df.columns:
    try:
        df['geometry'] = df['geometry'].apply(wkt.loads)
        print("Geometria convertita correttamente")
    except Exception as e:
        print(f"Errore nella conversione della geometria: {e}")
Geometria convertita correttamente
In [6]:
# Controllo dei valori mancanti
missing_values = df.isnull().sum()
print("\nValori mancanti per colonna:")
missing_values[missing_values > 0]
Valori mancanti per colonna:
Out[6]:
CLC||Agricultural                                 1
CLC||Artificial, non-agricultural vegetated       1
CLC||Forest and semi natural                      1
CLC||Industrial, commercial and transport         1
CLC||Mine, dump and construction                  1
CLC||Urban                                        1
CLC||Water bodies                                 1
CLC||LABEL                                        1
CLC||int_a_m2                                     1
CLC||perc                                         1
ISTAT||POP_F__91                                 42
ISTAT||POP_M__91                                 42
ISTAT||POP_TOT__91                               42
ISTAT||P_0_14__91                                42
ISTAT||P_15_19__91                               42
ISTAT||P_20_39__91                               42
ISTAT||P_40_64__91                               42
ISTAT||P_65_99__91                               42
ISTAT||POP_F__01                                 41
ISTAT||POP_M__01                                 41
ISTAT||POP_TOT__01                               41
ISTAT||P_0_14__01                                41
ISTAT||P_15_19__01                               41
ISTAT||P_20_39__01                               41
ISTAT||P_40_64__01                               41
ISTAT||P_65_99__01                               41
ISTAT||POP_F__11                                 40
ISTAT||POP_M__11                                 40
ISTAT||POP_TOT__11                               40
ISTAT||P_0_14__11                                40
ISTAT||P_15_19__11                               40
ISTAT||P_20_39__11                               40
ISTAT||P_40_64__11                               40
ISTAT||P_65_99__11                               40
ISTAT||POP_F__21                                 39
ISTAT||POP_M__21                                 39
ISTAT||POP_TOT__21                               39
ISTAT||P_0_14__21                                39
ISTAT||P_15_19__21                               39
ISTAT||P_20_39__21                               39
ISTAT||P_40_64__21                               39
ISTAT||P_65_99__21                               39
ISTAT||POP_TOT__21__11                          666
OMI||Compr_min                                  624
OMI||Compr_max                                  624
OMI||Loc_min                                    624
OMI||Loc_max                                    624
airbnb_airbnb||total_airbnb                    1676
airbnb_airbnb||price_avg_airbnb                1682
airbnb_airbnb||beds_sum_airbnb                 1676
beni_immobili_erp||total_erp                   2176
beni_immobili_erp||n_abitazioni_erp            2176
beni_immobili_erp||sup_totale_erp              2176
beni_immobili_erp||sup_media_erp               2176
reddito_pro_capite||redd_cell                   959
reddito_pro_capite||redd_pc                    1005
dtype: int64
In [7]:
df = df.fillna(0)
In [8]:
# Verifica delle colonne relative all'uso del suolo
uso_suolo_cols = [col for col in df.columns if 'CLC||' in col]
print("\nColonne relative all'uso del suolo:")
for col in uso_suolo_cols:
    print(f"{col}")
Colonne relative all'uso del suolo:
CLC||Agricultural
CLC||Artificial, non-agricultural vegetated
CLC||Forest and semi natural
CLC||Industrial, commercial and transport
CLC||Mine, dump and construction
CLC||Urban
CLC||Water bodies
CLC||LABEL
CLC||int_a_m2
CLC||perc

Calcolo percentuali di uso del suolo

In [9]:
for col in [col for col in uso_suolo_cols if col not in ['CLC||LABEL', 'CLC||int_a_m2', 'CLC||perc']]:
    categoria = col.replace('CLC||', '')
    categoria_norm = categoria.lower().replace(' and ', '_').replace(' ', '_')
    # Conversione a numerico per evitare errori
    df[col] = pd.to_numeric(df[col], errors='coerce')
    df['cell_a_m2'] = pd.to_numeric(df['cell_a_m2'], errors='coerce')
    # Calcolo percentuale evitando divisione per zero
    df[f'perc_{categoria_norm}'] = np.where(df['cell_a_m2'] > 0, 
                                            df[col] / df['cell_a_m2'] * 100,
                                            0)

Indice di urbanizzazione¶

In [10]:
# Conversione a numerico
df['CLC||Urban'] = pd.to_numeric(df['CLC||Urban'], errors='coerce')
df['cell_a_m2'] = pd.to_numeric(df['cell_a_m2'], errors='coerce')

# Calcolo indice evitando divisione per zero
df['indice_urbanizzazione'] = np.where(df['cell_a_m2'] > 0,
                                        df['CLC||Urban'] / df['cell_a_m2'] * 100,
                                        0)
In [11]:
plt.figure(figsize=(10, 6))
sns.histplot(df['indice_urbanizzazione'].clip(0, 100), bins=20)
plt.title('Distribuzione dell\'indice di urbanizzazione')
plt.xlabel('Percentuale di area urbanizzata')
plt.ylabel('Numero di celle')
plt.show()
No description has been provided for this image

1. INDICATORE COMPOSITO: POTENZIALE PER ENERGIA VERDE¶

Componente area non urbanizzata

In [12]:
df['potenziale_base'] = 100 - df['indice_urbanizzazione']

Componente aree naturali (se disponibili)

In [13]:
if 'perc_forest_and_semi_natural' in df.columns:
    df['bonus_aree_naturali'] = df['perc_forest_and_semi_natural'] * 0.2
else:
    df['bonus_aree_naturali'] = 0

Componente aree agricole (se disponibili)

In [14]:
if 'perc_agricultural' in df.columns:
    df['bonus_aree_agricole'] = df['perc_agricultural'] * 0.1
else:
    df['bonus_aree_agricole'] = 0

Calcolo indice complessivo¶

In [15]:
df['indice_potenziale_verde'] = df['potenziale_base'] + df['bonus_aree_naturali'] + df['bonus_aree_agricole']
df['indice_potenziale_verde'] = df['indice_potenziale_verde'].clip(0, 100)
In [16]:
# Classificazione in categorie
df['classe_potenziale_verde'] = pd.cut(
    df['indice_potenziale_verde'], 
    bins=[0, 20, 40, 60, 80, 100],
    labels=['Molto basso', 'Basso', 'Medio', 'Alto', 'Molto alto']
)
In [17]:
plt.figure(figsize=(10, 6))
sns.histplot(df['indice_potenziale_verde'], bins=20)
plt.title('Distribuzione dell\'indice di potenziale per energia verde')
plt.xlabel('Indice di potenziale (0-100)')
plt.ylabel('Numero di celle')
plt.show()
No description has been provided for this image
In [18]:
# Distribuzione delle classi
plt.figure(figsize=(10, 6))
counts = df['classe_potenziale_verde'].value_counts().sort_index()
plt.bar(counts.index, counts.values)
plt.title('Distribuzione delle classi di potenziale per energia verde')
plt.xlabel('Classe di potenziale')
plt.ylabel('Numero di celle')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
No description has been provided for this image

2. INDICATORE COMPOSITO: SOSTENIBILITÀ AMBIENTALE URBANA¶

Accessibilità ai servizi

In [19]:
servizi_cittadinanza = ['infrastrutture', 'cultura', 'istruzione', 'sanita', 'sport']

access_cols = []
for col in df:
    for servizio in servizi_cittadinanza:
        if servizio in col:
            df[col] = df[col].fillna(0)
            access_cols.append(col)
In [20]:
# Calcoliamo indici di accessibilità
df['accessibilita_15min'] = df[[col for col in access_cols if '15' in col]].mean(axis=1)
df['accessibilita_30min'] = df[[col for col in access_cols if '30' in col]].mean(axis=1)
/tmp/ipykernel_1179158/1220317408.py:2: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['accessibilita_15min'] = df[[col for col in access_cols if '15' in col]].mean(axis=1)
/tmp/ipykernel_1179158/1220317408.py:3: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['accessibilita_30min'] = df[[col for col in access_cols if '30' in col]].mean(axis=1)
In [21]:
# Calcoliamo un indice composito di accessibilità
df['indice_accessibilita'] = (df['accessibilita_15min'] * 2 + df['accessibilita_30min']) / 3
/tmp/ipykernel_1179158/3252611048.py:2: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['indice_accessibilita'] = (df['accessibilita_15min'] * 2 + df['accessibilita_30min']) / 3
In [22]:
# Normalizzazione dell'indice di accessibilità (0-100)
max_acc = df['indice_accessibilita'].quantile(0.95)  # Uso il 95° percentile per evitare outlier
df['accessibilita_norm'] = (df['indice_accessibilita'] / max_acc * 100).clip(0, 100)
/tmp/ipykernel_1179158/3643911668.py:3: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['accessibilita_norm'] = (df['indice_accessibilita'] / max_acc * 100).clip(0, 100)

Potenziale verde

In [23]:
# Normalizzazione del potenziale verde (già calcolato)
df['verde_norm'] = df['indice_potenziale_verde']
/tmp/ipykernel_1179158/759367644.py:2: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['verde_norm'] = df['indice_potenziale_verde']

Densità abitativa

In [24]:
# Densità abitativa (se disponibile), inverso per premiare aree meno dense
df['ISTAT||POP_TOT__21'] = pd.to_numeric(df['ISTAT||POP_TOT__21'], errors='coerce').fillna(0)
df['densita_abitativa'] = np.where(df['cell_a_m2'] > 0,
                                    df['ISTAT||POP_TOT__21'] / (df['cell_a_m2'] / 1000000),
                                    0)  # abitanti per km²

max_dens = df['densita_abitativa'].quantile(0.95)  # Uso il 95° percentile per evitare outlier
df['densita_norm'] = ((max_dens - df['densita_abitativa']) / max_dens * 100).clip(0, 100)
/tmp/ipykernel_1179158/1805253285.py:3: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['densita_abitativa'] = np.where(df['cell_a_m2'] > 0,
/tmp/ipykernel_1179158/1805253285.py:8: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['densita_norm'] = ((max_dens - df['densita_abitativa']) / max_dens * 100).clip(0, 100)

Calcolo dell'indice composito di sostenibilità ambientale urbana¶

In [25]:
df['indice_sostenibilita_ambientale'] = (
    df['verde_norm'] * 0.5 +  # 50% potenziale verde
    df['accessibilita_norm'] * 0.3 +  # 30% accessibilità
    df['densita_norm'] * 0.2  # 20% inverso della densità
) / 100 * 100  # Normalizzazione a 0-100
/tmp/ipykernel_1179158/3432026295.py:1: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['indice_sostenibilita_ambientale'] = (
In [26]:
# Classificazione in categorie
df['classe_sostenibilita'] = pd.cut(
    df['indice_sostenibilita_ambientale'], 
    bins=[0, 20, 40, 60, 80, 100],
    labels=['Molto bassa', 'Bassa', 'Media', 'Alta', 'Molto alta']
)
/tmp/ipykernel_1179158/3928220547.py:2: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['classe_sostenibilita'] = pd.cut(
In [27]:
plt.figure(figsize=(10, 6))
sns.histplot(df['indice_sostenibilita_ambientale'], bins=20)
plt.title('Distribuzione dell\'indice di sostenibilità ambientale urbana')
plt.xlabel('Indice (0-100)')
plt.ylabel('Numero di celle')
plt.show()
No description has been provided for this image
In [28]:
plt.figure(figsize=(10, 6))
counts = df['classe_sostenibilita'].value_counts().sort_index()
plt.bar(counts.index, counts.values)
plt.title('Distribuzione delle classi di sostenibilità ambientale')
plt.xlabel('Classe di sostenibilità')
plt.ylabel('Numero di celle')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
No description has been provided for this image

3. INTEGRAZIONE CON DATI DEMOGRAFICI E ANALISI DELLE CORRELAZIONI¶

In [29]:
# Verifico se ci sono dati demografici
demo_cols = [col for col in df.columns if 'ISTAT||P' in col and '__21' in col]
In [30]:
# Correlazione tra indici e popolazione
correlations = {
    'Indice di urbanizzazione': df[['indice_urbanizzazione', 'ISTAT||POP_TOT__21']].corr().iloc[0,1],
    'Indice potenziale verde': df[['indice_potenziale_verde', 'ISTAT||POP_TOT__21']].corr().iloc[0,1],
    'Indice sostenibilità ambientale': df[['indice_sostenibilita_ambientale', 'ISTAT||POP_TOT__21']].corr().iloc[0,1]
}
In [31]:
plt.figure(figsize=(10, 6))
plt.bar(correlations.keys(), correlations.values())
plt.title('Correlazione tra indici e popolazione')
plt.ylabel('Coefficiente di correlazione')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
No description has been provided for this image
In [32]:
# Correlazione tra indici
correlation_matrix = df[['indice_urbanizzazione', 'indice_potenziale_verde', 
                        'indice_sostenibilita_ambientale']].corr()

plt.figure(figsize=(8, 6))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', vmin=-1, vmax=1)
plt.title('Matrice di correlazione tra indici')
plt.tight_layout()
plt.show()
No description has been provided for this image

4. IDENTIFICAZIONE DELLE AREE OTTIMALI PER ENERGIA RINNOVABILE¶

In [33]:
# Creazione indice per potenziale fotovoltaico
# Alto potenziale verde, bassa urbanizzazione, buona accessibilità

df['indice_potenziale_fotovoltaico'] = (
    df['indice_potenziale_verde'] * 0.6 +  # 60% potenziale verde
    (100 - df['indice_urbanizzazione']) * 0.3 +  # 30% aree non urbanizzate
    df['accessibilita_norm'] * 0.1  # 10% accessibilità
) / 100 * 100  # Normalizzazione a 0-100

# Top 10% delle celle per potenziale fotovoltaico
threshold = df['indice_potenziale_fotovoltaico'].quantile(0.9)
top_cells = df[df['indice_potenziale_fotovoltaico'] >= threshold]

print(f"\nIdentificate {len(top_cells)} celle (top 10%) con alto potenziale per energia fotovoltaica")
print(f"Potenziale medio delle celle selezionate: {top_cells['indice_potenziale_fotovoltaico'].mean():.2f}/100")
Identificate 229 celle (top 10%) con alto potenziale per energia fotovoltaica
Potenziale medio delle celle selezionate: 96.40/100
/tmp/ipykernel_1179158/2140658467.py:4: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['indice_potenziale_fotovoltaico'] = (
In [34]:
plt.figure(figsize=(10, 6))
sns.histplot(df['indice_potenziale_fotovoltaico'], bins=20)
plt.axvline(x=threshold, color='r', linestyle='--', 
           label=f'Soglia top 10% ({threshold:.2f})')
plt.title('Distribuzione dell\'indice di potenziale fotovoltaico')
plt.xlabel('Indice (0-100)')
plt.ylabel('Numero di celle')
plt.legend()
plt.show()
No description has been provided for this image

5. ANALISI CONSUMO DI SUOLO E IDENTIFICAZIONE AREE CRITICHE¶

In [35]:
# Identificazione aree ad alto consumo di suolo
urban_threshold = df['indice_urbanizzazione'].quantile(0.75)
high_urban_cells = df[df['indice_urbanizzazione'] >= urban_threshold]

print(f"\nIdentificate {len(high_urban_cells)} celle (25% più urbanizzate)")
print(f"Indice medio di urbanizzazione delle celle selezionate: {high_urban_cells['indice_urbanizzazione'].mean():.2f}%")
Identificate 572 celle (25% più urbanizzate)
Indice medio di urbanizzazione delle celle selezionate: 69.37%
In [36]:
plt.figure(figsize=(10, 6))
sns.histplot(df['indice_urbanizzazione'], bins=20)
plt.axvline(x=urban_threshold, color='r', linestyle='--', 
           label=f'Soglia top 25% ({urban_threshold:.2f}%)')
plt.title('Distribuzione dell\'indice di urbanizzazione')
plt.xlabel('Percentuale di area urbanizzata')
plt.ylabel('Numero di celle')
plt.legend()
plt.show()
No description has been provided for this image
In [37]:
# Rapporto tra consumo di suolo e densità abitativa (se disponibile)
plt.figure(figsize=(10, 6))
plt.scatter(df['indice_urbanizzazione'], df['densita_abitativa'], alpha=0.5)
plt.title('Relazione tra consumo di suolo e densità abitativa')
plt.xlabel('Indice di urbanizzazione (%)')
plt.ylabel('Densità abitativa (ab/km²)')
plt.grid(True)
plt.show()
No description has been provided for this image
In [38]:
# Calcolo efficienza uso del suolo (abitanti/% area urbanizzata)
df['efficienza_uso_suolo'] = np.where(df['indice_urbanizzazione'] > 0,
                                    df['densita_abitativa'] / df['indice_urbanizzazione'],
                                    0)

plt.figure(figsize=(10, 6))
sns.histplot(df['efficienza_uso_suolo'].clip(0, df['efficienza_uso_suolo'].quantile(0.95)), bins=20)
plt.title('Distribuzione dell\'indice di efficienza dell\'uso del suolo')
plt.xlabel('Abitanti per unità di urbanizzazione')
plt.ylabel('Numero di celle')
plt.show()
/tmp/ipykernel_1179158/355514563.py:2: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['efficienza_uso_suolo'] = np.where(df['indice_urbanizzazione'] > 0,
No description has been provided for this image

6. SINTESI DEGLI INDICATORI PER LA CONFERENZA¶

In [39]:
# Creazione tabella di sintesi
summary_stats = pd.DataFrame({
    'Indicatore': [
        'Indice di urbanizzazione (%)', 
        'Indice di potenziale verde (0-100)', 
        'Indice di sostenibilità ambientale (0-100)',
        'Indice di potenziale fotovoltaico (0-100)',
        'Efficienza uso del suolo (ab/unità urbanizzazione)'
    ],
    'Media': [
        df['indice_urbanizzazione'].mean(),
        df['indice_potenziale_verde'].mean(),
        df['indice_sostenibilita_ambientale'].mean(),
        df['indice_potenziale_fotovoltaico'].mean(),
        df['efficienza_uso_suolo'].mean() if 'efficienza_uso_suolo' in df.columns else np.nan
    ],
    'Mediana': [
        df['indice_urbanizzazione'].median(),
        df['indice_potenziale_verde'].median(),
        df['indice_sostenibilita_ambientale'].median(),
        df['indice_potenziale_fotovoltaico'].median(),
        df['efficienza_uso_suolo'].median() if 'efficienza_uso_suolo' in df.columns else np.nan
    ],
    'Dev. Std': [
        df['indice_urbanizzazione'].std(),
        df['indice_potenziale_verde'].std(),
        df['indice_sostenibilita_ambientale'].std(),
        df['indice_potenziale_fotovoltaico'].std(),
        df['efficienza_uso_suolo'].std() if 'efficienza_uso_suolo' in df.columns else np.nan
    ]
})

print("\nSintesi degli indicatori per la conferenza:")
summary_stats
Sintesi degli indicatori per la conferenza:
Out[39]:
Indicatore Media Mediana Dev. Std
0 Indice di urbanizzazione (%) 19.942717 0.000000 31.280477
1 Indice di potenziale verde (0-100) 81.604457 100.000000 30.912257
2 Indice di sostenibilità ambientale (0-100) 68.900500 72.771544 16.393705
3 Indice di potenziale fotovoltaico (0-100) 76.636223 90.572073 26.287756
4 Efficienza uso del suolo (ab/unità urbanizzazi... 169.937432 0.000000 3709.193731

7. MAPPA DI PRIORITÀ PER INTERVENTI DI ENERGIA VERDE¶

Creazione dell'indice di priorità

Alto potenziale verde + alta densità abitativa + alta accessibilità

In [40]:
# Normalizzazione della densità abitativa (0-100)
max_dens = df['densita_abitativa'].quantile(0.95)  # Uso il 95° percentile per evitare outlier
df['densita_norm_pos'] = (df['densita_abitativa'] / max_dens * 100).clip(0, 100)
/tmp/ipykernel_1179158/141740308.py:3: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['densita_norm_pos'] = (df['densita_abitativa'] / max_dens * 100).clip(0, 100)
In [41]:
# Calcolo indice di priorità
df['indice_priorita_energia_verde'] = (
    df['indice_potenziale_verde'] * 0.5 +  # 50% potenziale verde
    df['densita_norm_pos'] * 0.3 +  # 30% densità (positiva in questo caso)
    df['accessibilita_norm'] * 0.2  # 20% accessibilità
) / 100 * 100  # Normalizzazione a 0-100
/tmp/ipykernel_1179158/2520647873.py:2: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['indice_priorita_energia_verde'] = (
In [42]:
# Classificazione in 5 classi di priorità
df['classe_priorita'] = pd.qcut(
    df['indice_priorita_energia_verde'], 
    q=5, 
    labels=['Molto bassa', 'Bassa', 'Media', 'Alta', 'Molto alta']
)
/tmp/ipykernel_1179158/69077833.py:2: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  df['classe_priorita'] = pd.qcut(
In [43]:
plt.figure(figsize=(10, 6))
sns.histplot(df['indice_priorita_energia_verde'], bins=20)
plt.title('Distribuzione dell\'indice di priorità per interventi di energia verde')
plt.xlabel('Indice di priorità (0-100)')
plt.ylabel('Numero di celle')
plt.show()
No description has been provided for this image

Conclusioni¶

In [44]:
# Estrazione dei risultati numerici dagli indicatori per conclusioni basate sui dati

# Statistiche di base dei principali indicatori
stats = {
    'Urbanizzazione': {
        'media': df['indice_urbanizzazione'].mean(),
        'mediana': df['indice_urbanizzazione'].median(),
        'deviazione': df['indice_urbanizzazione'].std(),
        'q25': df['indice_urbanizzazione'].quantile(0.25),
        'q75': df['indice_urbanizzazione'].quantile(0.75)
    },
    'Potenziale Verde': {
        'media': df['indice_potenziale_verde'].mean(),
        'mediana': df['indice_potenziale_verde'].median(),
        'deviazione': df['indice_potenziale_verde'].std(),
        'q25': df['indice_potenziale_verde'].quantile(0.25),
        'q75': df['indice_potenziale_verde'].quantile(0.75)
    }
}

if 'indice_sostenibilita_ambientale' in df.columns:
    stats['Sostenibilità Ambientale'] = {
        'media': df['indice_sostenibilita_ambientale'].mean(),
        'mediana': df['indice_sostenibilita_ambientale'].median(),
        'deviazione': df['indice_sostenibilita_ambientale'].std(),
        'q25': df['indice_sostenibilita_ambientale'].quantile(0.25),
        'q75': df['indice_sostenibilita_ambientale'].quantile(0.75)
    }

if 'efficienza_uso_suolo' in df.columns:
    stats['Efficienza Uso Suolo'] = {
        'media': df['efficienza_uso_suolo'].mean(),
        'mediana': df['efficienza_uso_suolo'].median(),
        'deviazione': df['efficienza_uso_suolo'].std(),
        'q25': df['efficienza_uso_suolo'].quantile(0.25),
        'q75': df['efficienza_uso_suolo'].quantile(0.75)
    }

# Percentuale di aree con alto potenziale verde
high_potential = len(df[df['indice_potenziale_verde'] > 60]) / len(df) * 100

# Correlazione tra urbanizzazione e potenziale verde
urb_green_corr = df[['indice_urbanizzazione', 'indice_potenziale_verde']].corr().iloc[0,1]

# Aree prioritarie identificate
if 'indice_priorita_energia_verde' in df.columns:
    priority_areas = len(df[df['indice_priorita_energia_verde'] > df['indice_priorita_energia_verde'].quantile(0.8)]) 
    priority_pct = priority_areas / len(df) * 100

# Analisi delle aree altamente urbanizzate
high_urban = len(df[df['indice_urbanizzazione'] > 50]) / len(df) * 100

# Output dei risultati
print("\n=== CONSIDERAZIONI FINALI BASATE SUI DATI ===\n")
print(f"1. MODELLI DI URBANIZZAZIONE E POTENZIALE VERDE")
print(f"   • L'indice di urbanizzazione medio è {stats['Urbanizzazione']['media']:.1f}%, con una mediana di {stats['Urbanizzazione']['mediana']:.1f}%")
print(f"   • Il 25% delle aree ha un indice di urbanizzazione superiore al {stats['Urbanizzazione']['q75']:.1f}%")
print(f"   • {high_urban:.1f}% delle celle analizzate presenta un'urbanizzazione superiore al 50%")
print(f"   • Il potenziale verde medio è {stats['Potenziale Verde']['media']:.1f}/100, con una mediana di {stats['Potenziale Verde']['mediana']:.1f}")
print(f"   • {high_potential:.1f}% delle aree presenta un alto potenziale per l'energia verde (>60/100)")
print(f"   • La correlazione tra urbanizzazione e potenziale verde è {urb_green_corr:.2f}, indicando una {abs(urb_green_corr) > 0.5 and 'forte' or 'moderata'} relazione {urb_green_corr < 0 and 'negativa' or 'positiva'}")

if 'Efficienza Uso Suolo' in stats:
    print(f"\n2. EFFICIENZA DELL'USO DEL SUOLO")
    print(f"   • L'efficienza media dell'uso del suolo è {stats['Efficienza Uso Suolo']['media']:.1f} abitanti per unità di urbanizzazione")
    print(f"   • Il 25% delle aree più efficienti presenta valori superiori a {stats['Efficienza Uso Suolo']['q75']:.1f}")
    print(f"   • La distribuzione mostra una deviazione standard di {stats['Efficienza Uso Suolo']['deviazione']:.1f}, indicando una {stats['Efficienza Uso Suolo']['deviazione'] > stats['Efficienza Uso Suolo']['media'] and 'alta' or 'moderata'} variabilità")

if 'indice_priorita_energia_verde' in df.columns:
    print(f"\n3. AREE PRIORITARIE PER INTERVENTI DI ENERGIA VERDE")
    print(f"   • Sono state identificate {priority_areas} celle ad alta priorità, pari al {priority_pct:.1f}% del territorio analizzato")
    print(f"   • Queste aree combinano alto potenziale verde, buona accessibilità e densità abitativa significativa")

# Aggiungere altri insight specifici se disponibili
if 'classe_potenziale_verde' in df.columns:
    verde_counts = df['classe_potenziale_verde'].value_counts(normalize=True) * 100
    print(f"\n4. DISTRIBUZIONE DEL POTENZIALE VERDE")
    for classe, percentuale in verde_counts.sort_index().items():
        print(f"   • {classe}: {percentuale:.1f}% delle aree")

print("\nRACCOMANDAZIONI BASATE SUI DATI:")
print(f"• Prioritizzare interventi di energia verde nelle {priority_areas} celle identificate come ad alta priorità")
print(f"• Aumentare l'efficienza dell'uso del suolo nelle aree urbanizzate, specialmente nel 25% con valori inferiori a {stats['Efficienza Uso Suolo']['q25']:.1f}" if 'Efficienza Uso Suolo' in stats else "")
print(f"• Sviluppare progetti pilota di comunità energetiche nel {high_potential:.1f}% delle aree con alto potenziale verde")
print(f"• Implementare strategie di densificazione urbana sostenibile nelle aree con indice di urbanizzazione tra 30% e 50%, bilanciando sviluppo e conservazione del potenziale verde")
=== CONSIDERAZIONI FINALI BASATE SUI DATI ===

1. MODELLI DI URBANIZZAZIONE E POTENZIALE VERDE
   • L'indice di urbanizzazione medio è 19.9%, con una mediana di 0.0%
   • Il 25% delle aree ha un indice di urbanizzazione superiore al 32.8%
   • 18.6% delle celle analizzate presenta un'urbanizzazione superiore al 50%
   • Il potenziale verde medio è 81.6/100, con una mediana di 100.0
   • 79.2% delle aree presenta un alto potenziale per l'energia verde (>60/100)
   • La correlazione tra urbanizzazione e potenziale verde è -1.00, indicando una forte relazione negativa

2. EFFICIENZA DELL'USO DEL SUOLO
   • L'efficienza media dell'uso del suolo è 169.9 abitanti per unità di urbanizzazione
   • Il 25% delle aree più efficienti presenta valori superiori a 42.5
   • La distribuzione mostra una deviazione standard di 3709.2, indicando una alta variabilità

3. AREE PRIORITARIE PER INTERVENTI DI ENERGIA VERDE
   • Sono state identificate 457 celle ad alta priorità, pari al 20.0% del territorio analizzato
   • Queste aree combinano alto potenziale verde, buona accessibilità e densità abitativa significativa

4. DISTRIBUZIONE DEL POTENZIALE VERDE
   • Molto basso: 7.0% delle aree
   • Basso: 5.5% delle aree
   • Medio: 6.6% delle aree
   • Alto: 7.0% delle aree
   • Molto alto: 74.0% delle aree

RACCOMANDAZIONI BASATE SUI DATI:
• Prioritizzare interventi di energia verde nelle 457 celle identificate come ad alta priorità
• Aumentare l'efficienza dell'uso del suolo nelle aree urbanizzate, specialmente nel 25% con valori inferiori a 0.0
• Sviluppare progetti pilota di comunità energetiche nel 79.2% delle aree con alto potenziale verde
• Implementare strategie di densificazione urbana sostenibile nelle aree con indice di urbanizzazione tra 30% e 50%, bilanciando sviluppo e conservazione del potenziale verde
In [45]:
print('CONCLUSIONI PER RISOLUZIONE 8')

print("L'analisi del territorio mostra un pattern di urbanizzazione eterogeneo, con un valore medio del 20% ma una mediana di 0%, suggerendo che molte aree rimangono prevalentemente non urbanizzate mentre altre presentano un'intensa edificazione, come conferma il dato che quasi il 19% delle celle ha un'urbanizzazione superiore al 50%.")

print("È evidente una forte relazione inversamente proporzionale (correlazione -1.00) tra urbanizzazione e potenziale verde, confermando che le aree meno urbanizzate mantengono maggiore capacità di sviluppo sostenibile. Questo è ulteriormente supportato dal fatto che quasi l'80% del territorio presenta un alto potenziale per l'energia verde (>60/100).")

print("L'efficienza dell'uso del suolo mostra una distribuzione estremamente variabile (deviazione standard di 3709.2), con alcune aree che ottimizzano il rapporto tra densità abitativa e superficie urbanizzata mentre altre appaiono significativamente sottoutilizzate, suggerendo opportunità di densificazione in alcune zone.")

print("La classificazione del territorio per potenziale verde rivela una distribuzione fortemente sbilanciata verso la categoria 'molto alto' (74% delle aree), indicando ampie opportunità per investimenti in energia rinnovabile e infrastrutture verdi nella maggior parte del territorio analizzato.")

print("L'identificazione di 457 celle ad alta priorità (20% del territorio) che combinano alto potenziale verde, buona accessibilità e densità abitativa significativa rappresenta un'opportunità strategica per interventi che possano massimizzare i benefici sociali ed ecologici, rivitalizzando aree già popolate attraverso soluzioni energetiche sostenibili.")

print("Questi risultati suggeriscono l'opportunità di politiche di pianificazione urbana orientate alla 'crescita interna', incentivando lo sviluppo nelle aree già urbanizzate per preservare il considerevole potenziale verde esistente, mentre si promuovono simultaneamente interventi di efficientamento energetico e sviluppo di comunità energetiche nelle aree prioritarie identificate.")
CONCLUSIONI PER RISOLUZIONE 8
L'analisi del territorio mostra un pattern di urbanizzazione eterogeneo, con un valore medio del 20% ma una mediana di 0%, suggerendo che molte aree rimangono prevalentemente non urbanizzate mentre altre presentano un'intensa edificazione, come conferma il dato che quasi il 19% delle celle ha un'urbanizzazione superiore al 50%.
È evidente una forte relazione inversamente proporzionale (correlazione -1.00) tra urbanizzazione e potenziale verde, confermando che le aree meno urbanizzate mantengono maggiore capacità di sviluppo sostenibile. Questo è ulteriormente supportato dal fatto che quasi l'80% del territorio presenta un alto potenziale per l'energia verde (>60/100).
L'efficienza dell'uso del suolo mostra una distribuzione estremamente variabile (deviazione standard di 3709.2), con alcune aree che ottimizzano il rapporto tra densità abitativa e superficie urbanizzata mentre altre appaiono significativamente sottoutilizzate, suggerendo opportunità di densificazione in alcune zone.
La classificazione del territorio per potenziale verde rivela una distribuzione fortemente sbilanciata verso la categoria 'molto alto' (74% delle aree), indicando ampie opportunità per investimenti in energia rinnovabile e infrastrutture verdi nella maggior parte del territorio analizzato.
L'identificazione di 457 celle ad alta priorità (20% del territorio) che combinano alto potenziale verde, buona accessibilità e densità abitativa significativa rappresenta un'opportunità strategica per interventi che possano massimizzare i benefici sociali ed ecologici, rivitalizzando aree già popolate attraverso soluzioni energetiche sostenibili.
Questi risultati suggeriscono l'opportunità di politiche di pianificazione urbana orientate alla 'crescita interna', incentivando lo sviluppo nelle aree già urbanizzate per preservare il considerevole potenziale verde esistente, mentre si promuovono simultaneamente interventi di efficientamento energetico e sviluppo di comunità energetiche nelle aree prioritarie identificate.

Export¶

In [46]:
cols_indicatori = [
    # 'indice_urbanizzazione', 
    # 'potenziale_base', 
    # 'bonus_aree_naturali',
    # 'bonus_aree_agricole', 
    # 'indice_potenziale_verde',
    # 'classe_potenziale_verde', 
    # 'accessibilita_15min', 
    # 'accessibilita_30min',
    # 'indice_accessibilita', 
    # 'accessibilita_norm', 
    # 'verde_norm',
    # 'densita_abitativa', 
    # 'densita_norm', 
    'indice_sostenibilita_ambientale',
    # 'classe_sostenibilita', 
    'indice_potenziale_fotovoltaico',
    'efficienza_uso_suolo', 
    # 'densita_norm_pos',
    # 'indice_priorita_energia_verde', 
    # 'classe_priorita'
]
In [47]:
map_indicatori = {
    'indice_sostenibilita_ambientale': 'ISA',
    'indice_potenziale_fotovoltaico': 'IPF',
    'efficienza_uso_suolo': 'ESS', 
}
In [48]:
df_base = df.copy()

Output con classi

In [49]:
n_classes = 5
new_columns = {}

for col in cols_indicatori:
    # Calcola i natural breaks di Jenks per la classificazione
    breaks = jenks_breaks(df[col].values, n_classes=n_classes)
    
    # Crea le classi usando pd.cut ma salvale in un dizionario temporaneo
    labels = [i+1 for i in range(len(breaks)-1)]
    temp_series = pd.cut(
        df[col], 
        bins=breaks, 
        labels=labels,
        include_lowest=True
    )
    
    # Salva il risultato convertito in int nel dizionario
    new_columns[col] = temp_series.astype(int)

# Aggiorna il dataframe una sola volta con tutte le colonne
df = pd.concat([df.drop(columns=cols_indicatori), pd.DataFrame(new_columns)], axis=1)

df.rename(columns=map_indicatori, inplace=True)

gdf = gpd.GeoDataFrame(df[list(map_indicatori.values()) + ['geometry', f'h3_{resolution:02}']], geometry='geometry', crs=32632)
gdf['geometry'] = gdf['geometry'].centroid

gdf.to_crs(4326).to_file(os.path.join(out_path, f'grid_{resolution:02}_pt_tavolo4.geojson'), driver="GeoJSON")

Output con valori assoluti

In [50]:
n_classes = 5

df = df_base.copy()
df.rename(columns=map_indicatori, inplace=True)
gdf = gpd.GeoDataFrame(df[list(map_indicatori.values()) + ['geometry', f'h3_{resolution:02}']], geometry='geometry', crs=32632)
gdf['geometry'] = gdf['geometry'].centroid
cols_indicatori = map_indicatori.values()
asc3 = gpd.read_file(os.path.join(ilab_path,'ROMA','DATA','ASC_21', 'ASC_Liv_3_WGS84.shp'))
asc3 = asc3[asc3['PRO_COM']==58091].copy()
asc3_ind = asc3.sjoin(gdf)
aggs = {col:'mean' for col in cols_indicatori}
asc3_ind_g = asc3_ind.groupby('DEN_ASC3', as_index=False).agg(aggs)
for col in cols_indicatori:
    # Calcola i natural breaks di Jenks per la classificazione
    breaks = jenks_breaks(asc3_ind_g[col].values, n_classes=n_classes)

    # Crea una nuova colonna con le classi di Jenks
    labels = [i+1 for i in range(len(breaks)-1)]
    asc3_ind_g.loc[:, f'{col}_cls'] = pd.cut(
        asc3_ind_g[col], 
        bins=breaks, 
        labels=labels,
        include_lowest=True
    )
    asc3_ind_g[f'{col}_cls'] = asc3_ind_g[f'{col}_cls'].astype(int)
asc3_out = asc3.merge(asc3_ind_g, how='left', on='DEN_ASC3')
asc3_out.to_crs(4326).to_file(os.path.join(out_path, f'asc3_tavolo4.geojson'), driver="GeoJSON")