Guida definitiva alla regressione logistica in Python PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Guida definitiva alla regressione logistica in Python

Introduzione

A volte confuso con regressione lineare dai novizi – per la condivisione del termine regressione - regressione logistica è molto diverso da regressione lineare. Mentre la regressione lineare prevede valori come 2, 2.45, 6.77 o valori continui, rendendolo un regressione algoritmo, regressione logistica prevede valori come 0 o 1, 1 o 2 o 3, che sono valori discreti, rendendolo un classificazione algoritmo. Sì, si chiama regressione ma è un classificazione algoritmo. Ne parleremo tra un momento.

Pertanto, se il tuo problema di data science coinvolge valori continui, puoi applicare a regressione algoritmo (la regressione lineare è uno di questi). In caso contrario, se si tratta di classificare input, valori discreti o classi, è possibile applicare a classificazione algoritmo (la regressione logistica è uno di questi).

In questa guida, eseguiremo la regressione logistica in Python con la libreria Scikit-Learn. Spiegheremo anche perché la parola "regressione" è presente nel nome e come funziona la regressione logistica.

Per fare ciò, caricheremo prima i dati che verranno classificati, visualizzati e pre-elaborati. Quindi, costruiremo un modello di regressione logistica che comprenderà quei dati. Questo modello verrà quindi valutato e utilizzato per prevedere i valori sulla base di nuovi input.

Motivazione

L'azienda per cui lavori ha stretto una partnership con un'azienda agricola turca. Questa partnership prevede la vendita di semi di zucca. I semi di zucca sono molto importanti per l'alimentazione umana. Contengono una buona proporzione di carboidrati, grassi, proteine, calcio, potassio, fosforo, magnesio, ferro e zinco.

Nel team di scienza dei dati, il tuo compito è distinguere tra i tipi di semi di zucca semplicemente utilizzando i dati - o classificazione i dati in base al tipo di seme.

La fattoria turca lavora con due tipi di semi di zucca, uno si chiama Cercevelik e l'altro Ürgup Sivrisi.

Per classificare i semi di zucca, il tuo team ha seguito il documento del 2021 “L'uso dei metodi di machine learning nella classificazione dei semi di zucca (Cucurbita pepo L.). Risorse genetiche ed evoluzione delle colture” di Koklu, Sarigil e Ozbek: in questo articolo c'è una metodologia per fotografare ed estrarre le misurazioni dei semi dalle immagini.

Dopo aver completato il processo descritto nel documento, sono state estratte le seguenti misurazioni:

  • Zona – il numero di pixel all'interno dei bordi di un seme di zucca
  • Perimetro – la circonferenza in pixel di un seme di zucca
  • Lunghezza dell'asse maggiore – anche la circonferenza in pixel di un seme di zucca
  • Lunghezza dell'asse minore – la piccola distanza dell'asse di un seme di zucca
  • Eccentricità – l'eccentricità di un seme di zucca
  • Area convessa – il numero di pixel del guscio convesso più piccolo nella regione formata dal seme di zucca
  • Estensione – il rapporto tra un'area di semi di zucca e i pixel del riquadro di delimitazione
  • Diametro equivalente – la radice quadrata della moltiplicazione dell'area del seme di zucca per quattro divisa per pi
  • Compattezza – la proporzione dell'area del seme di zucca rispetto all'area del cerchio con la stessa circonferenza
  • Solidity – la condizione convessa e convessa dei semi di zucca
  • Rotondità – l'ovalità dei semi di zucca senza considerare le distorsioni dei bordi
  • Aspect Ratio – le proporzioni dei semi di zucca

Queste sono le misure con cui devi lavorare. Oltre alle misure, c'è anche il Classe etichetta per i due tipi di semi di zucca.

Per iniziare a classificare i semi, importiamo i dati e iniziamo a guardarli.

Comprendere il set di dati

Nota: Puoi scaricare il set di dati della zucca qui.

Dopo aver scaricato il set di dati, possiamo caricarlo in una struttura dataframe utilizzando il file pandas biblioteca. Poiché si tratta di un file excel, utilizzeremo il read_excel() Metodo:

import pandas as pd

fpath = 'dataset/pumpkin_seeds_dataset.xlsx' 
df = pd.read_excel(fpath)

Una volta caricati i dati, possiamo dare una rapida occhiata alle prime 5 righe usando il file head() Metodo:

df.head() 

Questo risulta in:

	Area 	Perimeter 	Major_Axis_Length 	Minor_Axis_Length 	Convex_Area 	Equiv_Diameter 	Eccentricity 	Solidity 	Extent 	Roundness 	Aspect_Ration 	Compactness 	Class
0 	56276 	888.242 	326.1485 			220.2388 			56831 			267.6805 		0.7376 			0.9902 		0.7453 	0.8963 		1.4809 			0.8207 			Çerçevelik
1 	76631 	1068.146 	417.1932 			234.2289 			77280 			312.3614 		0.8275 			0.9916 		0.7151 	0.8440 		1.7811 			0.7487 			Çerçevelik
2 	71623 	1082.987 	435.8328 			211.0457 			72663 			301.9822 		0.8749 			0.9857 		0.7400 	0.7674 		2.0651 			0.6929 			Çerçevelik
3 	66458 	992.051 	381.5638 			222.5322 			67118 			290.8899 		0.8123 			0.9902 		0.7396 	0.8486 		1.7146 			0.7624 			Çerçevelik
4 	66107 	998.146 	383.8883 			220.4545 			67117 			290.1207 		0.8187 			0.9850 		0.6752 	0.8338 		1.7413 			0.7557 			Çerçevelik

Qui abbiamo tutte le misure nelle rispettive colonne, la nostra Caratteristiche, E anche il Classe colonna, ns bersaglio, che è l'ultimo nel dataframe. Possiamo vedere quante misurazioni abbiamo usando il shape attributo:

df.shape 

L'output è:

(2500, 13)

Il risultato della forma ci dice che ci sono 2500 voci (o righe) nel set di dati e 13 colonne. Poiché sappiamo che esiste una colonna di destinazione, ciò significa che abbiamo 12 colonne di funzionalità.

Ora possiamo esplorare la variabile target, il seme di zucca Class. Dal momento che prevediamo quella variabile, è interessante vedere quanti campioni di ciascun seme di zucca abbiamo. Di solito, minore è la differenza tra il numero di istanze nelle nostre classi, più equilibrato è il nostro campione e migliori sono le nostre previsioni.

Questa ispezione può essere eseguita contando ogni campione di semi con il value_counts() Metodo:

df['Class'].value_counts() 

Il codice sopra mostra:

Çerçevelik       1300
Ürgüp Sivrisi    1200
Name: Class, dtype: int64

Possiamo vedere che ci sono 1300 campioni di Cercevelik seme e 1200 campioni di Ürgup Sivrisi seme. Si noti che la differenza tra loro è di 100 campioni, una differenza molto piccola, il che è positivo per noi e indica che non è necessario riequilibrare il numero di campioni.

Diamo un'occhiata anche alle statistiche descrittive delle nostre funzionalità con il describe() metodo per vedere quanto sono ben distribuiti i dati. Trasporremo anche la tabella risultante con T per semplificare il confronto tra le statistiche:

df.describe().T

La tabella risultante è:

					count 	mean 			std 			min 		25% 			50% 			75% 			max
Area 				2500.0 	80658.220800 	13664.510228 	47939.0000 	70765.000000 	79076.00000 	89757.500000 	136574.0000
Perimeter 			2500.0 	1130.279015 	109.256418 		868.4850 	1048.829750 	1123.67200 		1203.340500 	1559.4500
Major_Axis_Length 	2500.0 	456.601840 		56.235704 		320.8446 	414.957850 		449.49660 		492.737650 		661.9113
Minor_Axis_Length 	2500.0 	225.794921 		23.297245 		152.1718 	211.245925 		224.70310 		240.672875 		305.8180
Convex_Area 		2500.0 	81508.084400 	13764.092788 	48366.0000 	71512.000000 	79872.00000 	90797.750000 	138384.0000
Equiv_Diameter 		2500.0 	319.334230 		26.891920 		247.0584 	300.167975 		317.30535 		338.057375 		417.0029
Eccentricity 		2500.0 	0.860879 		0.045167 		0.4921 		0.831700 		0.86370 		0.897025 		0.9481
Solidity 			2500.0 	0.989492 		0.003494 		0.9186 		0.988300 		0.99030 		0.991500 		0.9944
Extent 				2500.0 	0.693205 		0.060914 		0.4680 		0.658900 		0.71305 		0.740225 		0.8296
Roundness 			2500.0 	0.791533 		0.055924 		0.5546 		0.751900 		0.79775 		0.834325 		0.9396
Aspect_Ration 		2500.0 	2.041702 		0.315997 		1.1487 		1.801050 		1.98420 		2.262075 		3.1444
Compactness 		2500.0 	0.704121 		0.053067 		0.5608 		0.663475 		0.70770 		0.743500 		0.9049

Guardando la tabella, quando si confrontano i significare ed deviazione standard (std) colonne, si può notare che la maggior parte delle caratteristiche ha una media che è lontana dalla deviazione standard. Ciò indica che i valori dei dati non sono concentrati attorno al valore medio, ma più sparsi intorno ad esso, in altre parole, lo sono elevata variabilità.

Inoltre, guardando il ordine (min) e massimo (max) colonne, alcune funzionalità, ad esempio Areae Convex_Area, presentano grandi differenze tra i valori minimo e massimo. Ciò significa che quelle colonne contengono dati molto piccoli e anche valori di dati molto grandi, o ampiezza maggiore tra valori di dati.

Con elevata variabilità, ampiezza elevata e caratteristiche con unità di misura diverse, la maggior parte dei nostri dati trarrebbero vantaggio dall'avere la stessa scala per tutte le caratteristiche o dall'essere scalato. Il ridimensionamento dei dati centra i dati attorno alla media e ne riduce la varianza.

Questo scenario probabilmente indica anche la presenza di valori anomali e valori estremi nei dati. Quindi, è meglio averne alcuni trattamento anomalo oltre a ridimensionare i dati.

Esistono alcuni algoritmi di apprendimento automatico, ad esempio algoritmi basati su alberi come Classificazione casuale delle foreste, che non sono influenzati da varianza dei dati elevata, valori anomali e valori estremi. Regressione logistica è diverso, si basa su una funzione che classifica i nostri valori e i parametri di tale funzione possono essere influenzati da valori che sono fuori dall'andamento generale dei dati e hanno una varianza elevata.

Capiremo di più sulla regressione logistica tra un po' quando la implementeremo. Per ora, possiamo continuare a esplorare i nostri dati.

Nota: C'è un detto popolare in Informatica: "Spazzatura dentro, spazzatura fuori" (GIGO), che è adatto per l'apprendimento automatico. Ciò significa che quando abbiamo dati spazzatura - misurazioni che non descrivono i fenomeni in sé, dati che non sono stati compresi e ben preparati in base al tipo di algoritmo o modello, genereranno probabilmente un output errato che non funzionerà su una base quotidiana.
Questo è uno dei motivi per cui l'esplorazione, la comprensione dei dati e il funzionamento del modello scelto sono così importanti. In questo modo, possiamo evitare di mettere spazzatura nel nostro modello, mettendo invece valore in esso e ottenendo valore.

Visualizzazione dei dati

Finora, con le statistiche descrittive, abbiamo un'istantanea in qualche modo astratta di alcune qualità dei dati. Un altro passo importante è visualizzarlo e confermare la nostra ipotesi di varianza, ampiezza e valori anomali elevati. Per vedere se ciò che abbiamo osservato finora appare nei dati, possiamo tracciare alcuni grafici.

È anche interessante vedere come le caratteristiche siano relative alle due classi che saranno previste. Per fare ciò, importiamo il file seaborn pacchetto e utilizzare il pairplot grafico per esaminare ogni distribuzione delle caratteristiche e ogni separazione di classi per caratteristica:

import seaborn as sns


sns.pairplot(data=df, hue='Class')

Nota: L'esecuzione del codice precedente potrebbe richiedere del tempo, poiché il pairplot combina i grafici a dispersione di tutte le funzionalità (può farlo) e visualizza anche le distribuzioni delle funzionalità.

Osservando il pairplot, possiamo vedere che nella maggior parte dei casi i punti del Çerçevelik classe sono nettamente separati dai punti della Ürgüp Sivrisi classe. O i punti di una classe sono a destra quando gli altri sono a sinistra, oppure alcuni sono in alto mentre gli altri sono in basso. Se dovessimo usare una sorta di curva o linea per separare le classi, questo mostra che è più facile separarle, se fossero miste, la classificazione sarebbe un compito più difficile.

Nel Eccentricity, Compactness ed Aspect_Ration colonne, alcuni punti che sono "isolati" o devianti dall'andamento generale dei dati - valori anomali - sono facilmente individuabili.

Osservando la diagonale dalla parte superiore sinistra alla parte inferiore destra del grafico, si noti che anche le distribuzioni dei dati sono codificate a colori in base alle nostre classi. Le forme di distribuzione e la distanza tra le due curve sono altri indicatori di quanto siano separabili: più sono distanti l'una dall'altra, meglio è. Nella maggior parte dei casi, non sono sovrapposti, il che implica che sono più facili da separare, contribuendo anche al nostro compito.

In sequenza, possiamo anche tracciare i boxplot di tutte le variabili con il sns.boxplot() metodo. La maggior parte delle volte, è utile orientare i boxplot orizzontalmente, quindi le forme dei boxplot sono le stesse delle forme di distribuzione, possiamo farlo con il orient argomento:


sns.boxplot(data=df, orient='h') 

Guida definitiva alla regressione logistica in Python PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Nella trama sopra, notalo Area ed Convex_Area hanno una magnitudine così elevata rispetto alle magnitudini delle altre colonne, che schiacciano gli altri boxplot. Per essere in grado di guardare tutti i boxplot, possiamo ridimensionare le funzionalità e tracciarle di nuovo.

Prima di farlo, capiamo solo che se ci sono valori di caratteristiche che sono intimamente correlati ad altri valori, per esempio, se ci sono valori che aumentano anche quando altri valori di caratteristica diventano più grandi, avere un correlazione positiva; o se ci sono valori che fanno il contrario, diventano più piccoli mentre altri valori diventano più piccoli, avendo a correlazione negativa.

Questo è importante da considerare perché avere relazioni forti nei dati potrebbe significare che alcune colonne sono state derivate da altre colonne o hanno un significato simile al nostro modello. Quando ciò accade, i risultati del modello potrebbero essere sovrastimati e vogliamo risultati più vicini alla realtà. Se ci sono forti correlazioni, significa anche che possiamo ridurre il numero di funzionalità e utilizzare meno colonne per aumentare il modello parsimonioso.

Nota: La correlazione predefinita calcolata con il corr() il metodo è il Coefficiente di correlazione di Pearson. Questo coefficiente è indicato quando i dati sono quantitativi, normalmente distribuiti, non hanno valori anomali e hanno una relazione lineare.

Un'altra scelta sarebbe calcolare Coefficiente di correlazione di Spearman. Il coefficiente di Spearman viene utilizzato quando i dati sono ordinali, non lineari, hanno qualsiasi distribuzione e hanno valori anomali. Si noti che i nostri dati non si adattano completamente alle ipotesi di Pearson o Spearman (ci sono anche più metodi di correlazione, come quello di Kendall). Poiché i nostri dati sono quantitativi ed è importante per noi misurarne la relazione lineare, utilizzeremo il coefficiente di Pearson.

Diamo un'occhiata alle correlazioni tra le variabili e poi possiamo passare alla pre-elaborazione dei dati. Calcoleremo le correlazioni con il corr() metodo e visualizzarli con Seaborn's heatmap(). La dimensione standard della mappa di calore tende ad essere piccola, quindi importeremo matplotlib (motore di visualizzazione generale/libreria su cui è costruito Seaborn) e modificare le dimensioni con figsize:

import matplotlib.pyplot as plt
plt.figure(figsize=(15, 10))

correlations = df.corr()
sns.heatmap(correlations, annot=True) 

Guida definitiva alla regressione logistica in Python PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

In questa mappa di calore, i valori più vicini a 1 o -1 sono i valori a cui dobbiamo prestare attenzione. Il primo caso, denota un'elevata correlazione positiva e il secondo, un'elevata correlazione negativa. Entrambi i valori, se non superiori a 0.8 o -0.8, saranno utili per il nostro modello di regressione logistica.

Quando ci sono alte correlazioni come quella di 0.99 fra Aspec_Ration ed Compactness, questo significa che possiamo scegliere di utilizzare solo Aspec_Ration o solo Compactness, invece di entrambi (dal momento che sarebbero quasi uguali predittori di ciascun altro). Lo stesso vale per Eccentricity ed Compactness con una -0.98 correlazione, per Area ed Perimeter con una 0.94 correlazione e alcune altre colonne.

Pre-elaborazione dei dati

Poiché abbiamo già esplorato i dati per un po', possiamo iniziare a pre-elaborarli. Per ora, utilizziamo tutte le funzionalità per la previsione della classe. Dopo aver ottenuto un primo modello, una linea di base, possiamo quindi rimuovere alcune delle colonne altamente correlate e confrontarlo con la linea di base.

Le colonne delle caratteristiche saranno le nostre X data e la colonna classe, ns y dati di destinazione:

y = df['Class']
X = df.drop(columns=['Class'], axis=1)

Trasformare le feature categoriali in feature numeriche

Per quanto riguarda il nostro Class colonna: i suoi valori non sono numeri, questo significa che dobbiamo anche trasformarli. Ci sono molti modi per fare questa trasformazione; qui, useremo il replace() metodo e sostituzione Çerçevelik a 0 ed Ürgüp Sivrisi a 1.

y = y.replace('Çerçevelik', 0).replace('Ürgüp Sivrisi', 1)

Tieni a mente la mappatura! Quando leggi i risultati dal tuo modello, ti consigliamo di riconvertirli almeno nella tua mente o di nuovo nel nome della classe per altri utenti.

Suddivisione dei dati in Train e Test Set

Nella nostra esplorazione, abbiamo notato che le funzionalità richiedevano il ridimensionamento. Se eseguissimo il ridimensionamento ora, o in modo automatico, ridimensioneremmo i valori con l'intero X ed y. In tal caso, vorremmo introdurre perdita di dati, poiché i valori del prossimo set di test avrebbero influito sul ridimensionamento. La fuga di dati è una causa comune di risultati irriproducibili e prestazioni elevate illusorie dei modelli ML.

Pensare al ridimensionamento mostra che dobbiamo prima dividere X ed y dati ulteriormente in treno e set di test e poi a in forma uno scaler sul set di allenamento e a trasformare sia il treno che i set di prova (senza mai che il set di prova influisca sull'ablatore che lo fa). Per questo, useremo Scikit-Learn's train_test_split() Metodo:

from sklearn.model_selection import train_test_split
SEED = 42 

X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size=.25, 
                                                    random_state=SEED)

Configurazione test_size=.25 sta assicurando che stiamo utilizzando il 25% dei dati per i test e il 75% per la formazione. Questo potrebbe essere omesso, una volta che è la divisione predefinita, ma il Divinatorio il modo di scrivere il codice suggerisce che "essere espliciti è meglio che impliciti".

Nota: La frase "esplicito è meglio di implicito" è un riferimento a Lo Zen di Pythono PEP20. Fornisce alcuni suggerimenti per scrivere codice Python. Se si seguono questi suggerimenti, il codice viene considerato Divinatorio. Puoi saperne di più qui.

Dopo aver suddiviso i dati in set di treni e test, è buona norma esaminare quanti record sono presenti in ciascun set. Questo può essere fatto con il shape attributo:

X_train.shape, X_test.shape, y_train.shape, y_test.shape

Questo mostra:

((1875, 12), (625, 12), (1875,), (625,))

Possiamo vedere che dopo la divisione, abbiamo 1875 record per l'addestramento e 625 per i test.

Ridimensionamento dei dati

Una volta che abbiamo il nostro treno e set di test pronti, possiamo procedere a ridimensionare i dati con Scikit-Learn StandardScaler oggetto (o altri scaler forniti dalla libreria). Per evitare perdite, l'ablatore è montato sul X_train i dati e i valori del treno vengono quindi utilizzati per ridimensionare o trasformare i dati del treno e del test:

from sklearn.preprocessing import StandardScaler

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

Dal momento che in genere chiamerai:

scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

Le prime due righe possono essere compresse al singolare fit_transform() call, che si adatta allo scaler sul set e lo trasforma in una volta sola. Ora possiamo riprodurre i grafici boxplot per vedere la differenza dopo aver ridimensionato i dati.

Considerando che il ridimensionamento rimuove i nomi delle colonne, prima del tracciamento, possiamo organizzare nuovamente i dati del treno in un dataframe con i nomi delle colonne per facilitare la visualizzazione:

column_names = df.columns[:12] 
X_train = pd.DataFrame(X_train, columns=column_names)

sns.boxplot(data=X_train, orient='h')

Guida definitiva alla regressione logistica in Python PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Possiamo finalmente vedere tutti i nostri boxplot! Si noti che tutti hanno valori anomali e le caratteristiche che presentano una distribuzione più lontana dalla normale (che hanno curve oblique a sinistra o a destra), come Solidity, Extent, Aspect_Ratione Compactedness, sono gli stessi che avevano correlazioni maggiori.

Rimozione dei valori anomali con il metodo IQR

Sappiamo già che la regressione logistica può essere influenzata da valori anomali. Uno dei modi per trattarli è usare un metodo chiamato Intervallo interquartile or IQR. Il passaggio iniziale del metodo IQR consiste nel dividere i dati del nostro treno in quattro parti, chiamate quartili. Il primo quartile, Q1, ammonta al 25% dei dati, il secondo, Q2, al 50%, il terzo, Q3, al 75%, e l'ultimo, Q4, al 100%. I riquadri nel boxplot sono definiti dal metodo IQR e ne sono una rappresentazione visiva.

Considerando un boxplot orizzontale, la linea verticale a sinistra segna il 25% dei dati, la linea verticale al centro, il 50% dei dati (o la mediana), e l'ultima linea verticale a destra, il 75% dei dati . Più sono uniformi in termini di dimensioni entrambi i quadrati definiti dalle linee verticali – o più la linea verticale mediana è al centro – significa che i nostri dati sono più vicini alla distribuzione normale o meno distorti, il che è utile per la nostra analisi.

Oltre alla casella IQR, ci sono anche linee orizzontali su entrambi i lati. Tali linee segnano i valori di distribuzione minimo e massimo definiti da

$$
Minimo = Q1 – 1.5*IQR
$$

ed

$$
Massimo = Q3 + 1.5*IQR
$$

IQR è esattamente la differenza tra Q3 e Q1 (o Q3 – Q1) ed è il punto più centrale dei dati. Ecco perché quando troviamo l'IQR, finiamo per filtrare i valori anomali nelle estremità dei dati o nei punti minimo e massimo. I box plot ci danno un'anteprima di quale sarà il risultato del metodo IQR.

Guida definitiva alla regressione logistica in Python PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Possiamo usare i Panda quantile() metodo per trovare i nostri quantili, e iqr dal scipy.stats pacchetto per ottenere l'intervallo di dati interquartile per ciascuna colonna:

from scipy.stats import iqr

Q1 = X_train.quantile(q=.25)
Q3 = X_train.quantile(q=.75)

IQR = X_train.apply(iqr)

Ora abbiamo Q1, Q3 e IQR, possiamo filtrare i valori più vicini alla mediana:


minimum = X_train < (Q1-1.5*IQR)
maximum = X_train > (Q3+1.5*IQR)


filter = ~(minimum | maximum).any(axis=1)


X_train = X_train[filter]

Dopo aver filtrato le nostre righe di addestramento, possiamo vedere con quante di esse sono ancora presenti nei dati shape:

X_train.shape

Questo risulta in:

(1714, 12)

Possiamo vedere che il numero di righe è passato da 1875 a 1714 dopo il filtraggio. Ciò significa che 161 righe contenevano valori anomali o l'8.5% dei dati.

Nota: Si consiglia che il filtraggio dei valori anomali, la rimozione dei valori NaN e altre azioni che implicano il filtraggio e la pulizia dei dati rimangano al di sotto o fino al 10% dei dati. Prova a pensare ad altre soluzioni se il filtraggio o la rimozione supera il 10% dei tuoi dati.

Dopo aver rimosso i valori anomali, siamo quasi pronti per includere i dati nel modello. Per l'adattamento del modello, utilizzeremo i dati del treno. X_train è filtrato, ma che dire y_train?

y_train.shape

Questo produce:

(1875,)

Notare che y_train ha ancora 1875 righe. Dobbiamo abbinare il numero di y_train righe al numero di X_train righe e non solo arbitrariamente. Dobbiamo rimuovere i valori y delle istanze di semi di zucca che abbiamo rimosso, che sono probabilmente sparsi per il y_train impostare. Il filtrato X_train ancora ha i suoi indici originali e l'indice ha delle lacune in cui abbiamo rimosso i valori anomali! Possiamo quindi utilizzare l'indice di X_train DataFrame in cui cercare i valori corrispondenti y_train:

y_train = y_train.iloc[X_train.index]

Dopo averlo fatto, possiamo guardare il y_train forma di nuovo:

y_train.shape

Quali uscite:

(1714,)

Dai un'occhiata alla nostra guida pratica e pratica per l'apprendimento di Git, con le migliori pratiche, gli standard accettati dal settore e il cheat sheet incluso. Smetti di cercare su Google i comandi Git e in realtà imparare esso!

Adesso, y_train ha anche 1714 righe e sono le stesse del X_train righe. Siamo finalmente pronti per creare il nostro modello di regressione logistica!

Implementazione del modello di regressione logistica

La parte difficile è fatta! La preelaborazione è solitamente più difficile dello sviluppo di modelli, quando si tratta di utilizzare librerie come Scikit-Learn, che hanno semplificato l'applicazione dei modelli ML a solo un paio di righe.

Per prima cosa importiamo il LogisticRegression class e istanziarla, creando a LogisticRegression oggetto:

from sklearn.linear_model import LogisticRegression
logreg = LogisticRegression(random_state=SEED)

In secondo luogo, adattiamo i dati del nostro treno a logreg modello con il fit() metodo e prevedere i nostri dati di test con il predict() metodo, memorizzando i risultati come y_pred:



logreg.fit(X_train.values, y_train)
y_pred = logreg.predict(X_test)

Abbiamo già fatto previsioni con il nostro modello! Diamo un'occhiata alle prime 3 righe X_train per vedere quali dati abbiamo utilizzato:

X_train[:3]

Il codice sopra restituisce:

       Area          Perimeter     Major_Axis_Length    Minor_Axis_Length    Convex_Area   Equiv_Diameter       Eccentricity  Solidity      Extent        Roundness     Aspect_Ration        Compactness
0      -1.098308     -0.936518     -0.607941            -1.132551            -1.082768     -1.122359            0.458911      -1.078259     0.562847      -0.176041     0.236617             -0.360134
1      -0.501526     -0.468936     -0.387303            -0.376176            -0.507652     -0.475015            0.125764      0.258195      0.211703      0.094213      -0.122270            0.019480
2      0.012372      -0.209168     -0.354107            0.465095              0.003871      0.054384            -0.453911     0.432515      0.794735      0.647084      -0.617427            0.571137

E ai primi 3 pronostici in y_pred per vedere i risultati:

y_pred[:3] 

Questo risulta in:

array([0, 0, 0])

Per quelle tre file, le nostre previsioni erano che fossero semi di prima classe, Çerçevelik.

Con regressione logistica, invece di prevedere la classe finale, ad esempio 0, possiamo anche prevedere la probabilità che la riga abbia di appartenere a 0 classe. Questo è ciò che accade effettivamente quando la regressione logistica classifica i dati e il predict() il metodo passa quindi questa previsione attraverso una soglia per restituire una classe "difficile". Per prevedere la probabilità di appartenere a una classe, predict_proba() si usa:

y_pred_proba = logreg.predict_proba(X_test)

Diamo anche un'occhiata ai primi 3 valori delle previsioni di probabilità y:

y_pred_proba[:3] 

Quali uscite:

        # class 0   class 1   
array([[0.54726628, 0.45273372],
       [0.56324527, 0.43675473],
       [0.86233349, 0.13766651]])

Ora, invece di tre zeri, abbiamo una colonna per ogni classe. Nella colonna a sinistra, a partire da 0.54726628, sono le probabilità dei dati relativi alla classe 0; e nella colonna di destra, iniziando con 0.45273372, sono le probabilità che appartengano alla classe 1.

Nota: Questa differenza di classificazione è anche nota come difficile ed morbido predizione. La previsione hard racchiude la previsione in una classe, mentre le previsioni soft generano il probabilità dell'istanza appartenente a una classe.

Sono disponibili ulteriori informazioni su come è stato realizzato l'output previsto. In realtà non lo era 0, ma una probabilità del 55% di classe 0, e una probabilità del 45% di lezione 1. Questo emerge come i primi tre X_test punti dati, relativi alla classe 0, sono veramente chiari solo per quanto riguarda il terzo punto dati, con una probabilità dell'86% – e non tanto per i primi due punti dati.

Quando si comunicano i risultati utilizzando i metodi ML, in genere è meglio restituire una classe soft e la probabilità associata come "fiducia" di tale classificazione.

Parleremo di più su come viene calcolato quando andremo più a fondo nel modello. A questo punto, possiamo procedere al passaggio successivo.

Valutazione del Modello con Report di Classificazione

Il terzo passaggio consiste nel vedere come si comporta il modello sui dati di test. Possiamo importare Scikit-Learn classification_report() e passa il nostro y_test ed y_pred come argomenti. Successivamente, possiamo stampare la sua risposta.

Il rapporto di classificazione contiene le metriche di classificazione più utilizzate, ad esempio precisione, ricordare, punteggio f1e precisione.

  1. Precisione: per capire quali valori di previsione corretti sono stati considerati corretti dal nostro classificatore. La precisione dividerà quei valori di veri positivi per tutto ciò che è stato previsto come positivo:

$$
precision = frac{testo{vero positivo}}{testo{vero positivo} + testo{falso positivo}}
$$

  1. Richiamo: per capire quanti dei veri positivi sono stati individuati dal nostro classificatore. Il richiamo viene calcolato dividendo i veri positivi per tutto ciò che avrebbe dovuto essere previsto come positivo:

$$
richiamo = frac{testo{vero positivo}}{testo{vero positivo} + testo{falso negativo}}
$$

  1. punteggio F1: è il bilanciato o media armonica di precisione e di richiamo. Il valore più basso è 0 e il più alto è 1. Quando f1-score è uguale a 1, significa che tutte le classi sono state previste correttamente – questo è un punteggio molto difficile da ottenere con dati reali:

$$
testo{f1-score} = 2* frac{testo{precision} * testo{recall}}{text{precision} + testo{recall}}
$$

  1. Precisione: descrive quante previsioni ha ottenuto il nostro classificatore. Il valore di precisione più basso è 0 e il più alto è 1. Tale valore viene solitamente moltiplicato per 100 per ottenere una percentuale:

$$
accuratezza = frac{testo{numero di previsioni corrette}}{testo{numero totale di previsioni}}
$$

Nota: È estremamente difficile ottenere un'accuratezza del 100% su qualsiasi dato reale, se ciò accade, tieni presente che potrebbero verificarsi perdite o qualcosa di sbagliato: non c'è consenso su un valore di precisione ideale ed è anche dipendente dal contesto. Un valore del 70%, il che significa che il classificatore commetterà errori sul 30% dei dati, o superiore al 70% tende ad essere sufficiente per la maggior parte dei modelli.

from sklearn.metrics import classification_report
cr = classification_report(y_test, y_pred)
print(cr)

Possiamo quindi guardare l'output del rapporto di classificazione:

				precision    recall  f1-score   support

           0       0.83      0.91      0.87       316
           1       0.90      0.81      0.85       309

    accuracy                           0.86       625
   macro avg       0.86      0.86      0.86       625
weighted avg       0.86      0.86      0.86       625

Questo è il nostro risultato. Notare che precision, recall, f1-scoree accuracy le metriche sono tutte molto alte, superiori all'80%, il che è l'ideale, ma quei risultati sono stati probabilmente influenzati da correlazioni elevate e non si manterranno a lungo termine.

La precisione del modello è dell'86%, il che significa che sbaglia la classificazione il 14% delle volte. Abbiamo queste informazioni generali, ma sarebbe interessante sapere se gli errori del 14% si verificano nella classificazione della classe 0 o classe 1. Per identificare quali classi sono erroneamente identificate come quali e con quale frequenza, possiamo calcolare e tracciare a matrice di confusione delle previsioni del nostro modello.

Valutazione del modello con una matrice di confusione

Calcoliamo e quindi tracciamo la matrice di confusione. Dopo averlo fatto, possiamo capirne ogni parte. Per tracciare la matrice di confusione, useremo Scikit-Learn confusion_matrix(), che importeremo da metrics modulo.

La matrice di confusione è più facile da visualizzare usando un Seaborn heatmap(). Quindi, dopo averlo generato, passeremo la nostra matrice di confusione come argomento per la mappa di calore:

from sklearn.metrics import confusion_matrix

cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='d')

Guida definitiva alla regressione logistica in Python PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

  1. Matrice di confusione: la matrice mostra quanti campioni il modello ha corretto o sbagliato per ogni classe. Vengono chiamati i valori che erano corretti e correttamente previsti veri positivi, e quelli che erano stati previsti come positivi ma non erano positivi vengono chiamati falsi positivi. La stessa nomenclatura di veri negativi ed falsi negativi è usato per valori negativi;

Osservando la trama della matrice di confusione, possiamo vedere che abbiamo 287 valori che erano 0 e previsto come 0 - o veri positivi per la classe 0 (i semi di Çerçevelik). Abbiamo anche 250 veri aspetti positivi per la classe 1 (Semi di Ürgüp Sivrisi). I veri positivi si trovano sempre nella diagonale della matrice che va da sinistra in alto a destra in basso.

Abbiamo anche 29 valori che avrebbero dovuto essere 0, ma previsto come 1 (falsi positivi) e 59 valori che erano 1 e previsto come 0 (falsi negativi). Con quei numeri, possiamo capire che l'errore che il modello fa di più è che prevede falsi negativi. Quindi, può finire principalmente per classificare un seme Ürgüp Sivrisi come seme Çerçevelik.

Questo tipo di errore si spiega anche con il richiamo dell'81% della classe 1. Si noti che le metriche sono collegate. E la differenza nel richiamo deriva dall'avere 100 campioni in meno della classe Ürgüp Sivrisi. Questa è una delle implicazioni dell'avere solo pochi campioni in meno rispetto all'altra classe. Per migliorare ulteriormente il ricordo, puoi sperimentare con i pesi delle classi o utilizzare più campioni di Ürgüp Sivrisi.

Finora, abbiamo eseguito la maggior parte dei passaggi tradizionali della scienza dei dati e utilizzato il modello di regressione logistica come una scatola nera.

Nota: Se vuoi andare oltre, usa Convalida incrociata (CV) e ricerca griglia cercare, rispettivamente, il modello che generalizza maggiormente i dati e i migliori parametri del modello che vengono scelti prima dell'addestramento, oppure iperparametri.

Idealmente, con CV e Grid Search, potresti anche implementare un modo concatenato per eseguire fasi di pre-elaborazione dei dati, suddivisione dei dati, modellazione e valutazione, il che è semplificato con Scikit-Learn oleodotti.

Ora è il momento di aprire la scatola nera e guardarci dentro, per approfondire la comprensione di come funziona la regressione logistica.

Approfondire come funziona davvero la regressione logistica

Il regressione la parola non è lì per caso, per capire cosa fa la regressione logistica, possiamo ricordare cosa fa la sua regressione lineare ai dati. La formula di regressione lineare era la seguente:

$$
y = b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldot + b_n * x_n
$$

in cui b0 era l'intercetta di regressione, b1 il coefficiente e x1 i dati.

Tale equazione ha prodotto una linea retta che è stata utilizzata per prevedere nuovi valori. Ricordando l'introduzione, la differenza ora è che non prevediamo nuovi valori, ma una classe. Quindi quella linea retta deve cambiare. Con la regressione logistica, introduciamo una non linearità e la previsione viene ora effettuata utilizzando una curva anziché una linea:

Guida definitiva alla regressione logistica in Python PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Osservare che mentre la retta di regressione lineare continua ed è composta da valori infiniti continui, la curva di regressione logistica può essere divisa a metà e ha estremi in 0 e 1 valori. Quella forma a "S" è il motivo per cui classifica i dati: i punti più vicini o che cadono sull'estremità più alta appartengono alla classe 1, mentre i punti che si trovano nel quadrante inferiore o più vicini a 0 appartengono alla classe 0. La parte centrale di la “S” è la metà tra 0 e 1, 0.5 – è la soglia per i punti di regressione logistica.

Guida definitiva alla regressione logistica in Python PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Comprendiamo già la differenza visiva tra regressione logistica e lineare, ma per quanto riguarda la formula? La formula per la regressione logistica è la seguente:

$$
y = b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldot + b_n * x_n
$$

Può anche essere scritto come:

$$
y_{prob} = frac{1}{1 + e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}}
$$

O anche essere scritto come:

$$
y_{prob} = frac{e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}}{1 + e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldot + b_n * x_n)}}
$$

Nell'equazione sopra, abbiamo la probabilità di input, invece del suo valore. Ha 1 come numeratore, quindi può risultare in un valore compreso tra 0 e 1 e 1 più un valore al denominatore, in modo che il suo valore sia 1 e qualcosa del genere: ciò significa che il risultato della frazione intera non può essere maggiore di 1 .

E qual è il valore che c'è al denominatore? è e, la base del logaritmo naturale (circa 2.718282), elevata alla potenza della regressione lineare:

$$
e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}
$$

Un altro modo di scriverlo sarebbe:

$$
ln sinistra( frac{p}{1-p} destra) = {(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}
$$

In quell'ultima equazione, ln è il logaritmo naturale (base e) e p è la probabilità, quindi il logaritmo della probabilità del risultato è lo stesso del risultato della regressione lineare.

In altre parole, con il risultato della regressione lineare e il logaritmo naturale, possiamo arrivare alla probabilità che un input appartenga o meno a una classe progettata.

L'intero processo di derivazione della regressione logistica è il seguente:

$$
p{X} = frac{e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}}{1 + e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldot + b_n * x_n)}}
$$

$$
p(1 + e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}) = e^{(b_0 + b_1 * x_1 + b_2 *x_2 + b_3 * x_3 + ldots + b_n * x_n)}
$$

$$
p + p*e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)} = e^{(b_0 + b_1 * x_1 + b_2 *x_2 + b_3 * x_3 + ldots + b_n * x_n)}
$$

p
=

e

(

b
0

+

b
1

*

x
1

+

b
2

*

x
2

+

b
3

*

x
3

+
...
+

b
n

*

x
n

)

-
p
*

e

(

b
0

+

b
1

*

x
1

+

b
2

*

x
2

+

b
3

*

x
3

+
...
+

b
n

*

x
n

)

$$
frac{p}{1-p} = e^{(b_0 + b_1 * x_1 + b_2 *x_2 + b_3 * x_3 + ldots + b_n * x_n)}
$$

$$
ln sinistra( frac{p}{1-p} destra) = (b_0 + b_1 * x_1 + b_2 *x_2 + b_3 * x_3 + ldots + b_n * x_n)
$$

Ciò significa che il modello di regressione logistica ha anche coefficienti e un valore di intercetta. Perché usa una regressione lineare e vi aggiunge una componente non lineare con il logaritmo naturale (e).

Possiamo vedere i valori dei coefficienti e l'intercetta del nostro modello, allo stesso modo in cui abbiamo fatto per la regressione lineare, usando coef_ ed intercept_ proprietà:

logreg.coef_

Che mostra i coefficienti di ciascuna delle 12 caratteristiche:

array([[ 1.43726172, -1.03136968,  0.24099522, -0.61180768,  1.36538261,
        -1.45321951, -1.22826034,  0.98766966,  0.0438686 , -0.78687889,
         1.9601197 , -1.77226097]])
logreg.intercept_

Ciò si traduce in:

array([0.08735782])

Con i coefficienti e i valori di intercettazione, possiamo calcolare le probabilità previste dei nostri dati. Prendiamo il primo X_test di nuovo i valori, ad esempio:

X_test[:1]

Questo restituisce la prima riga di X_test come matrice NumPy:

array([[-1.09830823, -0.93651823, -0.60794138, -1.13255059, -1.0827684 ,
        -1.12235877,  0.45891056, -1.07825898,  0.56284738, -0.17604099,
         0.23661678, -0.36013424]])

Seguendo l'equazione iniziale:

$$
p{X} = frac{e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}}{1 + e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldot + b_n * x_n)}}
$$

In Python abbiamo:

import math

lin_reg = logreg.intercept_[0] + 
((logreg.coef_[0][0]* X_test[:1][0][0])+ 
(logreg.coef_[0][1]* X_test[:1][0][1])+ 
(logreg.coef_[0][2]* X_test[:1][0][2])+ 
(logreg.coef_[0][3]* X_test[:1][0][3])+ 
(logreg.coef_[0][4]* X_test[:1][0][4])+ 
(logreg.coef_[0][5]* X_test[:1][0][5])+ 
(logreg.coef_[0][6]* X_test[:1][0][6])+ 
(logreg.coef_[0][7]* X_test[:1][0][7])+ 
(logreg.coef_[0][8]* X_test[:1][0][8])+ 
(logreg.coef_[0][9]* X_test[:1][0][9])+ 
(logreg.coef_[0][10]* X_test[:1][0][10])+ 
(logreg.coef_[0][11]* X_test[:1][0][11]))

px = math.exp(lin_reg)/(1 +(math.exp(lin_reg)))
px

Questo risulta in:

0.45273372469369133

Se guardiamo di nuovo al predict_proba risultato del primo X_test riga, abbiamo:

logreg.predict_proba(X_test[:1])


Ciò significa che l'equazione di regressione logistica originale ci fornisce la probabilità dell'input relativo alla classe 1, per scoprire quale probabilità è per la classe 0, possiamo semplicemente:

1 - px


Nota che entrambi px ed 1-px sono identici a predict_proba risultati. Ecco come viene calcolata la regressione logistica e perché regressione fa parte del suo nome. Ma che dire del termine logistica?

Il termine logistica viene da logit, che è una funzione che abbiamo già visto:

$$
ln sinistra( frac{p}{1-p} destra)
$$

L'abbiamo appena calcolato con px ed 1-px. Questo è il logit, chiamato anche log-quote poiché è uguale al logaritmo delle quote dove p è una probabilità.

Conclusione

In questa guida abbiamo studiato uno degli algoritmi di classificazione del machine learning più fondamentali, es regressione logistica.

Inizialmente, abbiamo implementato la regressione logistica come una scatola nera con la libreria di apprendimento automatico di Scikit-Learn, e in seguito l'abbiamo capito passo dopo passo per avere un chiaro perché e da dove provengono i termini regressione e logistica.

Abbiamo anche esplorato e studiato i dati, comprendendo che è una delle parti più cruciali di un'analisi della scienza dei dati.

Da qui, ti consiglierei di giocarci regressione logistica multiclasse, regressione logistica per più di due classi: puoi applicare lo stesso algoritmo di regressione logistica per altri set di dati che hanno più classi e interpretare i risultati.

Nota: È disponibile una buona raccolta di set di dati qui con cui giocare.

Ti consiglierei anche di studiare L1 e L2 regolarizzazioni, sono un modo per "penalizzare" i dati più elevati in modo che si avvicinino alla normalità, mantenendo la complessità del modello, in modo che l'algoritmo possa ottenere un risultato migliore. L'implementazione Scikit-Learn che abbiamo utilizzato ha già la regolarizzazione L2 per impostazione predefinita. Un'altra cosa da guardare è il diverso risolutori, come lbgs, che ottimizzano le prestazioni dell'algoritmo di regressione logistica.

È anche importante dare un'occhiata al statistiche approccio alla regressione logistica. Esso ha ipotesi sul comportamento dei dati, e su altre statistiche che devono valere per garantire risultati soddisfacenti, quali:

  • le osservazioni sono indipendenti;
  • non c'è multicollinearità tra variabili esplicative;
  • non ci sono valori anomali estremi;
  • esiste una relazione lineare tra variabili esplicative e logit della variabile di risposta;
  • la dimensione del campione è sufficientemente grande.

Notare quante di queste ipotesi erano già coperte nella nostra analisi e trattamento dei dati.

Spero che continuerai a esplorare ciò che la regressione logistica ha da offrire in tutti i suoi diversi approcci!

Timestamp:

Di più da Impilamento