Introducere
Uneori confundat cu regresie liniara de către novici – datorită împărtășirii termenului regres - regresie logistică este mult diferit de regresie liniara. În timp ce regresia liniară prezice valori precum 2, 2.45, 6.77 sau valori continue, făcându-l un regres algoritm, regresie logistică prezice valori precum 0 sau 1, 1 sau 2 sau 3, care sunt valori discrete, făcându-l un clasificare algoritm. Da, se numește regres dar este o clasificare algoritm. Mai multe despre asta într-o clipă.
Prin urmare, dacă problema dvs. de știință a datelor implică valori continue, puteți aplica a regres algoritm (regresia liniară este una dintre ele). În caz contrar, dacă implică clasificarea intrărilor, a valorilor discrete sau a claselor, puteți aplica o clasificare algoritm (regresia logistică este una dintre ele).
În acest ghid, vom efectua regresia logistică în Python cu biblioteca Scikit-Learn. Vom explica, de asemenea, de ce cuvântul „regresie” este prezent în nume și cum funcționează regresia logistică.
Pentru a face acest lucru, vom încărca mai întâi date care vor fi clasificate, vizualizate și preprocesate. Apoi, vom construi un model de regresie logistică care va înțelege aceste date. Acest model va fi apoi evaluat și folosit pentru a prezice valori pe baza noilor intrări.
motivaţia
Compania pentru care lucrezi a făcut un parteneriat cu o fermă agricolă turcească. Acest parteneriat presupune vânzarea semințelor de dovleac. Semințele de dovleac sunt foarte importante pentru alimentația umană. Conțin o proporție bună de carbohidrați, grăsimi, proteine, calciu, potasiu, fosfor, magneziu, fier și zinc.
În echipa de știință a datelor, sarcina ta este să faci diferența dintre tipurile de semințe de dovleac doar folosind date - sau clasificator datele în funcție de tipul de sămânță.
Ferma turcească lucrează cu două tipuri de semințe de dovleac, unul se numește Çerçevelik si celalalt Ürgüp Sivrisi.
Pentru a clasifica semințele de dovleac, echipa ta a urmat lucrarea din 2021 „Utilizarea metodelor de învățare automată în clasificarea semințelor de dovleac (Cucurbita pepo L.). Resursele genetice și evoluția culturilor” de la Koklu, Sargil și Ozbek – în această lucrare, există o metodologie pentru fotografiarea și extragerea măsurătorilor semințelor din imagini.
După finalizarea procesului descris în lucrare, au fost extrase următoarele măsurători:
- Zonă – numărul de pixeli din limitele unei semințe de dovleac
- Perimetru – circumferința în pixeli a unei semințe de dovleac
- Lungimea axei majore – de asemenea circumferința în pixeli a unei semințe de dovleac
- Lungimea axei minore – distanța pe axa mică a unei semințe de dovleac
- Excentricitate – excentricitatea unei semințe de dovleac
- Zona convexa – numărul de pixeli ai celei mai mici coji convexe la regiunea formată de sămânța de dovleac
- Măsură – raportul dintre suprafața unei semințe de dovleac și pixelii casetei de delimitare
- Diametru echivalent – rădăcina pătrată a înmulțirii ariei semințelor de dovleac cu patru împărțită la pi
- soliditate – proporția suprafeței semințelor de dovleac față de aria cercului cu aceeași circumferință
- trăinicie – starea convexă și convexă a semințelor de dovleac
- Rotunjime – ovalitatea semințelor de dovleac fără a lua în considerare distorsiunile marginilor acestuia
- Raportul de aspect – raportul de aspect al semintelor de dovleac
Acestea sunt măsurătorile cu care trebuie să lucrați. Pe langa masuratori, mai exista si Clasă etichetă pentru cele două tipuri de semințe de dovleac.
Pentru a începe să clasificăm semințele, să importăm datele și să începem să le privim.
Înțelegerea setului de date
Notă: Puteți descărca setul de date pentru dovleac aici.
După descărcarea setului de date, îl putem încărca într-o structură de cadru de date folosind pandas
bibliotecă. Deoarece este un fișier Excel, vom folosi fișierul read_excel()
metodă:
import pandas as pd
fpath = 'dataset/pumpkin_seeds_dataset.xlsx'
df = pd.read_excel(fpath)
Odată ce datele sunt încărcate, putem arunca o privire rapidă la primele 5 rânduri folosind head()
metodă:
df.head()
Rezultă:
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
Aici, avem toate măsurătorile în coloanele lor respective, noastre caracteristici, și de asemenea Clasă coloana, nostru ţintă, care este ultimul din cadrul de date. Putem vedea câte măsurători avem folosind shape
atribut:
df.shape
Rezultatul este:
(2500, 13)
Rezultatul formei ne spune că există 2500 de intrări (sau rânduri) în setul de date și 13 coloane. Deoarece știm că există o coloană țintă - asta înseamnă că avem 12 coloane de caracteristici.
Acum putem explora variabila țintă, sămânța de dovleac Class
. Deoarece vom prezice acea variabilă, este interesant să vedem câte mostre din fiecare sămânță de dovleac avem. De obicei, cu cât diferența dintre numărul de instanțe din clasele noastre este mai mică, cu atât eșantionul nostru este mai echilibrat și predicțiile noastre sunt mai bune.
Această inspecție se poate face prin numărarea fiecărei probe de semințe cu value_counts()
metodă:
df['Class'].value_counts()
Codul de mai sus afișează:
Çerçevelik 1300
Ürgüp Sivrisi 1200
Name: Class, dtype: int64
Putem vedea că există 1300 de mostre ale Çerçevelik sămânță și 1200 de mostre de Ürgüp Sivrisi sămânță. Observați că diferența dintre ele este de 100 de mostre, o diferență foarte mică, ceea ce este bun pentru noi și indică că nu este nevoie să reechilibrați numărul de mostre.
Să ne uităm și la statisticile descriptive ale caracteristicilor noastre cu describe()
metoda pentru a vedea cât de bine sunt distribuite datele. Vom transpune și tabelul rezultat cu T
pentru a facilita compararea între statistici:
df.describe().T
Tabelul rezultat este:
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
Privind la tabel, când comparăm însemna și deviație standard (std
), se poate observa că majoritatea caracteristicilor au o medie care este departe de abaterea standard. Aceasta indică faptul că valorile datelor nu sunt concentrate în jurul valorii medii, ci mai împrăștiate în jurul acesteia - cu alte cuvinte, au variabilitate mare.
De asemenea, când se uită la minim (min
) Şi maxim (max
) coloane, unele caracteristici, cum ar fi Area
, și Convex_Area
, au diferențe mari între valorile minime și maxime. Aceasta înseamnă că acele coloane au date foarte mici și, de asemenea, valori de date foarte mari, sau amplitudine mai mare între valorile datelor.
Cu variabilitate mare, amplitudine mare și caracteristici cu unități de măsură diferite, majoritatea datelor noastre ar beneficia de aceeași scară pentru toate caracteristicile sau de a fi scalate. Scalarea datelor va centra datele în jurul mediei și va reduce varianța acesteia.
Acest scenariu indică probabil și faptul că există valori aberante și valori extreme în date. Deci, cel mai bine este să aveți câteva tratament anormal pe lângă scalarea datelor.
Există unii algoritmi de învățare automată, de exemplu, algoritmi bazați pe arbore, cum ar fi Clasificarea aleatorie a pădurilor, care nu sunt afectate de variația mare a datelor, valori aberante și valori extreme. Regresie logistică este diferit, se bazează pe o funcție care ne clasifică valorile, iar parametrii acelei funcții pot fi afectați de valori care sunt în afara trendului general al datelor și au varianță mare.
Vom înțelege mai multe despre regresia logistică într-un pic când vom ajunge să o implementăm. Deocamdată, putem continua să ne explorăm datele.
Notă: Există o vorbă populară în informatică: „Gunoi înăuntru, gunoi afară” (GIGO), care este potrivit pentru învățarea automată. Aceasta înseamnă că atunci când avem date de gunoi – măsurători care nu descriu fenomenele în sine, date care nu au fost înțelese și bine pregătite în funcție de tipul de algoritm sau model, vor genera probabil o ieșire incorectă care nu va funcționa. de la o zi la alta.
Acesta este unul dintre motivele pentru care explorarea, înțelegerea datelor și modul în care funcționează modelul ales sunt atât de importante. Făcând asta, putem evita să punem gunoi în modelul nostru – să-i punem valoare în schimb și să scoatem valoare.
Vizualizarea datelor
Până acum, cu statisticile descriptive, avem un instantaneu oarecum abstract al unor calități ale datelor. Un alt pas important este să îl vizualizăm și să confirmăm ipoteza noastră de varianță mare, amplitudine și valori aberante. Pentru a vedea dacă ceea ce am observat până acum arată în date, putem reprezenta niște grafice.
De asemenea, este interesant de văzut cum se leagă caracteristicile cu cele două clase care vor fi prezise. Pentru a face asta, să importăm fișierul seaborn
ambalați și utilizați pairplot
grafic pentru a analiza fiecare distribuție de caracteristici și fiecare separare de clasă per caracteristică:
import seaborn as sns
sns.pairplot(data=df, hue='Class')
Notă: Rularea codului de mai sus poate dura ceva timp, deoarece diagrama de perechi combină graficele de dispersie ale tuturor caracteristicilor (se poate) și afișează, de asemenea, distribuțiile caracteristicilor.
Privind la diagrama de perechi, putem vedea că, în majoritatea cazurilor, punctele Çerçevelik
clasa sunt clar separate de punctele Ürgüp Sivrisi
clasă. Fie punctele unei clase sunt la dreapta când celelalte sunt la stânga, fie unele sunt în sus în timp ce celelalte sunt în jos. Dacă ar fi să folosim un fel de curbă sau linie pentru a separa clasele, acest lucru arată că este mai ușor să le separăm, dacă ar fi amestecate, clasificarea ar fi o sarcină mai grea.
În Eccentricity
, Compactness
și Aspect_Ration
coloane, unele puncte care sunt „izolate” sau care se abat de la tendința generală a datelor – valori aberante – sunt de asemenea ușor de observat.
Când vă uitați la diagonala din stânga sus până în dreapta jos a diagramei, observați că distribuțiile de date sunt, de asemenea, codificate în culori în funcție de clasele noastre. Formele de distribuție și distanța dintre ambele curbe sunt alți indicatori ai cât de separabile sunt – cu cât sunt mai îndepărtate una de cealaltă, cu atât mai bine. În cele mai multe cazuri, ele nu sunt suprapuse, ceea ce înseamnă că sunt mai ușor de separat, contribuind și la sarcina noastră.
În secvență, putem, de asemenea, reprezenta graficul boxplot-urilor tuturor variabilelor cu sns.boxplot()
metodă. De cele mai multe ori, este util să orientați boxplot-urile pe orizontală, astfel încât formele boxploturilor sunt aceleași cu formele de distribuție, putem face asta cu orient
argument:
sns.boxplot(data=df, orient='h')
În complotul de mai sus, observați că Area
și Convex_Area
au o magnitudine atât de mare în comparație cu mărimile celorlalte coloane, încât strică celelalte boxplot. Pentru a putea privi toate boxploturile, putem scala caracteristicile și le putem reprezenta din nou.
Înainte de a face asta, să înțelegem doar că, dacă există valori ale caracteristicilor care sunt strâns legate de alte valori, de exemplu, dacă există valori care devin și mai mari atunci când alte valori ale caracteristicilor devin mai mari, având o pozitiv de corespondență; sau dacă există valori care fac opusul, se micșorează în timp ce alte valori se micșorează, având a corelație negativă.
Acest lucru este important de luat în considerare, deoarece existența unor relații puternice în date ar putea însemna că unele coloane au fost derivate din alte coloane sau au o semnificație similară cu modelul nostru. Când se întâmplă acest lucru, rezultatele modelului ar putea fi supraestimate și dorim rezultate mai apropiate de realitate. Dacă există corelații puternice, înseamnă, de asemenea, că putem reduce numărul de caracteristici și putem folosi mai puține coloane, făcând modelul mai mult strângător.
Notă: Corelația implicită calculată cu corr()
metoda este Coeficientul de corelație Pearson. Acest coeficient este indicat atunci când datele sunt cantitative, distribuite în mod normal, nu au valori aberante și au o relație liniară.
O altă alegere ar fi să calculezi Coeficientul de corelație al lui Spearman. Coeficientul lui Spearman este utilizat atunci când datele sunt ordinale, neliniare, au orice distribuție și au valori aberante. Observați că datele noastre nu se încadrează în totalitate în ipotezele lui Pearson sau Spearman (există și mai multe metode de corelare, cum ar fi cea a lui Kendall). Deoarece datele noastre sunt cantitative și este important pentru noi să măsurăm relația lor liniară, vom folosi coeficientul Pearson.
Să aruncăm o privire la corelațiile dintre variabile și apoi putem trece la preprocesarea datelor. Vom calcula corelațiile cu corr()
metoda și vizualizați-le cu Seaborn's heatmap()
. Dimensiunea standard a hărții termice tinde să fie mică, așa că vom importa matplotlib
(motor de vizualizare generală/biblioteca pe care Seaborn este construit) și modificați dimensiunea cu figsize
:
import matplotlib.pyplot as plt
plt.figure(figsize=(15, 10))
correlations = df.corr()
sns.heatmap(correlations, annot=True)
În această hartă termică, valorile mai apropiate de 1 sau -1 sunt valorile cărora trebuie să fim atenți. Primul caz, denotă o corelație pozitivă ridicată, iar al doilea, o corelație negativă ridicată. Ambele valori, dacă nu sunt peste 0.8 sau -0.8, vor fi benefice pentru modelul nostru de regresie logistică.
Când există corelații mari precum cea de 0.99
între Aspec_Ration
și Compactness
, aceasta înseamnă că putem alege să folosim numai Aspec_Ration
sau numai Compactness
, în loc de ambele (deoarece ar fi aproape egale predictori unul de altul). Același lucru este valabil și pentru Eccentricity
și Compactness
cu -0.98
corelație, pentru Area
și Perimeter
cu 0.94
corelație și alte câteva coloane.
Preprocesarea Datelor
Deoarece am explorat deja datele pentru o vreme, putem începe să le preprocesăm. Deocamdată, să folosim toate caracteristicile pentru predicția clasei. După obținerea unui prim model, o linie de bază, putem apoi elimina unele dintre coloanele foarte corelate și le putem compara cu linia de bază.
Coloanele de caracteristici vor fi ale noastre X
date și coloana de clasă, nostru y
date țintă:
y = df['Class']
X = df.drop(columns=['Class'], axis=1)
Transformarea caracteristicilor categoriale în caracteristici numerice
Referitor la noastre Class
coloană – valorile sale nu sunt numere, asta înseamnă că trebuie să le transformăm. Există multe moduri de a face această transformare; aici, vom folosi replace()
metoda și înlocuiți Çerçevelik
la 0
și Ürgüp Sivrisi
la 1
.
y = y.replace('Çerçevelik', 0).replace('Ürgüp Sivrisi', 1)
Tine cont de cartografiere! Când citiți rezultatele din modelul dvs., veți dori să le convertiți înapoi cel puțin în minte sau înapoi în numele clasei pentru alți utilizatori.
Împărțirea datelor în seturi de tren și de testare
În explorarea noastră, am observat că funcțiile au nevoie de scalare. Dacă am face scalarea acum, sau într-un mod automat, am scala valorile cu întregul X
și y
. În acest caz, ne-am prezenta scurgeri de date, deoarece valorile setului de testare care urmează să fie în curând ar fi afectat scalarea. Scurgerea de date este o cauză comună a rezultatelor ireproductibile și a performanțelor ridicate iluzorii ale modelelor ML.
Gândindu-ne la scalare, arată că mai întâi trebuie să ne despărțim X
și y
date mai departe în tren și seturi de testare și apoi la potrivi un scaler pe setul de antrenament și să transforma atât trenul, cât și seturile de testare (fără ca setul de testare să afecteze vreodată scalatorul care face acest lucru). Pentru aceasta, vom folosi Scikit-Learn's train_test_split()
metodă:
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)
reglaj test_size=.25
se asigură că folosim 25% din date pentru testare și 75% pentru instruire. Acest lucru ar putea fi omis, odată ce este împărțirea implicită, dar Pitonic Modul de scriere a codului sugerează că a fi „explicit este mai bine decât implicit”.
Notă: Propoziția „explicit este mai bine decât implicit” este o referire la Zenul lui Python, sau PEP20. Prezintă câteva sugestii pentru scrierea codului Python. Dacă aceste sugestii sunt urmate, codul este luat în considerare Pitonic. Puteți afla mai multe despre asta aici.
După împărțirea datelor în seturi de tren și de testare, este o practică bună să vă uitați la câte înregistrări sunt în fiecare set. Asta se poate face cu shape
atribut:
X_train.shape, X_test.shape, y_train.shape, y_test.shape
Aceasta afișează:
((1875, 12), (625, 12), (1875,), (625,))
Putem vedea că după despărțire avem 1875 de înregistrări pentru antrenament și 625 pentru testare.
Scalare date
Odată ce avem trenul și seturile de testare pregătite, putem trece la scalarea datelor cu Scikit-Learn StandardScaler
obiect (sau alte scaler furnizate de bibliotecă). Pentru a evita scurgerile, detartratorul este montat pe X_train
datele și valorile trenului sunt apoi utilizate pentru a scala – sau transforma – atât datele trenului, cât și cele de testare:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
Deoarece veți suna de obicei:
scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)
Primele două rânduri pot fi restrânse cu un singular fit_transform()
apel, care se potrivește cu scaler-ul de pe platou și îl transformă dintr-o singură mișcare. Acum putem reproduce graficele boxplot pentru a vedea diferența după scalarea datelor.
Având în vedere că scalarea elimină numele coloanelor, înainte de trasare, putem organiza din nou datele trenului într-un cadru de date cu nume de coloane pentru a facilita vizualizarea:
column_names = df.columns[:12]
X_train = pd.DataFrame(X_train, columns=column_names)
sns.boxplot(data=X_train, orient='h')
Putem vedea în sfârșit toate boxploturile noastre! Observați că toate au valori aberante și caracteristicile care prezintă o distribuție mai departe de normal (care au curbe înclinate fie spre stânga, fie spre dreapta), cum ar fi Solidity
, Extent
, Aspect_Ration
, și Compactedness
, sunt aceleași care au avut corelații mai mari.
Eliminarea valorii aberante cu metoda IQR
Știm deja că regresia logistică poate fi afectată de valori aberante. Una dintre modalitățile de a le trata este utilizarea unei metode numite Intervalul intercuartil or I.Q.R.. Pasul inițial al metodei IQR este împărțirea datelor noastre de tren în patru părți, numite quartile. Prima quartila, Q1, reprezintă 25% din date, al doilea, Q2, la 50%, al treilea, Q3, la 75%, iar ultimul, Q4, la 100%. Casetele din boxplot sunt definite prin metoda IQR și sunt o reprezentare vizuală a acesteia.
Luând în considerare un boxplot orizontal, linia verticală din stânga marchează 25% din date, linia verticală din mijloc, 50% din date (sau mediana), iar ultima linie verticală din dreapta, 75% din date . Cu cât ambele pătrate definite de liniile verticale sunt mai egale în dimensiune – sau cu cât linia verticală mediană este mai mare în mijloc – înseamnă că datele noastre sunt mai aproape de distribuția normală sau mai puțin denaturate, ceea ce este util pentru analiza noastră.
Pe lângă caseta IQR, există și linii orizontale pe ambele părți ale acesteia. Aceste linii marchează valorile de distribuție minime și maxime definite de
$$
Minim = Q1 – 1.5*IQR
$$
și
$$
Maxim = Q3 + 1.5*IQR
$$
IQR este exact diferența dintre Q3 și Q1 (sau Q3 – Q1) și este cel mai central punct al datelor. De aceea, atunci când găsim IQR, ajungem să filtram valorile aberante din extremitățile datelor, sau în punctele minime și maxime. Box plots ne oferă o perspectivă a ceea ce va fi rezultatul metodei IQR.
Putem folosi Pandas quantile()
metoda de a găsi cuantilele noastre și iqr
de la scipy.stats
pachet pentru a obține intervalul de date interquartile pentru fiecare coloană:
from scipy.stats import iqr
Q1 = X_train.quantile(q=.25)
Q3 = X_train.quantile(q=.75)
IQR = X_train.apply(iqr)
Acum avem Q1, Q3 și IQR, putem filtra valorile mai aproape de mediană:
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]
După ce ne-am filtrat rândurile de antrenament, putem vedea câte dintre ele sunt încă în date cu shape
:
X_train.shape
Rezultă:
(1714, 12)
Putem vedea că numărul de rânduri a trecut de la 1875 la 1714 după filtrare. Aceasta înseamnă că 161 de rânduri au conținut valori aberante sau 8.5% din date.
Notă: Se recomandă ca filtrarea valorilor aberante, eliminarea valorilor NaN și alte acțiuni care implică filtrarea și curățarea datelor să rămână sub sau până la 10% din date. Încercați să vă gândiți la alte soluții dacă filtrarea sau eliminarea dvs. depășește 10% din datele dvs.
După eliminarea valorii aberante, suntem aproape gata să includem date în model. Pentru montarea modelului, vom folosi datele trenului. X_train
este filtrat, dar ce zici y_train
?
y_train.shape
Acest rezultat:
(1875,)
Observa asta y_train
mai are 1875 de rânduri. Trebuie să potrivim numărul de y_train
rânduri la numărul de X_train
rânduri și nu doar în mod arbitrar. Trebuie să eliminăm valorile y ale cazurilor de semințe de dovleac pe care le-am îndepărtat, care sunt probabil împrăștiate prin y_train
a stabilit. Cel filtrat X_train
stil are indicii sai originali, iar indicele are lacune de unde am eliminat valorile aberante! Apoi putem folosi indexul lui X_train
DataFrame pentru a căuta valorile corespunzătoare în y_train
:
y_train = y_train.iloc[X_train.index]
După ce facem asta, ne putem uita la y_train
forma din nou:
y_train.shape
Care iese:
(1714,)
Consultați ghidul nostru practic și practic pentru a învăța Git, cu cele mai bune practici, standarde acceptate de industrie și fisa de cheat incluse. Opriți căutarea pe Google a comenzilor Git și de fapt învăţa aceasta!
Acum, y_train
are, de asemenea, 1714 rânduri și sunt la fel ca și X_train
rânduri. Suntem în sfârșit gata să creăm modelul nostru de regresie logistică!
Implementarea modelului de regresie logistică
Partea grea este gata! Preprocesarea este de obicei mai dificilă decât dezvoltarea modelului, atunci când vine vorba de utilizarea bibliotecilor precum Scikit-Learn, care au simplificat aplicarea modelelor ML la doar câteva linii.
În primul rând, importăm LogisticRegression
clasă și instanțiază-o, creând un LogisticRegression
obiect:
from sklearn.linear_model import LogisticRegression
logreg = LogisticRegression(random_state=SEED)
În al doilea rând, ne potrivim datele trenului la logreg
model cu fit()
metoda și preziceți datele noastre de testare cu predict()
metoda, stocând rezultatele ca y_pred
:
logreg.fit(X_train.values, y_train)
y_pred = logreg.predict(X_test)
Am făcut deja predicții cu modelul nostru! Să ne uităm la primele 3 rânduri din X_train
pentru a vedea ce date am folosit:
X_train[:3]
Codul de mai sus iese:
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
Și la primele 3 predicții în y_pred
pentru a vedea rezultatele:
y_pred[:3]
Rezultă:
array([0, 0, 0])
Pentru acele trei rânduri, predicțiile noastre au fost că erau semințe de prima clasă, Çerçevelik
.
cu regresie logistică, în loc să prezică clasa finală, cum ar fi 0
, putem de asemenea prezice probabilitatea pe care o are rândul să aparțină la 0
clasă. Acesta este ceea ce se întâmplă de fapt atunci când regresia logistică clasifică datele și predict()
metoda trece apoi această predicție printr-un prag pentru a returna o clasă „hard”. Pentru a prezice probabilitatea de a face parte dintr-o clasă, predict_proba()
este folosit:
y_pred_proba = logreg.predict_proba(X_test)
Să aruncăm o privire și asupra primelor 3 valori ale predicțiilor probabilităților y:
y_pred_proba[:3]
Care iese:
# class 0 class 1
array([[0.54726628, 0.45273372],
[0.56324527, 0.43675473],
[0.86233349, 0.13766651]])
Acum, în loc de trei zerouri, avem o coloană pentru fiecare clasă. În coloana din stânga, începând cu 0.54726628
, sunt probabilitățile datelor care aparțin clasei 0
; iar în coloana din dreapta, începând cu 0.45273372
, sunt probabilitatea ca aceasta să aparțină clasei 1
.
Notă: Această diferență de clasificare este cunoscută și ca greu și moale predictie. Predicțiile hard încadrează predicția într-o clasă, în timp ce predicțiile soft generează probabilitate a instanţei aparţinând unei clase.
Există mai multe informații despre modul în care a fost realizată rezultatul estimat. Nu a fost de fapt 0
, dar o șansă de 55% la curs 0
, și o șansă de 45% la curs 1
. Aceasta arată cum primele trei X_test
puncte de date, referitoare la clasă 0
, sunt chiar clare doar în ceea ce privește al treilea punct de date, cu o probabilitate de 86% – și nu atât pentru primele două puncte de date.
Când comunicați constatări folosind metode ML – de obicei este mai bine să returnați o clasă soft și probabilitatea asociată ca "încredere" din acea clasificare.
Vom vorbi mai multe despre modul în care se calculează atunci când vom aprofunda modelul. În acest moment, putem trece la pasul următor.
Evaluarea modelului cu rapoarte de clasificare
Al treilea pas este să vedem cum funcționează modelul pe datele de testare. Putem importa Scikit-Learn classification_report()
și treci de la noi y_test
și y_pred
ca argumente. După aceea, putem tipări răspunsul acestuia.
Raportul de clasificare conține cele mai utilizate valori de clasificare, cum ar fi precizie, rechemare, scor f1, și precizie.
- Precizie: pentru a înțelege ce valori corecte de predicție au fost considerate corecte de către clasificatorul nostru. Precizia va împărți acele valori pozitive adevărate la orice a fost prezis ca fiind pozitiv:
$$
precizie = frac{text{adevărat pozitiv}}{text{adevărat pozitiv} + text{fals pozitiv}}
$$
- Rechemare: pentru a înțelege câte dintre adevăratele pozitive au fost identificate de clasificatorul nostru. Rechemarea se calculează împărțind adevăratele pozitive la orice ar fi trebuit prezis ca pozitiv:
$$
recall = frac{text{adevărat pozitiv}}{text{adevărat pozitiv} + text{fals negativ}}
$$
- Scor F1: este echilibrat sau medie armonică de precizie și reamintire. Cea mai mică valoare este 0, iar cea mai mare este 1. Când
f1-score
este egal cu 1, înseamnă că toate clasele au fost prezise corect – acesta este un scor foarte greu de obținut cu date reale:
$$
text{f1-score} = 2* frac{text{precizie} * text{recall}}{text{precizie} + text{recall}}
$$
- Acuratete: descrie câte predicții a corectat clasificatorul nostru. Cea mai mică valoare de precizie este 0, iar cea mai mare este 1. Această valoare este de obicei înmulțită cu 100 pentru a obține un procent:
$$
acuratețe = frac{text{numărul de predicții corecte}}{text{numărul total de predicții}}
$$
Notă: Este extrem de greu să obțineți acuratețe de 100% pentru orice date reale, dacă se întâmplă acest lucru, fiți conștienți de faptul că s-ar putea întâmpla o scurgere sau ceva greșit - nu există un consens cu privire la o valoare ideală a preciziei și este, de asemenea, dependentă de context. O valoare de 70%, ceea ce înseamnă că clasificatorul va face greșeli în 30% din date sau peste 70% tinde să fie suficientă pentru majoritatea modelelor.
from sklearn.metrics import classification_report
cr = classification_report(y_test, y_pred)
print(cr)
Apoi putem analiza rezultatul raportului de clasificare:
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
Acesta este rezultatul nostru. Observa asta precision
, recall
, f1-score
, și accuracy
toate valorile sunt foarte mari, peste 80%, ceea ce este ideal – dar acele rezultate au fost probabil influențate de corelații mari și nu se vor menține pe termen lung.
Precizia modelului este de 86%, ceea ce înseamnă că greșit în 14% din cazuri. Avem acele informații generale, dar ar fi interesant de știut dacă cele 14% greșeli se întâmplă în ceea ce privește clasificarea clasei 0
sau clasa 1
. Pentru a identifica clasele care sunt identificate greșit și în ce frecvență – putem calcula și reprezenta un grafic a matrice de confuzie a predicțiilor modelului nostru.
Evaluarea modelului cu o matrice de confuzie
Să calculăm și apoi să trasăm matricea de confuzie. După ce facem asta, putem înțelege fiecare parte a acesteia. Pentru a reprezenta matricea de confuzie, vom folosi Scikit-Learn confusion_matrix()
, pe care îl vom importa din metrics
modul.
Matricea de confuzie este mai ușor de vizualizat folosind un Seaborn heatmap()
. Deci, după generarea acesteia, vom trece matricea noastră de confuzie ca argument pentru harta termică:
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='d')
- Matricea confuziei: matricea arată câte mostre modelul a fost corect sau greșit pentru fiecare clasă. Se numesc valorile care au fost corecte și prezise corect adevărate pozitive, iar cele care au fost prezise ca pozitive, dar nu au fost pozitive sunt numite fals pozitive. Aceeași nomenclatură a negative adevărate și false negative este folosit pentru valori negative;
Privind graficul matricei de confuzie, putem vedea că avem 287
valori care au fost 0
si prezis ca 0
- sau adevărate pozitive pentru clasă 0
(semințele de Çerçevelik). De asemenea avem 250
adevărate pozitive pentru clasă 1
(Semințe de Ürgüp Sivrisi). Adevărații pozitive sunt întotdeauna localizate în diagonala matricei care merge din stânga sus la dreapta jos.
De asemenea avem 29
valori care trebuiau să fie 0
, dar prezis ca 1
(fals pozitive) Şi 59
valori care au fost 1
si prezis ca 0
(false negative). Cu aceste numere, putem înțelege că eroarea pe care modelul o face cel mai mult este că prezice negative false. Deci, în mare parte poate ajunge să clasifice o sămânță de Ürgüp Sivrisi drept sămânță de Çerçevelik.
Acest tip de eroare se explică și prin rechemarea de 81% a clasei 1
. Observați că valorile sunt conectate. Iar diferența în rechemare vine din faptul că avem cu 100 de mostre mai puține din clasa Ürgüp Sivrisi. Aceasta este una dintre implicațiile de a avea doar câteva mostre mai puțin decât cealaltă clasă. Pentru a îmbunătăți și mai mult reamintirea, puteți fie să experimentați cu greutăți de clasă, fie să utilizați mai multe mostre Ürgüp Sivrisi.
Până acum, am executat majoritatea pașilor tradiționali ai științei datelor și am folosit modelul de regresie logistică ca o cutie neagră.
Notă: Dacă vrei să mergi mai departe, folosește Validare încrucișată (CV) și căutare în grilă să caute, respectiv, modelul care generalizează cel mai mult în ceea ce privește datele și cei mai buni parametri de model care sunt aleși înainte de antrenament, sau hiperparametri.
În mod ideal, cu CV și Grid Search, ați putea implementa, de asemenea, o modalitate concatenată de a face pașii de preprocesare a datelor, împărțirea datelor, modelare și evaluare - ceea ce este simplificat cu Scikit-Learn conducte.
Acum este momentul să deschidem cutia neagră și să privim în interiorul ei, pentru a înțelege mai profund cum funcționează regresia logistică.
Aprofundarea cum funcționează cu adevărat regresia logistică
regres Cuvântul nu este acolo din întâmplare, pentru a înțelege ce face regresia logistică, ne putem aminti ce face regresia liniară fratelui său cu datele. Formula de regresie liniară a fost următoarea:
$$
y = b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n
$$
În care b0 a fost interceptarea regresiei, b1 coeficientul și x1 datele.
Acea ecuație a rezultat într-o linie dreaptă care a fost folosită pentru a prezice noi valori. Reamintind introducerea, diferența acum este că nu vom prezice valori noi, ci o clasă. Deci linia dreaptă trebuie să se schimbe. Cu regresia logistică, introducem o neliniaritate și predicția se face acum folosind o curbă în loc de o linie:
Observați că, în timp ce linia de regresie liniară continuă și este formată din valori infinite continue, curba de regresie logistică poate fi împărțită la mijloc și are extreme în valori 0 și 1. Forma „S” este motivul pentru care clasifică datele – punctele care sunt mai aproape sau cad pe extremitatea cea mai înaltă aparțin clasei 1, în timp ce punctele care se află în cadranul inferior sau mai aproape de 0 aparțin clasei 0. „S” este mijlocul între 0 și 1, 0.5 – este pragul pentru punctele de regresie logistică.
Înțelegem deja diferența vizuală dintre regresia logistică și regresia liniară, dar cum rămâne cu formula? Formula de regresie logistică este următoarea:
$$
y = b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n
$$
Se mai poate scrie ca:
$$
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)}}
$$
Sau chiar să fie scris ca:
$$
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 + ldots + b_n * x_n)}}
$$
În ecuația de mai sus, avem probabilitatea de intrare, în loc de valoarea acesteia. Are 1 ca numărător, astfel încât poate rezulta o valoare între 0 și 1 și 1 plus o valoare la numitorul său, astfel încât valoarea sa este 1 și ceva - asta înseamnă că rezultatul întregii fracții nu poate fi mai mare de 1 .
Și care este valoarea care este în numitor? Este e, baza logaritmului natural (aproximativ 2.718282), ridicată la puterea regresiei liniare:
$$
e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}
$$
Un alt mod de a scrie ar fi:
$$
ln stânga( frac{p}{1-p} dreapta) = {(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}
$$
În acea ultimă ecuație, ln este logaritmul natural (baza e) și p este probabilitatea, deci logaritmul probabilității rezultatului este același cu rezultatul regresiei liniare.
Cu alte cuvinte, cu rezultatul regresiei liniare și logaritmul natural, putem ajunge la probabilitatea unei intrări aparținând sau nu unei clase proiectate.
Întregul proces de derivare a regresiei logistice este următorul:
$$
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 + ldots + 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 stânga( frac{p}{1-p} dreapta) = (b_0 + b_1 * x_1 + b_2 *x_2 + b_3 * x_3 + ldots + b_n * x_n)
$$
Aceasta înseamnă că modelul de regresie logistică are și coeficienți și o valoare de interceptare. Deoarece folosește o regresie liniară și îi adaugă o componentă neliniară cu logaritmul natural (e
).
Putem vedea valorile coeficienților și interceptarea modelului nostru, la fel ca și pentru regresia liniară, folosind coef_
și intercept_
proprietăţi:
logreg.coef_
Care afișează coeficienții fiecăreia dintre cele 12 caracteristici:
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_
Asta are ca rezultat:
array([0.08735782])
Cu coeficienții și valorile de interceptare, putem calcula probabilitățile prezise ale datelor noastre. Să luăm primul X_test
valorile din nou, de exemplu:
X_test[:1]
Aceasta returnează primul rând de X_test
ca o 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]])
Urmând ecuația inițială:
$$
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 + ldots + b_n * x_n)}}
$$
În python, avem:
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
Rezultă:
0.45273372469369133
Dacă ne uităm din nou la predict_proba
rezultatul primei X_test
linie, avem:
logreg.predict_proba(X_test[:1])
Aceasta înseamnă că ecuația originală de regresie logistică ne oferă probabilitatea intrării în ceea ce privește clasa 1
, pentru a afla ce probabilitate este pentru clasă 0
, putem pur și simplu:
1 - px
Observați că ambele px
și 1-px
sunt identice cu predict_proba
rezultate. Acesta este modul în care se calculează regresia logistică și de ce regres face parte din numele său. Dar cum rămâne cu termenul logistic?
Termenul logistic vine de la logit, care este o funcție pe care am văzut-o deja:
$$
în stânga (frac{p}{1-p} dreapta)
$$
Tocmai am calculat-o cu px
și 1-px
. Acesta este logit-ul, numit și log-cote deoarece este egal cu logaritmul cotelor unde p
este o probabilitate.
Concluzie
În acest ghid, am studiat unul dintre cei mai fundamentali algoritmi de clasificare a învățării automate, adică regresie logistică.
Inițial, am implementat regresia logistică ca o cutie neagră cu biblioteca de învățare automată a lui Scikit-Learn, iar ulterior am înțeles-o pas cu pas pentru a avea clar de ce și de unde provin termenii regresie și logistică.
De asemenea, am explorat și studiat datele, înțelegând că aceasta este una dintre cele mai importante părți ale unei analize a științei datelor.
De aici, te-aș sfătui să te joci regresie logistică multiclasă, regresie logistică pentru mai mult de două clase – puteți aplica același algoritm de regresie logistică pentru alte seturi de date care au mai multe clase și puteți interpreta rezultatele.
Notă: Este disponibilă o colecție bună de seturi de date aici cu care să te joci.
De asemenea, te-aș sfătui să studiezi L1 și L2 regularizări, sunt o modalitate de a „penaliza” datele superioare pentru ca acestea să devină mai aproape de normal, menținând complexitatea modelului, astfel încât algoritmul să poată ajunge la un rezultat mai bun. Implementarea Scikit-Learn pe care am folosit-o, are deja regularizare L2 în mod implicit. Un alt lucru de privit este diferit rezolvatori, Cum ar fi lbgs
, care optimizează performanța algoritmului de regresie logistică.
De asemenea, este important să aruncați o privire asupra statistic abordarea regresiei logistice. Are ipoteze despre comportamentul datelor și despre alte statistici care trebuie să fie valabile pentru a garanta rezultate satisfăcătoare, cum ar fi:
- observațiile sunt independente;
- nu există multicoliniaritate între variabilele explicative;
- nu există valori aberante extreme;
- există o relație liniară între variabilele explicative și logit-ul variabilei răspuns;
- dimensiunea eșantionului este suficient de mare.
Observați câte dintre aceste ipoteze au fost deja acoperite în analiza și tratarea datelor noastre.
Sper că veți continua să explorați ce are de oferit regresia logistică în toate abordările sale diferite!
- blockchain
- C ++
- cod
- coingenius
- știința datelor
- vizualizarea datelor
- Java
- matplotlib
- jeton non-fungibil
- NumPy
- Opensea
- panda
- PHP
- Plato
- platoul ai
- Informații despre date Platon
- Jocul lui Platon
- Platoblockchain
- PlatoData
- platogaming
- Poligon
- Piton
- Reacţiona
- scikit-learn
- născut în mare
- contract inteligent
- suntrap
- Stackabuse
- vyper
- Web3
- zephyrnet