Ricerca nel sito web

Valutare gli algoritmi di machine learning per il riconoscimento delle attività umane


Il riconoscimento dell'attività umana è il problema di classificare sequenze di dati dell'accelerometro registrati da imbracature specializzate o smartphone in movimenti noti e ben definiti.

Gli approcci classici al problema coinvolgono funzionalità di creazione manuale dai dati di serie temporali basate su finestre di dimensioni fisse e modelli di apprendimento automatico di formazione, come insiemi di alberi decisionali. La difficoltà è che questa ingegneria di funzionalità richiede una profonda esperienza nel settore.

Recentemente, è stato dimostrato che metodi di deep learning come le reti neurali ricorrenti e le reti neurali convoluzionali unidimensionali, o CNN, forniscono risultati all'avanguardia su compiti impegnativi di riconoscimento delle attività con poca o nessuna ingegneria delle funzionalità dei dati, utilizzando invece funzionalità apprendimento sui dati grezzi.

In questo tutorial scoprirai come valutare una suite diversificata di algoritmi di machine learning sul set di dati "Riconoscimento delle attività tramite smartphone".

Dopo aver completato questo tutorial, saprai:

  • Come caricare e valutare algoritmi di machine learning non lineari e di insieme sulla versione progettata per funzionalità del set di dati di riconoscimento delle attività.
  • Come caricare e valutare gli algoritmi di apprendimento automatico sui dati del segnale grezzo per il set di dati di riconoscimento dell'attività.
  • Come definire limiti inferiori e superiori ragionevoli sulle prestazioni attese di algoritmi più sofisticati in grado di apprendere funzionalità, come i metodi di deep learning.

Avvia il tuo progetto con il mio nuovo libro Deep Learning for Time Series Forecasting, che include tutorial passo passo e i file codice sorgente Python per tutti gli esempi.

Cominciamo.

Panoramica dell'esercitazione

Questo tutorial è diviso in tre parti; sono:

  1. Riconoscimento dell'attività utilizzando il set di dati degli smartphone
  2. Dati ingegnerizzati delle funzionalità di modellazione
  3. Modellazione dei dati grezzi

Riconoscimento dell'attività utilizzando il set di dati degli smartphone

Il riconoscimento dell'attività umana, o HAR in breve, è il problema di prevedere cosa sta facendo una persona sulla base di una traccia del suo movimento utilizzando sensori.

Un set di dati standard per il riconoscimento dell’attività umana è il set di dati “Activity Recognition Using Smart Phones” reso disponibile nel 2012.

È stato preparato e reso disponibile da Davide Anguita, et al. dell’Università di Genova, Italia ed è descritto in modo completo nel loro articolo del 2013 “A Public Domain Dataset for Human Activity Recognition Using Smartphones”. Il set di dati è stato modellato con algoritmi di apprendimento automatico nel loro articolo del 2012 intitolato "Riconoscimento dell'attività umana su smartphone utilizzando una macchina vettoriale di supporto compatibile con l'hardware multiclasse".

Il set di dati è stato reso disponibile e può essere scaricato gratuitamente dall'UCI Machine Learning Repository:

  • Riconoscimento dell'attività umana utilizzando il set di dati degli smartphone, repository di apprendimento automatico UCI

I dati sono stati raccolti da 30 soggetti di età compresa tra 19 e 48 anni che eseguivano una delle sei attività standard mentre indossavano uno smartphone montato in vita che registrava i dati di movimento. È stato registrato un video di ciascun soggetto che eseguiva le attività e i dati di movimento sono stati etichettati manualmente da questi video.

Di seguito è riportato un video di esempio di un soggetto che esegue le attività mentre vengono registrati i dati di movimento.

Le sei attività svolte sono state le seguenti:

  1. A piedi
  2. Camminando di sopra
  3. Camminando al piano di sotto
  4. Seduta
  5. In piedi
  6. Posa

I dati di movimento registrati erano i dati dell'accelerometro x, yez (accelerazione lineare) e i dati giroscopici (velocità angolare) dello smartphone, in particolare un Samsung Galaxy S II. Le osservazioni sono state registrate a 50 Hz (ovvero 50 punti dati al secondo). Ciascun soggetto ha eseguito la sequenza di attività due volte, una volta con il dispositivo sul lato sinistro e una volta con il dispositivo sul lato destro.

I dati grezzi non sono disponibili. È stata invece resa disponibile una versione preelaborata del set di dati. Le fasi di pre-elaborazione includevano:

  • Accelerometro e giroscopio pre-elaborati utilizzando filtri antirumore.
  • Suddivisione dei dati in finestre fisse di 2,56 secondi (128 punti dati) con una sovrapposizione del 50%.
  • Suddivisione dei dati dell'accelerometro in componenti gravitazionali (totali) e di movimento del corpo.

Ai dati della finestra è stata applicata la progettazione delle funzionalità ed è stata resa disponibile una copia dei dati con queste funzionalità progettate.

Da ciascuna finestra sono state estratte una serie di caratteristiche temporali e di frequenza comunemente utilizzate nel campo del riconoscimento dell'attività umana. Il risultato è stato un vettore di caratteristiche di 561 elementi.

Il set di dati è stato suddiviso in set di training (70%) e test (30%) in base ai dati dei soggetti, ad es. 21 soggetti per il treno e nove per il test.

I risultati dell'esperimento con una macchina vettoriale di supporto destinata all'uso su uno smartphone (ad esempio aritmetica a virgola fissa) hanno prodotto un'accuratezza predittiva dell'89% sul set di dati di test, ottenendo risultati simili a quelli di un'implementazione SVM non modificata.

Il set di dati è disponibile gratuitamente e può essere scaricato dal repository UCI Machine Learning.

I dati vengono forniti come un singolo file zip di circa 58 megabyte. Il link diretto per questo download è qui sotto:

  • Set di dati UCI HAR.zip

Scarica il set di dati e decomprimi tutti i file in una nuova directory nella directory di lavoro corrente denominata "HARDataset".

Dati ingegnerizzati delle funzionalità di modellazione

In questa sezione svilupperemo il codice per caricare la versione del set di dati dotata di funzionalità ingegnerizzate e valutare una suite di algoritmi di apprendimento automatico non lineare, incluso SVM utilizzato nel documento originale.

L'obiettivo è raggiungere una precisione minima dell'89% sul set di dati di test.

I risultati dei metodi che utilizzano la versione del set di dati dotata di funzionalità ingegnerizzate forniscono una base di riferimento per qualsiasi metodo sviluppato per la versione dei dati grezzi.

Questa sezione è divisa in cinque parti; sono:

  • Carica set di dati
  • Definire i modelli
  • Valutare i modelli
  • Riepilogare i risultati
  • Esempio completo

Carica set di dati

Il primo passaggio consiste nel caricare il treno e testare i dati di input (X) e di output (y).

Nello specifico i seguenti file:

  • HARDataset/train/X_train.txt
  • HARDataset/train/y_train.txt
  • HARDataset/test/X_test.txt
  • HARDataset/test/y_test.txt

I dati di input sono in formato CSV in cui le colonne sono separate tramite spazi bianchi. Ciascuno di questi file può essere caricato come array NumPy.

La funzione load_file() di seguito carica un set di dati in base al percorso del file e restituisce i dati caricati come array NumPy.

# load a single file as a numpy array
def load_file(filepath):
	dataframe = read_csv(filepath, header=None, delim_whitespace=True)
	return dataframe.values

Possiamo chiamare questa funzione per caricare i file X e y per un dato gruppo di treni o set di test, data la somiglianza nel layout delle directory e nei nomi dei file. La funzione load_dataset_group() di seguito caricherà entrambi questi file per un gruppo e restituirà gli elementi X e y come array NumPy. Questa funzione può quindi essere utilizzata per caricare gli elementi X e y sia per il gruppo treno che per quello di prova.

# load a dataset group, such as train or test
def load_dataset_group(group, prefix=''):
	# load input data
	X = load_file(prefix + group + '/X_'+group+'.txt')
	# load class output
	y = load_file(prefix + group + '/y_'+group+'.txt')
	return X, y

Infine, possiamo caricare sia il set di dati di training che quello di test e restituirli come array NumPy pronti per l'adattamento e la valutazione dei modelli di machine learning.

# load the dataset, returns train and test X and y elements
def load_dataset(prefix=''):
	# load all train
	trainX, trainy = load_dataset_group('train', prefix + 'HARDataset/')
	print(trainX.shape, trainy.shape)
	# load all test
	testX, testy = load_dataset_group('test', prefix + 'HARDataset/')
	print(testX.shape, testy.shape)
	# flatten y
	trainy, testy = trainy[:,0], testy[:,0]
	print(trainX.shape, trainy.shape, testX.shape, testy.shape)
	return trainX, trainy, testX, testy

Possiamo chiamare questa funzione per caricare tutti i dati richiesti; Per esempio:

# load dataset
trainX, trainy, testX, testy = load_dataset()

Definire i modelli

Successivamente, possiamo definire un elenco di modelli di machine learning da valutare su questo problema.

Valuteremo i modelli utilizzando le configurazioni predefinite. A questo punto non stiamo cercando configurazioni ottimali di questi modelli, ma solo un'idea generale di come i modelli sofisticati con configurazioni predefinite si comportano bene su questo problema.

Valuteremo un insieme diversificato di algoritmi di machine learning non lineari e ensemble, in particolare:

Algoritmi non lineari:

  • k-Vicini più vicini
  • Classificazione e albero di regressione
  • Supporta la macchina vettoriale
  • L'ingenuo Bayes

Algoritmi di insieme:

  • Alberi decisionali insaccati
  • Foresta casuale
  • Alberi aggiuntivi
  • Macchina per l'aumento del gradiente

Definiremo i modelli e li memorizzeremo in un dizionario che associa l'oggetto del modello a un nome breve che aiuterà nell'analisi dei risultati.

La funzione define_models() di seguito definisce gli otto modelli che valuteremo.

# create a dict of standard models to evaluate {name:object}
def define_models(models=dict()):
	# nonlinear models
	models['knn'] = KNeighborsClassifier(n_neighbors=7)
	models['cart'] = DecisionTreeClassifier()
	models['svm'] = SVC()
	models['bayes'] = GaussianNB()
	# ensemble models
	models['bag'] = BaggingClassifier(n_estimators=100)
	models['rf'] = RandomForestClassifier(n_estimators=100)
	models['et'] = ExtraTreesClassifier(n_estimators=100)
	models['gbm'] = GradientBoostingClassifier(n_estimators=100)
	print('Defined %d models' % len(models))
	return models

Questa funzione è abbastanza estensibile e puoi facilmente aggiornarla per definire qualsiasi modello di machine learning o configurazione di modello desideri.

Valutare i modelli

Il passaggio successivo consiste nel valutare i modelli definiti nel set di dati caricato.

Questa fase è divisa nella valutazione di un singolo modello e nella valutazione di tutti i modelli.

Valuteremo un singolo modello adattandolo prima al set di dati di training, effettuando una previsione sul set di dati di test e quindi valutando la previsione utilizzando una metrica. In questo caso utilizzeremo l'accuratezza della classificazione che catturerà le prestazioni (o l'errore) di un modello date le osservazioni dell'equilibrio tra le sei attività (o classi).

La funzione evaluate_model() di seguito implementa questo comportamento, valutando un determinato modello e restituendo la precisione della classificazione come percentuale.

# evaluate a single model
def evaluate_model(trainX, trainy, testX, testy, model):
	# fit the model
	model.fit(trainX, trainy)
	# make predictions
	yhat = model.predict(testX)
	# evaluate predictions
	accuracy = accuracy_score(testy, yhat)
	return accuracy * 100.0

Ora possiamo chiamare ripetutamente la funzione evaluate_model() per ciascuno dei modelli definiti.

La funzione evaluate_models() di seguito implementa questo comportamento, prendendo il dizionario dei modelli definiti e restituisce un dizionario di nomi di modelli mappati in base alla loro precisione di classificazione.

Poiché la valutazione dei modelli può richiedere alcuni minuti, la funzione stampa le prestazioni di ciascun modello dopo che è stato valutato come feedback dettagliato.

# evaluate a dict of models {name:object}, returns {name:score}
def evaluate_models(trainX, trainy, testX, testy, models):
	results = dict()
	for name, model in models.items():
		# evaluate the model
		results[name] = evaluate_model(trainX, trainy, testX, testy, model)
		# show process
		print('>%s: %.3f' % (name, results[name]))
	return results

Riepilogare i risultati

Il passo finale è riassumere i risultati.

Possiamo ordinare tutti i risultati in base all'accuratezza della classificazione in ordine decrescente perché siamo interessati a massimizzare l'accuratezza.

I risultati dei modelli valutati possono quindi essere stampati, mostrando chiaramente il rango relativo di ciascuno dei modelli valutati.

La funzione summarize_results() riportata di seguito implementa questo comportamento.

# print and plot the results
def summarize_results(results, maximize=True):
	# create a list of (name, mean(scores)) tuples
	mean_scores = [(k,v) for k,v in results.items()]
	# sort tuples by mean score
	mean_scores = sorted(mean_scores, key=lambda x: x[1])
	# reverse for descending order (e.g. for accuracy)
	if maximize:
		mean_scores = list(reversed(mean_scores))
	print()
	for name, score in mean_scores:
		print('Name=%s, Score=%.3f' % (name, score))

Esempio completo

Sappiamo di avere tutti i pezzi a posto.

Di seguito è riportato l'esempio completo di valutazione di una suite di otto modelli di machine learning sulla versione del set di dati progettata per funzionalità.

# spot check on engineered-features
from pandas import read_csv
from sklearn.metrics import accuracy_score
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.ensemble import GradientBoostingClassifier

# load a single file as a numpy array
def load_file(filepath):
	dataframe = read_csv(filepath, header=None, delim_whitespace=True)
	return dataframe.values

# load a dataset group, such as train or test
def load_dataset_group(group, prefix=''):
	# load input data
	X = load_file(prefix + group + '/X_'+group+'.txt')
	# load class output
	y = load_file(prefix + group + '/y_'+group+'.txt')
	return X, y

# load the dataset, returns train and test X and y elements
def load_dataset(prefix=''):
	# load all train
	trainX, trainy = load_dataset_group('train', prefix + 'HARDataset/')
	print(trainX.shape, trainy.shape)
	# load all test
	testX, testy = load_dataset_group('test', prefix + 'HARDataset/')
	print(testX.shape, testy.shape)
	# flatten y
	trainy, testy = trainy[:,0], testy[:,0]
	print(trainX.shape, trainy.shape, testX.shape, testy.shape)
	return trainX, trainy, testX, testy

# create a dict of standard models to evaluate {name:object}
def define_models(models=dict()):
	# nonlinear models
	models['knn'] = KNeighborsClassifier(n_neighbors=7)
	models['cart'] = DecisionTreeClassifier()
	models['svm'] = SVC()
	models['bayes'] = GaussianNB()
	# ensemble models
	models['bag'] = BaggingClassifier(n_estimators=100)
	models['rf'] = RandomForestClassifier(n_estimators=100)
	models['et'] = ExtraTreesClassifier(n_estimators=100)
	models['gbm'] = GradientBoostingClassifier(n_estimators=100)
	print('Defined %d models' % len(models))
	return models

# evaluate a single model
def evaluate_model(trainX, trainy, testX, testy, model):
	# fit the model
	model.fit(trainX, trainy)
	# make predictions
	yhat = model.predict(testX)
	# evaluate predictions
	accuracy = accuracy_score(testy, yhat)
	return accuracy * 100.0

# evaluate a dict of models {name:object}, returns {name:score}
def evaluate_models(trainX, trainy, testX, testy, models):
	results = dict()
	for name, model in models.items():
		# evaluate the model
		results[name] = evaluate_model(trainX, trainy, testX, testy, model)
		# show process
		print('>%s: %.3f' % (name, results[name]))
	return results

# print and plot the results
def summarize_results(results, maximize=True):
	# create a list of (name, mean(scores)) tuples
	mean_scores = [(k,v) for k,v in results.items()]
	# sort tuples by mean score
	mean_scores = sorted(mean_scores, key=lambda x: x[1])
	# reverse for descending order (e.g. for accuracy)
	if maximize:
		mean_scores = list(reversed(mean_scores))
	print()
	for name, score in mean_scores:
		print('Name=%s, Score=%.3f' % (name, score))

# load dataset
trainX, trainy, testX, testy = load_dataset()
# get model list
models = define_models()
# evaluate models
results = evaluate_models(trainX, trainy, testX, testy, models)
# summarize results
summarize_results(results)

L'esecuzione dell'esempio carica innanzitutto i set di dati di training e test, mostrando la forma di ciascuno dei componenti di input e output.

Gli otto modelli vengono poi valutati a turno, stampando la prestazione per ciascuno.

Infine, viene visualizzata una classifica dei modelli in base alle loro prestazioni sul set di test.

Nota: i risultati possono variare a causa della natura stocastica dell'algoritmo o della procedura di valutazione o delle differenze nella precisione numerica. Considera l'idea di eseguire l'esempio alcune volte e confrontare il risultato medio.

Possiamo vedere che sia il metodo ensemble ExtraTrees che i metodi non lineari Support Vector Machines raggiungono una prestazione di circa il 94% di precisione sul set di test.

Si tratta di un ottimo risultato, che supera l’89% riportato da SVM nel documento originale.

(7352, 561) (7352, 1)
(2947, 561) (2947, 1)
(7352, 561) (7352,) (2947, 561) (2947,)
Defined 8 models
>knn: 90.329
>cart: 86.020
>svm: 94.028
>bayes: 77.027
>bag: 89.820
>rf: 92.772
>et: 94.028
>gbm: 93.756

Name=et, Score=94.028
Name=svm, Score=94.028
Name=gbm, Score=93.756
Name=rf, Score=92.772
Name=knn, Score=90.329
Name=bag, Score=89.820
Name=cart, Score=86.020
Name=bayes, Score=77.027

Questi risultati mostrano cosa è possibile fare data l’esperienza del dominio nella preparazione dei dati e nell’ingegnerizzazione delle caratteristiche specifiche del dominio. In quanto tali, questi risultati possono essere considerati come un limite superiore delle prestazioni di ciò che potrebbe essere perseguito attraverso metodi più avanzati che potrebbero essere in grado di apprendere automaticamente le funzionalità come parte dell’adattamento del modello, come i metodi di deep learning.

Qualsiasi metodo avanzato di questo tipo verrebbe adattato e valutato sui dati grezzi da cui derivano le caratteristiche ingegnerizzate. Pertanto, le prestazioni degli algoritmi di apprendimento automatico valutati direttamente su tali dati possono fornire un limite inferiore previsto sulle prestazioni di eventuali metodi più avanzati.

Esploreremo questo aspetto nella prossima sezione.

Modellazione dei dati grezzi

Possiamo utilizzare lo stesso framework per valutare i modelli di machine learning sui dati grezzi.

I dati grezzi richiedono un po' più di lavoro per essere caricati.

Esistono tre tipi principali di segnali nei dati grezzi: accelerazione totale, accelerazione del corpo e giroscopio del corpo. Ciascuno ha tre assi di dati. Ciò significa che ci sono un totale di nove variabili per ogni fase temporale.

Inoltre, ciascuna serie di dati è stata suddivisa in finestre sovrapposte di 2,65 secondi di dati, ovvero 128 passaggi temporali. Queste finestre di dati corrispondono alle finestre di caratteristiche ingegnerizzate (righe) nella sezione precedente.

Ciò significa che una riga di dati ha 128 * 9 o 1.152 elementi. Si tratta di poco meno del doppio della dimensione dei 561 vettori di elementi nella sezione precedente ed è probabile che vi siano alcuni dati ridondanti.

I segnali vengono memorizzati nella directory /Inertial Signals/ nelle sottodirectory train e test. Ciascun asse di ciascun segnale viene memorizzato in un file separato, il che significa che ciascuno dei set di dati di treno e test ha nove file di input da caricare e un file di output da caricare. Possiamo raggruppare il caricamento di questi file in gruppi date le strutture di directory coerenti e le convenzioni di denominazione dei file.

Innanzitutto, possiamo caricare tutti i dati per un dato gruppo in un singolo array NumPy tridimensionale, dove le dimensioni dell'array sono [campioni, passaggi temporali, caratteristiche]. Per renderlo più chiaro, ci sono 128 fasi temporali e nove funzioni, dove il numero di campioni è il numero di righe in un dato file di dati del segnale grezzo.

La funzione load_group() di seguito implementa questo comportamento. La funzione dstack() NumPy ci consente di impilare ciascuno degli array 3D caricati in un singolo array 3D in cui le variabili sono separate sulla terza dimensione (caratteristiche).

# load a list of files into a 3D array of [samples, timesteps, features]
def load_group(filenames, prefix=''):
	loaded = list()
	for name in filenames:
		data = load_file(prefix + name)
		loaded.append(data)
	# stack group so that features are the 3rd dimension
	loaded = dstack(loaded)
	return loaded

Possiamo utilizzare questa funzione per caricare tutti i dati del segnale di ingresso per un dato gruppo, come treno o test.

La funzione load_dataset_group() di seguito carica tutti i dati del segnale di input e i dati di output per un singolo gruppo utilizzando le convenzioni di denominazione coerenti tra le directory.

# load a dataset group, such as train or test
def load_dataset_group(group, prefix=''):
	filepath = prefix + group + '/Inertial Signals/'
	# load all 9 files as a single array
	filenames = list()
	# total acceleration
	filenames += ['total_acc_x_'+group+'.txt', 'total_acc_y_'+group+'.txt', 'total_acc_z_'+group+'.txt']
	# body acceleration
	filenames += ['body_acc_x_'+group+'.txt', 'body_acc_y_'+group+'.txt', 'body_acc_z_'+group+'.txt']
	# body gyroscope
	filenames += ['body_gyro_x_'+group+'.txt', 'body_gyro_y_'+group+'.txt', 'body_gyro_z_'+group+'.txt']
	# load input data
	X = load_group(filenames, filepath)
	# load class output
	y = load_file(prefix + group + '/y_'+group+'.txt')
	return X, y

Infine, possiamo caricare ciascuno dei set di dati del treno e testare.

Come parte della preparazione dei dati caricati, dobbiamo appiattire le finestre e le funzionalità in un unico lungo vettore.

Possiamo farlo con la funzione di rimodellamento di NumPy e convertire le tre dimensioni di [samples, timesteps, features] nelle due dimensioni di [samples, timessteps * features].

La funzione load_dataset() riportata di seguito implementa questo comportamento e restituisce gli elementi di training e test X e y pronti per l'adattamento e la valutazione dei modelli definiti.

# load the dataset, returns train and test X and y elements
def load_dataset(prefix=''):
	# load all train
	trainX, trainy = load_dataset_group('train', prefix + 'HARDataset/')
	print(trainX.shape, trainy.shape)
	# load all test
	testX, testy = load_dataset_group('test', prefix + 'HARDataset/')
	print(testX.shape, testy.shape)
	# flatten X
	trainX = trainX.reshape((trainX.shape[0], trainX.shape[1] * trainX.shape[2]))
	testX = testX.reshape((testX.shape[0], testX.shape[1] * testX.shape[2]))
	# flatten y
	trainy, testy = trainy[:,0], testy[:,0]
	print(trainX.shape, trainy.shape, testX.shape, testy.shape)
	return trainX, trainy, testX, testy

Mettendo tutto insieme, l'esempio completo è elencato di seguito.

# spot check on raw data
from numpy import dstack
from pandas import read_csv
from sklearn.metrics import accuracy_score
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.ensemble import GradientBoostingClassifier

# load a single file as a numpy array
def load_file(filepath):
	dataframe = read_csv(filepath, header=None, delim_whitespace=True)
	return dataframe.values

# load a list of files into a 3D array of [samples, timesteps, features]
def load_group(filenames, prefix=''):
	loaded = list()
	for name in filenames:
		data = load_file(prefix + name)
		loaded.append(data)
	# stack group so that features are the 3rd dimension
	loaded = dstack(loaded)
	return loaded

# load a dataset group, such as train or test
def load_dataset_group(group, prefix=''):
	filepath = prefix + group + '/Inertial Signals/'
	# load all 9 files as a single array
	filenames = list()
	# total acceleration
	filenames += ['total_acc_x_'+group+'.txt', 'total_acc_y_'+group+'.txt', 'total_acc_z_'+group+'.txt']
	# body acceleration
	filenames += ['body_acc_x_'+group+'.txt', 'body_acc_y_'+group+'.txt', 'body_acc_z_'+group+'.txt']
	# body gyroscope
	filenames += ['body_gyro_x_'+group+'.txt', 'body_gyro_y_'+group+'.txt', 'body_gyro_z_'+group+'.txt']
	# load input data
	X = load_group(filenames, filepath)
	# load class output
	y = load_file(prefix + group + '/y_'+group+'.txt')
	return X, y

# load the dataset, returns train and test X and y elements
def load_dataset(prefix=''):
	# load all train
	trainX, trainy = load_dataset_group('train', prefix + 'HARDataset/')
	print(trainX.shape, trainy.shape)
	# load all test
	testX, testy = load_dataset_group('test', prefix + 'HARDataset/')
	print(testX.shape, testy.shape)
	# flatten X
	trainX = trainX.reshape((trainX.shape[0], trainX.shape[1] * trainX.shape[2]))
	testX = testX.reshape((testX.shape[0], testX.shape[1] * testX.shape[2]))
	# flatten y
	trainy, testy = trainy[:,0], testy[:,0]
	print(trainX.shape, trainy.shape, testX.shape, testy.shape)
	return trainX, trainy, testX, testy

# create a dict of standard models to evaluate {name:object}
def define_models(models=dict()):
	# nonlinear models
	models['knn'] = KNeighborsClassifier(n_neighbors=7)
	models['cart'] = DecisionTreeClassifier()
	models['svm'] = SVC()
	models['bayes'] = GaussianNB()
	# ensemble models
	models['bag'] = BaggingClassifier(n_estimators=100)
	models['rf'] = RandomForestClassifier(n_estimators=100)
	models['et'] = ExtraTreesClassifier(n_estimators=100)
	models['gbm'] = GradientBoostingClassifier(n_estimators=100)
	print('Defined %d models' % len(models))
	return models

# evaluate a single model
def evaluate_model(trainX, trainy, testX, testy, model):
	# fit the model
	model.fit(trainX, trainy)
	# make predictions
	yhat = model.predict(testX)
	# evaluate predictions
	accuracy = accuracy_score(testy, yhat)
	return accuracy * 100.0

# evaluate a dict of models {name:object}, returns {name:score}
def evaluate_models(trainX, trainy, testX, testy, models):
	results = dict()
	for name, model in models.items():
		# evaluate the model
		results[name] = evaluate_model(trainX, trainy, testX, testy, model)
		# show process
		print('>%s: %.3f' % (name, results[name]))
	return results

# print and plot the results
def summarize_results(results, maximize=True):
	# create a list of (name, mean(scores)) tuples
	mean_scores = [(k,v) for k,v in results.items()]
	# sort tuples by mean score
	mean_scores = sorted(mean_scores, key=lambda x: x[1])
	# reverse for descending order (e.g. for accuracy)
	if maximize:
		mean_scores = list(reversed(mean_scores))
	print()
	for name, score in mean_scores:
		print('Name=%s, Score=%.3f' % (name, score))

# load dataset
trainX, trainy, testX, testy = load_dataset()
# get model list
models = define_models()
# evaluate models
results = evaluate_models(trainX, trainy, testX, testy, models)
# summarize results
summarize_results(results)

L'esecuzione dell'esempio carica innanzitutto il set di dati.

Possiamo vedere che il treno grezzo e i set di test hanno lo stesso numero di campioni delle caratteristiche ingegnerizzate (rispettivamente 7352 e 2947) e che i dati tridimensionali sono stati caricati correttamente. Possiamo anche vedere i dati appiattiti e i 1152 vettori di input che verranno forniti ai modelli.

Successivamente vengono valutati uno dopo l'altro gli otto modelli definiti.

Nota: i risultati possono variare a causa della natura stocastica dell'algoritmo o della procedura di valutazione o delle differenze nella precisione numerica. Considera l'idea di eseguire l'esempio alcune volte e confrontare il risultato medio.

I risultati finali suggeriscono che gli insiemi di alberi decisionali ottengono i migliori risultati sui dati grezzi. Gradient Boosting e Extra Trees danno il meglio di sé con una precisione pari a circa l'87% e l'86%, circa sette punti al di sotto dei modelli con le migliori prestazioni nella versione del set di dati progettata per le funzionalità.

È incoraggiante che il metodo dell’insieme Extra Trees abbia funzionato bene su entrambi i set di dati; suggerisce che metodi simili di insieme di alberi potrebbero essere adatti al problema, almeno in questa inquadratura semplificata.

Possiamo anche vedere il calo dell'SVM a circa il 72% di precisione.

La buona prestazione degli insiemi di alberi decisionali può suggerire la necessità di una selezione delle caratteristiche e la capacità dei metodi d'insieme di selezionare quelle caratteristiche che sono più rilevanti per prevedere l'attività associata.

(7352, 128, 9) (7352, 1)
(2947, 128, 9) (2947, 1)
(7352, 1152) (7352,) (2947, 1152) (2947,)
Defined 8 models
>knn: 61.893
>cart: 72.141
>svm: 76.960
>bayes: 72.480
>bag: 84.527
>rf: 84.662
>et: 86.902
>gbm: 87.615

Name=gbm, Score=87.615
Name=et, Score=86.902
Name=rf, Score=84.662
Name=bag, Score=84.527
Name=svm, Score=76.960
Name=bayes, Score=72.480
Name=cart, Score=72.141
Name=knn, Score=61.893

Come notato nella sezione precedente, questi risultati forniscono un limite inferiore di precisione per qualsiasi metodo più sofisticato che possa tentare di apprendere automaticamente funzionalità di ordine superiore (ad esempio tramite l'apprendimento delle funzionalità nei metodi di deep learning) dai dati grezzi.

In sintesi, i limiti per tali metodi si estendono su questo set di dati da circa l'87% di precisione con GBM sui dati grezzi a circa il 94% con Extra Trees e SVM sul set di dati altamente elaborato, [dall'87% al 94%].

Estensioni

In questa sezione sono elencate alcune idee per estendere il tutorial che potresti voler esplorare.

  • Più algoritmi. Sul problema sono stati valutati solo otto algoritmi di machine learning; provare alcuni metodi lineari e forse alcuni metodi più non lineari e d'insieme.
  • Ottimizzazione dell'algoritmo. Non è stata eseguita alcuna messa a punto degli algoritmi di apprendimento automatico; sono state utilizzate principalmente configurazioni predefinite. Scegli un metodo come SVM, ExtraTrees o Gradient Boosting e cerca sulla griglia una suite di diverse configurazioni di iperparametri per vedere se puoi aumentare ulteriormente le prestazioni sul problema.
  • Ridimensionamento dei dati. I dati sono già scalati a [-1,1], forse per soggetto. Esplorare se un ulteriore ridimensionamento, come la standardizzazione, può comportare prestazioni migliori, magari su metodi sensibili a tale ridimensionamento come kNN.

Se esplori una di queste estensioni, mi piacerebbe saperlo.

Ulteriori letture

Questa sezione fornisce più risorse sull'argomento se desideri approfondire.

Carte

  • Un set di dati di dominio pubblico per il riconoscimento dell'attività umana tramite smartphone, 2013.
  • Riconoscimento dell'attività umana sugli smartphone utilizzando una macchina vettoriale di supporto multiclasse compatibile con l'hardware, 2012.

Articoli

  • Riconoscimento dell'attività umana utilizzando il set di dati degli smartphone, repository di apprendimento automatico UCI
  • Riconoscimento delle attività, Wikipedia
  • Esperimento di riconoscimento delle attività utilizzando i sensori dello smartphone, video.

Riepilogo

In questo tutorial hai scoperto come valutare una suite diversificata di algoritmi di machine learning sul set di dati "Riconoscimento delle attività tramite smartphone".

Nello specifico, hai imparato:

  • Come caricare e valutare algoritmi di machine learning non lineari e di insieme sulla versione progettata per funzionalità del set di dati di riconoscimento delle attività.
  • Come caricare e valutare gli algoritmi di apprendimento automatico sui dati del segnale grezzo per il set di dati di riconoscimento dell'attività.
  • Come definire limiti inferiori e superiori ragionevoli sulle prestazioni attese di algoritmi più sofisticati in grado di apprendere funzionalità, come i metodi di deep learning.

Hai qualche domanda?
Poni le tue domande nei commenti qui sotto e farò del mio meglio per rispondere.

Articoli correlati