Dokončni vodnik za logistično regresijo v Python PlatoBlockchain Data Intelligence. Navpično iskanje. Ai.

Dokončni vodnik po logistični regresiji v Pythonu

Predstavitev

Včasih se zamenjuje z linearne regresije novinci – zaradi delitve termina regresija - logistična regresija se daleč razlikuje od linearne regresije. Medtem ko linearna regresija napoveduje vrednosti kot so 2, 2.45, 6.77 oz zvezne vrednosti, zaradi česar je regresija algoritem, logistična regresija napove vrednosti, kot so 0 ali 1, 1 ali 2 ali 3, ki so diskretne vrednosti, zaradi česar je Razvrstitev algoritem. Ja, imenuje se regresija vendar je a Razvrstitev algoritem. Več o tem čez trenutek.

Če torej vaš problem podatkovne znanosti vključuje zvezne vrednosti, lahko uporabite a regresija algoritem (linearna regresija je eden izmed njih). V nasprotnem primeru, če vključuje razvrščanje vnosov, diskretnih vrednosti ali razredov, lahko uporabite Razvrstitev algoritem (logistična regresija je eden izmed njih).

V tem priročniku bomo izvajali logistično regresijo v Pythonu s knjižnico Scikit-Learn. Pojasnili bomo tudi, zakaj slov “regresija” je prisoten v imenu in kako deluje logistična regresija.

Da bi to naredili, bomo najprej naložili podatke, ki bodo klasificirani, vizualizirani in predhodno obdelani. Nato bomo zgradili logistični regresijski model, ki bo razumel te podatke. Ta model bo nato ovrednoten in uporabljen za napovedovanje vrednosti na podlagi novih vnosov.

Motivacija

Podjetje, v katerem delate, je sklenilo partnerstvo s turško kmetijsko kmetijo. To partnerstvo vključuje prodajo bučnih semen. Bučna semena so zelo pomembna za prehrano ljudi. Vsebujejo dober delež ogljikovih hidratov, maščob, beljakovin, kalcija, kalija, fosforja, magnezija, železa in cinka.

V ekipi za podatkovno znanost je vaša naloga ugotoviti razliko med vrstami bučnih semen samo z uporabo podatkov – oz. razvrščanje podatke glede na vrsto semena.

Turška kmetija dela z dvema vrstama bučnih semen, ena se imenuje Çerçevelik in drugo Ürgüp Sivrisi.

Za razvrščanje bučnih semen je vaša ekipa sledila dokumentu iz leta 2021 »Uporaba metod strojnega učenja pri klasifikaciji bučnih semen (Cucurbita pepo L.). Genetski viri in razvoj pridelka iz Koklua, Sarigila in Ozbeka – v tem dokumentu je metodologija za fotografiranje in ekstrahiranje meritev semen iz slik.

Po zaključku postopka, opisanega v članku, so bile pridobljene naslednje meritve:

  • Območje – število slikovnih pik znotraj meja bučnega semena
  • Obseg – obseg bučnega semena v pikslih
  • Dolžina glavne osi – tudi obseg v pikslih bučnega semena
  • Dolžina manjše osi – majhna osna razdalja bučnega semena
  • Ekscentričnost – ekscentričnost bučnega semena
  • Konveksno območje – število slikovnih pik najmanjše konveksne lupine na območju, ki ga tvori bučno seme
  • Obseg – razmerje med površino bučnega semena in slikovnimi pikami omejevalnega polja
  • Ekvivalenten premer – kvadratni koren pomnožitve ploščine bučnega semena s štiri deljeno s pi
  • Kompaktnost – delež ploščine bučnega semena glede na ploščino kroga z enakim obsegom
  • Očistost – konveksno in konveksno stanje bučnih semen
  • Zaokroženost – ovalnost bučnih semen brez upoštevanja popačenosti robov
  • Razmerje – razmerje stranic bučnih semen

To so meritve, s katerimi morate delati. Poleg meritev je tu še Class oznaka za dve vrsti bučnih semen.

Za začetek razvrščanja semen uvozimo podatke in si jih začnimo ogledovati.

Razumevanje nabora podatkov

Opomba: Nabor podatkov o bučah lahko prenesete tukaj.

Po prenosu nabora podatkov ga lahko naložimo v strukturo podatkovnega okvira z uporabo pandas knjižnica. Ker gre za datoteko excel, bomo uporabili read_excel() metoda:

import pandas as pd

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

Ko so podatki naloženi, lahko na hitro pokukamo v prvih 5 vrstic z uporabo head() metoda:

df.head() 

Rezultat tega je:

	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

Tukaj imamo vse meritve v ustreznih stolpcih, naših lastnosti, in tudi Class stolpec, naš ciljna, ki je zadnji v podatkovnem okviru. Z uporabo lahko vidimo, koliko meritev imamo shape atribut:

df.shape 

Izhod je:

(2500, 13)

Rezultat oblike nam pove, da je v naboru podatkov 2500 vnosov (ali vrstic) in 13 stolpcev. Ker vemo, da obstaja en ciljni stolpec – to pomeni, da imamo 12 stolpcev funkcij.

Zdaj lahko raziščemo ciljno spremenljivko, bučno seme Class. Ker bomo to spremenljivko predvideli, je zanimivo videti, koliko vzorcev vsakega bučnega semena imamo. Običajno je manjša kot razlika med številom primerkov v naših razredih, bolj uravnotežen je naš vzorec in boljše so naše napovedi.

Ta pregled lahko opravite tako, da vsak vzorec semena preštejete z value_counts() metoda:

df['Class'].value_counts() 

Zgornja koda prikazuje:

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

Vidimo lahko, da obstaja 1300 vzorcev Çerçevelik semena in 1200 vzorcev Ürgüp Sivrisi seme. Upoštevajte, da je razlika med njima 100 vzorcev, kar je zelo majhna razlika, kar je za nas dobro in kaže, da ni potrebe po uravnavanju števila vzorcev.

Oglejmo si tudi opisno statistiko naših funkcij z describe() kako dobro so podatki porazdeljeni. Dobljeno tabelo bomo tudi prenesli z T za lažjo primerjavo statistik:

df.describe().T

Končna tabela je:

					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

Z ogledom tabele, ko primerjamo v pomeni in standardni odklon (std) stolpcev je razvidno, da ima večina funkcij povprečje, ki je daleč od standardnega odklona. To pomeni, da vrednosti podatkov niso skoncentrirane okoli srednje vrednosti, temveč bolj razpršene okoli nje – z drugimi besedami, imajo visoka variabilnost.

Tudi ob pogledu na minimalna (min) in največja (max) stolpce, nekatere funkcije, kot npr Areain Convex_Area, imajo velike razlike med najnižjo in najvišjo vrednostjo. To pomeni, da imajo tisti stolpci zelo majhne podatke in tudi zelo velike vrednosti podatkov oz večja amplituda med vrednostmi podatkov.

Z visoko variabilnostjo, visoko amplitudo in funkcijami z različnimi merskimi enotami bi večini naših podatkov koristilo, če bi imeli enako lestvico za vse značilnosti ali pomanjšana. Skaliranje podatkov osredotoči podatke okoli povprečja in zmanjša njihovo varianco.

Ta scenarij verjetno tudi nakazuje, da v podatkih obstajajo odstopanja in ekstremne vrednosti. Zato je najbolje imeti nekaj izstopno zdravljenje poleg skaliranja podatkov.

Obstaja nekaj algoritmov strojnega učenja, na primer drevesni algoritmi, kot je npr Naključna klasifikacija gozdov, na katere ne vplivajo velika varianca podatkov, odstopanja in ekstremne vrednosti. Logistična regresija je drugačen, temelji na funkciji, ki kategorizira naše vrednosti, na parametre te funkcije pa lahko vplivajo vrednosti, ki so izven splošnega trenda podatkov in imajo visoko varianco.

Čez nekaj časa bomo izvedeli več o logistični regresiji, ko jo bomo začeli izvajati. Za zdaj lahko nadaljujemo z raziskovanjem naših podatkov.

Opomba: V računalništvu obstaja priljubljen pregovor: “Smeti noter, smeti ven” (GIGO), ki je zelo primeren za strojno učenje. To pomeni, da ko imamo nepotrebne podatke – meritve, ki ne opisujejo pojavov samih, podatke, ki niso bili razumljeni in dobro pripravljeni v skladu z vrsto algoritma ali modela, bodo verjetno ustvarili napačen rezultat, ki ne bo deloval na dan za dnem.
To je eden od razlogov, zakaj je raziskovanje, razumevanje podatkov in delovanje izbranega modela tako pomembno. S tem se lahko izognemo vlaganju smeti v naš model – namesto tega dodamo vrednost vanj in pridobimo vrednost ven.

Vizualizacija podatkov

Do zdaj smo imeli z opisno statistiko nekoliko abstrakten posnetek nekaterih lastnosti podatkov. Drug pomemben korak je vizualizacija in potrditev naše hipoteze o visoki varianci, amplitudi in odstopanjih. Če želite videti, ali se to, kar smo do sedaj opazili, kaže v podatkih, lahko narišemo nekaj grafov.

Zanimivo je tudi videti, kako se značilnosti nanašajo na dva razreda, ki bosta predvidena. Če želite to narediti, uvozimo seaborn pakirajte in uporabite pairplot graf, da si ogledate vsako porazdelitev funkcij in vsako ločitev razreda na funkcijo:

import seaborn as sns


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

Opomba: Zagon zgornje kode lahko traja nekaj časa, saj parna ploskev združuje raztresene ploskve vseh funkcij (lahko) in prikaže tudi porazdelitve funkcij.

Če pogledamo graf parov, lahko vidimo, da so v večini primerov točke na Çerçevelik razreda so jasno ločeni od točk Ürgüp Sivrisi razred. Bodisi so točke enega razreda na desni, medtem ko so druge na levi, ali pa so nekatere navzgor, druge pa navzdol. Če bi za ločevanje razredov uporabili nekakšno krivuljo ali črto, to kaže, da jih je lažje ločiti, če bi bili mešani, bi bila klasifikacija težja naloga.

v Eccentricity, Compactness in Aspect_Ration stolpcev, je zlahka opaziti tudi nekatere točke, ki so "izolirane" ali odstopajo od splošnega trenda podatkov – izstopajoče vrednosti.

Ko gledate diagonalo od zgornjega levega do spodnjega desnega dela grafikona, opazite, da so porazdelitve podatkov tudi barvno označene glede na naše razrede. Oblike porazdelitve in razdalja med obema krivuljama sta še en pokazatelj, kako ločljivi sta – čim dlje sta ena od druge, tem bolje. V večini primerov niso prekrivane, kar pomeni, da jih je lažje ločiti, kar prispeva tudi k naši nalogi.

Zaporedoma lahko narišemo tudi škatlaste ploskve vseh spremenljivk z sns.boxplot() metoda. Večinoma je koristno, da škatle usmerimo vodoravno, tako da so oblike škatlastih ploskev enake oblikam porazdelitve, to lahko naredimo z orient argument:


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

Dokončni vodnik za logistično regresijo v Python PlatoBlockchain Data Intelligence. Navpično iskanje. Ai.

V zgornji risbi opazite to Area in Convex_Area imajo tako visoko magnitudo v primerjavi z magnitudami drugih stolpcev, da stisnejo druge škatlaste ploskve. Da si lahko ogledamo vse škatlaste ploskve, lahko prilagodimo značilnosti in jih znova narišemo.

Preden to storimo, razumejmo, da če obstajajo vrednosti funkcij, ki so tesno povezane z drugimi vrednostmi, na primer – če obstajajo vrednosti, ki prav tako postanejo večje, ko se povečajo vrednosti drugih funkcij, imamo pozitivna korelacija; ali če obstajajo vrednosti, ki delujejo nasprotno, postanejo manjše, medtem ko se druge vrednosti zmanjšajo, z a negativna korelacija.

To je pomembno preučiti, ker močna razmerja v podatkih lahko pomenijo, da so nekateri stolpci izpeljani iz drugih stolpcev ali imajo podoben pomen kot naš model. Ko se to zgodi, so lahko rezultati modela precenjeni in želimo rezultate, ki so bližje realnosti. Če obstajajo močne korelacije, to tudi pomeni, da lahko zmanjšamo število funkcij in uporabimo manj stolpcev, zaradi česar je model bolj parsimonious.

Opomba: Privzeta korelacija, izračunana z corr() metoda je Pearsonov korelacijski koeficient. Ta koeficient je naveden, ko so podatki kvantitativni, normalno porazdeljeni, nimajo izstopajočih vrednosti in imajo linearno razmerje.

Druga možnost bi bila izračunati Spearmanov korelacijski koeficient. Spearmanov koeficient se uporablja, kadar so podatki ordinalni, nelinearni, imajo kakršno koli porazdelitev in odstopanja. Upoštevajte, da se naši podatki ne ujemajo povsem s Pearsonovimi ali Spearmanovimi predpostavkami (obstaja tudi več korelacijskih metod, kot je Kendallova). Ker so naši podatki kvantitativni in je za nas pomembno, da izmerimo njihovo linearno razmerje, bomo uporabili Pearsonov koeficient.

Oglejmo si korelacije med spremenljivkami in nato lahko preidemo na predhodno obdelavo podatkov. Izračunali bomo korelacije z corr() in jih vizualizirajte s Seabornovo heatmap(). Standardna velikost toplotnega zemljevida je običajno majhna, zato bomo uvozili matplotlib (splošni mehanizem/knjižnica za vizualizacijo, na katerem je zgrajen Seaborn) in spremenite velikost figsize:

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

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

Dokončni vodnik za logistično regresijo v Python PlatoBlockchain Data Intelligence. Navpično iskanje. Ai.

V tem toplotnem zemljevidu so vrednosti, ki so bližje 1 ali -1, vrednosti, na katere moramo biti pozorni. Prvi primer pomeni visoko pozitivno korelacijo, drugi pa visoko negativno korelacijo. Obe vrednosti, če nista nad 0.8 ali -0.8, bosta koristni za naš logistični regresijski model.

Kadar obstajajo visoke korelacije, kot je tista od 0.99 med Aspec_Ration in Compactness, to pomeni, da se lahko odločimo za uporabo le Aspec_Ration ali samo Compactness, namesto obeh (saj bi bila skoraj enaka napovedovalci drug drugega). Enako velja za Eccentricity in Compactness z -0.98 korelacija, za Area in Perimeter z 0.94 korelacija in nekateri drugi stolpci.

Predhodna obdelava podatkov

Ker smo podatke že nekaj časa raziskovali, se lahko lotimo njihove predobdelave. Za zdaj uporabimo vse funkcije za napoved razreda. Ko pridobimo prvi model, osnovno linijo, lahko nato odstranimo nekaj visoko koreliranih stolpcev in ga primerjamo z osnovno linijo.

Stolpci s funkcijami bodo naši X podatki in stolpec razreda, naš y ciljni podatki:

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

Pretvarjanje kategoričnih značilnosti v številske značilnosti

Glede našega Class stolpec – njegove vrednosti niso števila, to pomeni, da jih moramo tudi transformirati. Obstaja veliko načinov za to preobrazbo; tukaj bomo uporabili replace() način in zamenjati Çerçevelik do 0 in Ürgüp Sivrisi do 1.

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

Upoštevajte preslikavo! Ko berete rezultate iz svojega modela, jih boste želeli vsaj v mislih pretvoriti nazaj ali nazaj v ime razreda za druge uporabnike.

Razdelitev podatkov na vlake in testne nize

V našem raziskovanju smo ugotovili, da je bilo treba funkcije povečati. Če bi skaliranje izvedli zdaj ali na samodejni način, bi vrednosti skalirali s celoto X in y. V tem primeru bi se predstavili uhajanje podatkov, saj bi vrednosti nabora, ki bo kmalu nastal, vplivale na skaliranje. Uhajanje podatkov je pogost vzrok za neponovljive rezultate in navidezno visoko zmogljivost modelov ML.

Razmišljanje o skaliranju kaže, da se moramo najprej razdeliti X in y podatke naprej v nize za usposabljanje in testiranje ter nato v fit skalar na vadbeni garnituri, ter do preoblikovanje tako vlak in testni nizi (ne da bi preskusni niz kdaj vplival na skalirnik, ki to počne). Za to bomo uporabili Scikit-Learn's train_test_split() metoda:

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)

Nastavitev test_size=.25 zagotavlja, da uporabljamo 25 % podatkov za testiranje in 75 % za usposabljanje. To bi lahko izpustili, ko je to privzeta razdelitev, vendar je Pythonic način pisanja kode svetuje, da je "eksplicitno bolje kot implicitno".

Opomba: Stavek "eksplicitno je bolje kot implicitno" se nanaša na Zen Pythonaali PEP20. Predstavlja nekaj predlogov za pisanje kode Python. Če se ti predlogi upoštevajo, se koda upošteva Pythonic. Lahko izveste več o tem tukaj.

Po razdelitvi podatkov na nize za usposabljanje in teste je dobro pogledati, koliko zapisov je v vsakem nizu. To je mogoče storiti z shape atribut:

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

To prikaže:

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

Vidimo lahko, da imamo po razdelitvi 1875 zapisov za usposabljanje in 625 za testiranje.

Podatki o skaliranju

Ko imamo pripravljene nabore za usposabljanje in teste, lahko nadaljujemo s skaliranjem podatkov s Scikit-Learn StandardScaler objekt (ali drugi skalirniki, ki jih ponuja knjižnica). Da bi preprečili puščanje, je skaler nameščen na X_train podatki in vrednosti vlaka se nato uporabijo za skaliranje – ali transformacijo – tako podatkov vlaka kot testa:

from sklearn.preprocessing import StandardScaler

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

Ker boste običajno poklicali:

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

Prvi dve vrstici se lahko strneta z ednino fit_transform() call, ki se prilega skalerju na setu in ga preoblikuje v enem zamahu. Zdaj lahko reproduciramo škatlaste grafe, da vidimo razliko po skaliranju podatkov.

Glede na to, da skaliranje odstrani imena stolpcev, lahko pred izrisom organiziramo podatke o vlaku v podatkovni okvir z imeni stolpcev, da olajšamo vizualizacijo:

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

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

Dokončni vodnik za logistično regresijo v Python PlatoBlockchain Data Intelligence. Navpično iskanje. Ai.

Končno lahko vidimo vse naše škatle! Upoštevajte, da imajo vsi izstopajoče vrednosti in značilnosti, ki predstavljajo porazdelitev, ki je bolj oddaljena od normalne (ki imajo krivulje nagnjene v levo ali desno), kot npr. Solidity, Extent, Aspect_Rationin Compactedness, so enaki, ki so imeli višje korelacije.

Odstranjevanje izstopajočih vrednosti z metodo IQR

Vemo že, da lahko na logistično regresijo vplivajo odstopanja. Eden od načinov njihovega zdravljenja je uporaba metode, imenovane Interkvartilni razpon or I.Q.R.. Začetni korak metode IQR je razdelitev naših podatkov o vlaku na štiri dele, imenovane kvartili. Prvi kvartil, Q1, znaša 25 % podatkov, drugo, Q2, do 50 %, tretji, Q3, na 75 % in zadnji, Q4, na 100 %. Polja v škatli so definirana z metodo IQR in so njena vizualna predstavitev.

Če upoštevamo vodoravni okvir, navpična črta na levi označuje 25 % podatkov, navpična črta na sredini 50 % podatkov (ali mediano) in zadnja navpična črta na desni 75 % podatkov. . Bolj enakomerna kot sta oba kvadrata, definirana z navpičnimi črtami – ali bolj ko je srednja navpična črta na sredini – pomeni, da so naši podatki bližje normalni porazdelitvi ali manj poševni, kar je koristno za našo analizo.

Poleg škatle IQR so na obeh straneh tudi vodoravne črte. Te vrstice označujejo najmanjšo in največjo vrednost porazdelitve, ki jo definira

$$
Najmanj = Q1 – 1.5*IQR
$$

in

$$
Največ = Q3 + 1.5*IQR
$$

IQR je ravno razlika med Q3 in Q1 (ali Q3 – Q1) in je najbolj osrednja točka podatkov. Zato pri iskanju IQR na koncu filtriramo izstopajoče vrednosti v skrajnih podatkih ali v točkah minimuma in maksimuma. Škatlaste ploskve nam dajejo kratek vpogled v to, kakšen bo rezultat metode IQR.

Dokončni vodnik za logistično regresijo v Python PlatoBlockchain Data Intelligence. Navpično iskanje. Ai.

Lahko uporabimo Pande quantile() metoda za iskanje naših kvantilov in iqr Iz scipy.stats paket za pridobitev interkvartilnega obsega podatkov za vsak stolpec:

from scipy.stats import iqr

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

IQR = X_train.apply(iqr)

Zdaj imamo Q1, Q3 in IQR, lahko filtriramo vrednosti bližje mediani:


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]

Po filtriranju vrstic za usposabljanje lahko vidimo, koliko jih je še v podatkih shape:

X_train.shape

Rezultat tega je:

(1714, 12)

Vidimo lahko, da se je število vrstic po filtriranju povečalo s 1875 na 1714. To pomeni, da je 161 vrstic vsebovalo izstopajoče vrednosti ali 8.5 % podatkov.

Opomba: Priporočljivo je, da filtriranje izstopajočih vrednosti, odstranitev vrednosti NaN in druga dejanja, ki vključujejo filtriranje in čiščenje podatkov, ostanejo pod ali do 10 % podatkov. Poskusite razmisliti o drugih rešitvah, če vaše filtriranje ali odstranjevanje presega 10 % vaših podatkov.

Po odstranitvi izstopajočih vrednosti smo skoraj pripravljeni na vključitev podatkov v model. Za prilagoditev modela bomo uporabili podatke o vlaku. X_train se filtrira, kaj pa y_train?

y_train.shape

To ustvari:

(1875,)

To opazite y_train še vedno ima 1875 vrstic. Ujemati se moramo s številom y_train vrstic na število X_train vrstice in ne samo poljubno. Odstraniti moramo y-vrednosti primerkov bučnih semen, ki smo jih odstranili in so verjetno razpršeni po y_train set. Filtrirano X_train stil ima svoje prvotne indekse in indeks ima vrzeli, kjer smo odstranili odstopanja! Nato lahko uporabimo indeks X_train DataFrame za iskanje ustreznih vrednosti y_train:

y_train = y_train.iloc[X_train.index]

Ko to storimo, si lahko ogledamo y_train ponovno oblikuj:

y_train.shape

Kateri izhodi:

(1714,)

Oglejte si naš praktični, praktični vodnik za učenje Gita z najboljšimi praksami, standardi, sprejetimi v panogi, in priloženo goljufijo. Nehajte Googlati ukaze Git in pravzaprav naučiti it!

zdaj, y_train ima tudi 1714 vrstic in so enake kot X_train vrstice. Končno smo pripravljeni ustvariti naš logistični regresijski model!

Implementacija modela logistične regresije

Najtežji del je končan! Predhodna obdelava je običajno težja od razvoja modela, ko gre za uporabo knjižnic, kot je Scikit-Learn, ki je poenostavila uporabo modelov ML na le nekaj vrsticah.

Najprej uvozimo LogisticRegression in ga instancirajte, tako da ustvarite a LogisticRegression predmet:

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

Drugič, naše podatke o vlaku prilagodimo logreg model z fit() metodo in napovedati naše testne podatke z predict() metoda, ki shranjuje rezultate kot y_pred:



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

Z našim modelom smo že naredili napovedi! Poglejmo prve 3 vrstice v X_train da vidite, katere podatke smo uporabili:

X_train[:3]

Zgornja koda izpiše:

       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

In pri prvih 3 napovedih v y_pred za ogled rezultatov:

y_pred[:3] 

Rezultat tega je:

array([0, 0, 0])

Za te tri vrste so bile naše napovedi, da so bila semena prvega razreda, Çerçevelik.

z logistična regresija, namesto napovedi končnega razreda, kot npr 0, lahko tudi napovemo verjetnost, da se vrstica nanaša na 0 razred. To se dejansko zgodi, ko logistična regresija razvrsti podatke in predict() metoda nato prenese to napoved skozi prag, da vrne "trdi" razred. Če želite napovedati verjetnost, da pripadate razredu, predict_proba() se uporablja:

y_pred_proba = logreg.predict_proba(X_test)

Oglejmo si tudi prve 3 vrednosti napovedi verjetnosti y:

y_pred_proba[:3] 

Kateri izhodi:

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

Zdaj imamo namesto treh ničel en stolpec za vsak razred. V stolpcu na levi, začenši z 0.54726628, so verjetnosti podatkov, ki se nanašajo na razred 0; in v desnem stolpcu, začenši z 0.45273372, so verjetnost, da se nanaša na razred 1.

Opomba: Ta razlika v klasifikaciji je znana tudi kot težko in mehko napoved. Trdo predvidevanje zaokroži napoved v razred, mehko predvidevanje pa izpiše verjetnost primerka, ki pripada razredu.

Obstaja več informacij o tem, kako je bil narejen predvideni rezultat. Pravzaprav ni bilo 0, vendar 55-odstotna možnost za razred 0, in 45-odstotno možnost za razred 1. To se kaže kot prvi trije X_test podatkovne točke, ki se nanašajo na razred 0, so resnično jasni le glede tretje podatkovne točke, s 86-odstotno verjetnostjo – in ne toliko za prvi dve podatkovni točki.

Pri sporočanju ugotovitev z uporabo metod ML – običajno je najbolje vrniti mehki razred in povezano verjetnost kot “zaupanje” te klasifikacije.

Več o tem, kako se to izračuna, bomo govorili, ko se poglobimo v model. V tem času lahko nadaljujemo z naslednjim korakom.

Vrednotenje modela s poročili o klasifikaciji

Tretji korak je videti, kako se model obnese na testnih podatkih. Scikit-Learn lahko uvozimo classification_report() in mimo našega y_test in y_pred kot argumenti. Po tem lahko natisnemo njegov odgovor.

Klasifikacijsko poročilo vsebuje najbolj uporabljene klasifikacijske metrike, kot npr natančnost, odpoklic, f1-rezultatin natančnost.

  1. Precision: razumeti, katere pravilne vrednosti napovedi je naš klasifikator štel za pravilne. Natančnost bo te prave pozitivne vrednosti razdelila na vse, kar je bilo predvideno kot pozitivno:

$$
natančnost = frac{text{true positive}}{text{true positive} + text{false positive}}
$$

  1. Recall: razumeti, koliko resničnih pozitivnih rezultatov je prepoznal naš klasifikator. Odpoklic se izračuna tako, da se resnični pozitivni učinki delijo s čimer koli, kar bi bilo predvideno kot pozitivno:

$$
odpoklic = frac{besedilo{resnično pozitivno}}{besedilo{resnično pozitivno} + besedilo{lažno negativno}}
$$

  1. Ocena F1: je uravnotežena oz harmonično srednjo vrednost natančnosti in odpoklica. Najnižja vrednost je 0, najvišja pa 1. Kdaj f1-score je enako 1, to pomeni, da so bili vsi razredi pravilno predvideni – to rezultat je zelo težko dobiti z resničnimi podatki:

$$
besedilo{f1-rezultat} = 2* frac{besedilo{natančnost} * besedilo{priklic}}{besedilo{natančnost} + besedilo{priklic}}
$$

  1. natančnost: opisuje, koliko napovedi je imel naš klasifikator pravilnih. Najnižja vrednost natančnosti je 0, najvišja pa 1. To vrednost običajno pomnožimo s 100, da dobimo odstotek:

$$
natančnost = frac{besedilo{število pravilnih napovedi}}{besedilo{skupno število napovedi}}
$$

Opomba: Izjemno težko je doseči 100-odstotno natančnost pri kakršnih koli resničnih podatkih. Če se to zgodi, se zavedajte, da morda prihaja do uhajanja ali kaj narobe – ni soglasja o idealni vrednosti natančnosti in je tudi odvisna od konteksta. Vrednost 70 %, kar pomeni, da se bo klasifikator zmotil pri 30 % podatkov ali nad 70 %, običajno zadostuje za večino modelov.

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

Nato si lahko ogledamo rezultat klasifikacijskega poročila:

				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

To je naš rezultat. Upoštevajte to precision, recall, f1-scorein accuracy vse meritve so zelo visoke, nad 80 %, kar je idealno – vendar so na te rezultate verjetno vplivale visoke korelacije in se dolgoročno ne bodo ohranile.

Natančnost modela je 86 %, kar pomeni, da se v 14 % primerov zmoti pri klasifikaciji. Imamo te splošne informacije, vendar bi bilo zanimivo vedeti, ali se 14% napak zgodi pri razvrščanju razreda 0 ali razred 1. Da ugotovimo, kateri razredi so napačno identificirani kot kateri in v kateri pogostosti – lahko izračunamo in narišemo matrika zmede napovedi našega modela.

Vrednotenje modela z matriko zmede

Izračunajmo in nato narišimo matriko zmede. Ko to storimo, lahko razumemo vsak del tega. Za izris matrike zmede bomo uporabili Scikit-Learn confusion_matrix(), ki jih bomo uvozili iz metrics modul.

Matriko zmede je lažje vizualizirati z uporabo Seaborna heatmap(). Ko jo ustvarimo, bomo našo matriko zmede posredovali kot argument za toplotni zemljevid:

from sklearn.metrics import confusion_matrix

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

Dokončni vodnik za logistično regresijo v Python PlatoBlockchain Data Intelligence. Navpično iskanje. Ai.

  1. Matrica zmede: matrika prikazuje, koliko vzorcev je model dobil pravilnih ali napačnih za vsak razred. Pokličemo vrednosti, ki so bile pravilne in pravilno napovedane resnično pozitivni, in tisti, ki so bili napovedani kot pozitivni, vendar niso bili pozitivni, se imenujejo lažno pozitivno. Ista nomenklatura prave negative in lažno negativnih uporablja se za negativne vrednosti;

Če pogledamo graf matrike zmede, lahko vidimo, da imamo 287 vrednote, ki so bile 0 in napovedal kot 0 - ali resnično pozitivni za razred 0 (semena Çerçevelik). Tudi imamo 250 resnično pozitivno za razred 1 (semena Ürgüp Sivrisi). Pravi pozitivi se vedno nahajajo v matrični diagonali, ki gre od zgornjega levega do spodnjega desnega.

Prav tako imajo 29 vrednote, ki naj bi bile 0, ampak napovedali kot 1 (lažno pozitivno) in 59 vrednote, ki so bile 1 in napovedal kot 0 (lažno negativnih). S temi številkami lahko razumemo, da je največja napaka modela ta, da napove napačno negativne rezultate. Tako lahko seme Ürgüp Sivrisi večinoma razvrstimo kot seme Çerçevelik.

Tovrstno napako pojasnjuje tudi 81-odstotni priklic razreda 1. Opazite, da so metrike povezane. In razlika v odpoklicu izhaja iz tega, da imamo 100 vzorcev manj razreda Ürgüp Sivrisi. To je ena od posledic le nekaj vzorcev manj kot v drugem razredu. Za nadaljnje izboljšanje priklica lahko eksperimentirate z utežmi razreda ali uporabite več vzorcev Ürgüp Sivrisi.

Doslej smo izvedli večino tradicionalnih korakov podatkovne znanosti in uporabili model logistične regresije kot črno skrinjico.

Opomba: Če želite iti dlje, uporabite Navzkrižno preverjanje (CV) in iskanje po mreži iskati model, ki glede podatkov najbolj posplošuje, in najboljše parametre modela, ki so izbrani pred treningom oz. hiperparametrov.

V idealnem primeru bi lahko z življenjepisom in iskanjem po mreži implementirali povezan način izvajanja korakov predhodne obdelave podatkov, razdelitve podatkov, modeliranja in vrednotenja – kar je enostavno s Scikit-Learnom. cevovodov.

Zdaj je čas, da odpremo črno skrinjico in pogledamo vanjo, da se poglobimo v razumevanje delovanja logistične regresije.

Poglabljamo se v resnično delovanje logistične regresije

O regresija Beseda ni naključna, da bi razumeli, kaj počne logistična regresija, se lahko spomnimo, kaj njen sorodnik, linearna regresija, naredi s podatki. Formula linearne regresije je bila naslednja:

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

V kateri b0 je bil regresijski presek, b1 koeficient in x1 podatki.

Ta enačba je povzročila ravno črto, ki je bila uporabljena za napovedovanje novih vrednosti. Če se spomnimo uvoda, je zdaj razlika v tem, da ne bomo napovedovali novih vrednosti, ampak razred. Torej je treba to ravno črto spremeniti. Z logistično regresijo uvedemo nelinearnost in napoved se zdaj izvaja s pomočjo krivulje namesto črte:

Dokončni vodnik za logistično regresijo v Python PlatoBlockchain Data Intelligence. Navpično iskanje. Ai.

Upoštevajte, da medtem ko linija linearne regresije poteka naprej in je sestavljena iz neprekinjenih neskončnih vrednosti, lahko krivuljo logistične regresije razdelimo na sredino in ima ekstreme v vrednosti 0 in 1. Ta oblika črke »S« je razlog, da razvršča podatke – točke, ki so bližje ali padejo na najvišjo skrajnost, spadajo v razred 1, medtem ko točke, ki so v spodnjem kvadrantu ali bližje 0, spadajo v razred 0. Sredina "S" je sredina med 0 in 1, 0.5 - je prag za logistične regresijske točke.

Dokončni vodnik za logistično regresijo v Python PlatoBlockchain Data Intelligence. Navpično iskanje. Ai.

Vizualno razliko med logistično in linearno regresijo že razumemo, kaj pa formula? Formula za logistično regresijo je naslednja:

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

Lahko se zapiše tudi kot:

$$
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)}}
$$

Ali celo zapisano kot:

$$
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 + pike + b_n * x_n)}}
$$

V zgornji enačbi imamo verjetnost vnosa namesto njegove vrednosti. Ima 1 kot števec, tako da lahko povzroči vrednost med 0 in 1, in 1 plus vrednost v imenovalcu, tako da je njegova vrednost 1 in nekaj – to pomeni, da rezultat celotnega ulomka ne more biti večji od 1 .

In kakšna je vrednost, ki je v imenovalcu? je e, osnova naravnega logaritma (približno 2.718282), dvignjena na potenco linearne regresije:

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

Drug način pisanja bi bil:

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

V zadnji enačbi ln je naravni logaritem (osnova e) in p je verjetnost, zato je logaritem verjetnosti rezultata enak rezultatu linearne regresije.

Z drugimi besedami, z rezultatom linearne regresije in naravnim logaritmom lahko pridemo do verjetnosti, da se vnos nanaša ali ne na zasnovani razred.

Celoten postopek izpeljave logistične regresije je naslednji:

$$
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 + pike + 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)}
$$

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

To pomeni, da ima model logistične regresije tudi koeficiente in vrednost preseka. Ker uporablja linearno regresijo in ji doda nelinearno komponento z naravnim logaritmom (e).

Vrednosti koeficientov in preseka našega modela lahko vidimo na enak način kot pri linearni regresiji z uporabo coef_ in intercept_ lastnosti:

logreg.coef_

Ki prikazuje koeficiente vsake od 12 lastnosti:

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_

Posledica tega je:

array([0.08735782])

S koeficienti in presečnimi vrednostmi lahko izračunamo predvidene verjetnosti naših podatkov. Dobimo prvo X_test spet vrednosti, kot primer:

X_test[:1]

To vrne prvo vrstico X_test kot niz 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]])

Po začetni enačbi:

$$
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 + pike + b_n * x_n)}}
$$

V pythonu imamo:

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

Rezultat tega je:

0.45273372469369133

Če ponovno pogledamo na predict_proba rezultat prvega X_test line, imamo:

logreg.predict_proba(X_test[:1])


To pomeni, da izvirna logistična regresijska enačba poda verjetnost vnosa glede na razred 1, da ugotovite, katera verjetnost je za razred 0, lahko preprosto:

1 - px


Upoštevajte, da oboje px in 1-px so enaki predict_proba rezultate. Tako se izračuna logistična regresija in zakaj regresija je del njegovega imena. Kaj pa izraz logistično?

Izraz logistično prihaja iz logit, kar je funkcija, ki smo jo že videli:

$$
Levo (frac{p}{1-p} desno)
$$

Pravkar smo ga izračunali z px in 1-px. To je logit, imenovan tudi log-odds ker je enak logaritmu kvot, kjer je p je verjetnost.

zaključek

V tem priročniku smo preučevali enega najbolj temeljnih klasifikacijskih algoritmov strojnega učenja, tj logistična regresija.

Sprva smo logistično regresijo izvajali kot črno skrinjico s knjižnico strojnega učenja Scikit-Learn, kasneje pa smo jo razumeli korak za korakom, da smo imeli jasno, zakaj in od kod prihajata izraza regresija in logistika.

Prav tako smo raziskali in preučili podatke, pri čemer smo razumeli, da je to eden najpomembnejših delov analize podatkovne znanosti.

Od tu naprej bi vam svetoval, da se malo poigrate večrazredna logistična regresija, logistična regresija za več kot dva razreda – lahko uporabite isti algoritem logistične regresije za druge nize podatkov, ki imajo več razredov, in interpretirate rezultate.

Opomba: Na voljo je dobra zbirka naborov podatkov tukaj za igranje z vami.

Prav tako bi vam svetoval, da preučite L1 in L2 ureditve, so način za »kaznovanje« višjih podatkov, da bi se približali normalnim, ki ohranjajo kompleksnost modela, tako da lahko algoritem doseže boljši rezultat. Izvedba Scikit-Learn, ki smo jo uporabili, že ima privzeto ureditev L2. Druga stvar, na katero je treba gledati, je drugačnost reševalci, Kot je lbgs, ki optimizirajo delovanje algoritma logistične regresije.

Pomembno je tudi, da si ogledate Statistično pristop k logistični regresiji. Ima predpostavke o obnašanju podatkov in o drugih statističnih podatkih, ki morajo veljati za zagotavljanje zadovoljivih rezultatov, kot so:

  • opazovanja so neodvisna;
  • med pojasnjevalnimi spremenljivkami ni multikolinearnosti;
  • ni ekstremnih odstopanj;
  • obstaja linearna povezava med pojasnjevalnimi spremenljivkami in logit spremenljivke odziva;
  • je vzorec dovolj velik.

Opazite, koliko teh predpostavk je bilo že zajetih v naši analizi in obdelavi podatkov.

Upam, da še naprej raziskujete, kaj ponuja logistična regresija v vseh svojih različnih pristopih!

Časovni žig:

Več od Stackabuse