mercoledì 10 aprile 2024

Decision Tree Tensorflow su dati Sentinel 2

 Ho ripreso il filone di questa prova per provare i Decision Tree con le firme spettrali di Sentinel 2

Per la prova ho preso l'immagine S2B_MSIL2A_20230826T100559_N0509_R022_T32TPP_20230826T134424.SAFE

del periodo estivo del Mugello (Toscana) in modo da avere suolo nudo disponibile.


Visto che volevo estrarre tutte le bande tramite SNAP ho campionato tutte le bande a 10 m (altrimenti come visto nel precedente post lo Spectral Viewer estrae solo le bande native a 10 m)...e qui c'e' un problema...ho dovuto fare il resampling spaziale di tutta l'immagine e dopo fare il subset della mia sola area di interesse altrimenti, invertendo le due operazioni, SNAP entrava continuamente in errore

Usando gli OpenData della Regione Toscana

https://dati.toscana.it/dataset/dbped

ho usato il dataset per selezionare il parametro contenuto in argilla del suolo categorizzandolo a passi del 5%. Usando i Pin e la vista sincronizzata tra la mappe del suolo e l'immagine telerilevata sono selezionati 153 punti appartenenti a 4 classi di contenuto in argilla

Classe/Nr spettri 3 44 2 41 0 34 1 34

Il contenuto in argille delle classi e'

classe 1 (amaranto) : 45-50%

classe 2 (arancione) : 30-35%

classe 3 (rosso) :40-45%

classe 4 (verde) : 20-25%




il file dati in CSV e' formato nel seguente modo

443,490,560,665,705,740,783,842,865,945,1610,2190,Classe
0.0711,0.1056,0.1548,0.2046,0.2335,0.2442,0.2617,0.2624,0.2801,0.2813,0.3556,0.2868,1
0.0777,0.1052,0.157,0.2032,0.2311,0.2415,0.2611,0.2562,0.2741,0.2841,0.3473,0.2829,1

Come si vede dall'esempio la variabilita' spettrale in ogni classe e' molto elevata (in rosso lo spettro medio)



Lo spettro medio per ogni classe di contenuto in argilla e' visualizzato negl grafico sottostante


Usando una rete neurale tradizionale l'accuratezza e ' prossima al 77%

import pandas as pd
import numpy as np
import tensorflow as tf
import seaborn as sns
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Dropout
from sklearn.preprocessing import LabelEncoder , StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix

df = pd.read_csv('/content/totale2.csv')
print(df.head())

le = LabelEncoder()
df['Classe'] = le.fit_transform(df['Classe'])

X = df.drop(columns=['Classe'])
y = df['Classe']
print(y.head())
print(y.value_counts())
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.25,shuffle=True,random_state=7)

sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)

print(X_train.size)
print(y_train)
y_train = tf.keras.utils.to_categorical(y_train,num_classes=4)
def get_models():
    model = Sequential([
        Dense(units=32,input_shape=(12,),activation='relu'),
        Dense(units=32,activation='relu'),
        Dropout(0.5),
        Dense(units=4,activation='softmax')
    ])
    return model

model = get_models()
model.compile(optimizer='Adam',loss='categorical_crossentropy',metrics=['accuracy'])
model.summary()

model.fit(X_train,y_train,epochs=100, verbose=2)

prediction = model.predict(X_test)
prediction = np.argmax(prediction,axis=-1)
acury = accuracy_score(y_test,prediction)
print(acury)
cm = confusion_matrix(y_test,prediction)
print(cm)

0.7692307692307693

Con la seguente matrice di confusione

[[ 4 1 0 0] [ 4 7 0 0] [ 0 0 9 0] [ 1 2 1 10]]


Utilizzando i decision tree

!pip install -q -U tensorflow_decision_forests
!pip install -q -U dtreeviz
import tensorflow_decision_forests as tfdf

import tensorflow as tf

import os
import numpy as np
import pandas as pd
import tensorflow as tf
import math

import dtreeviz

from matplotlib import pyplot as plt
from IPython import display

import logging
logging.getLogger('matplotlib.font_manager').setLevel(level=logging.CRITICAL)

display.set_matplotlib_formats('retina') # generate hires plots

np.random.seed(1234)
def split_dataset(dataset, test_ratio=0.30, seed=1234):
  np.random.seed(seed)
  test_indices = np.random.rand(len(dataset)) < test_ratio
  return dataset[~test_indices], dataset[test_indices]
df_spettri = pd.read_csv("/content/totale2.csv")
df_spettri.head(3)
spettri_label = "Classe"   # Name of the classification target label
classes = list(df_spettri[spettri_label].unique())
df_spettri[spettri_label] = df_spettri[spettri_label].map(classes.index)

print(f"Target '{spettri_label}'' classes: {classes}")
df_spettri.head(3)
# Split into training and test sets
train_ds_pd, test_ds_pd = split_dataset(df_spettri)
print(f"{len(train_ds_pd)} examples in training, {len(test_ds_pd)} examples for testing.")

# Convert to tensorflow data sets
train_ds = tfdf.keras.pd_dataframe_to_tf_dataset(train_ds_pd, label=spettri_label)
test_ds = tfdf.keras.pd_dataframe_to_tf_dataset(test_ds_pd, label=spettri_label)
cmodel = tfdf.keras.RandomForestModel(verbose=0, random_seed=1234)
cmodel.fit(train_ds)
cmodel.compile(metrics=["accuracy"])
cmodel.evaluate(test_ds, return_dict=True, verbose=0)
# Tell dtreeviz about training data and model
spettri_features = [f.name for f in cmodel.make_inspector().features()]
viz_cmodel = dtreeviz.model(cmodel,
                           tree_index=3,
                           X_train=train_ds_pd[spettri_features],
                           y_train=train_ds_pd[spettri_label],
                           feature_names=spettri_features,
                           target_name=spettri_label,
                           class_names=classes)
viz_cmodel.view(scale=1.75)

si ha una accuracy di circa 0.7




Nessun commento:

Posta un commento

Ricampionare un segnale con SciPy

Un sistema rapido per ricampionare dati con spaziatura non omogenea  usando una curva di interpolazione   Dati originali   import matplotlib...