Zephyrnet-logo

Lineaire regressie in Python met Scikit-Learn

Datum:

Als je langer had gestudeerd, zouden je algemene scores dan beter worden?

Een manier om deze vraag te beantwoorden is door gegevens te hebben over hoe lang je hebt gestudeerd en welke scores je hebt behaald. We kunnen dan proberen te zien of er een patroon in die gegevens zit, en als in dat patroon, als je de uren optelt, het uiteindelijk ook optelt bij het scorepercentage.

Stel dat u een dataset met uurscores hebt, die items bevat zoals 1.5 uur en 87.5% score. Het kan ook scores van 1.61 uur, 2.32 uur en 78%, 97% bevatten. Het soort gegevenstype dat een tussenliggende waarde kan hebben (of elk niveau van 'granulariteit') staat bekend als doorlopend data.

Een ander scenario is dat je een uurscore-dataset hebt die cijfers op basis van letters bevat in plaats van cijfers op basis van cijfers, zoals A, B of C. Cijfers zijn duidelijke waarden die kunnen worden geïsoleerd, aangezien je geen A kunt hebben. 23, A++++++++++++ (en tot oneindig) of A * e^12. Het soort gegevenstype dat niet kan worden gepartitioneerd of gedetailleerder kan worden gedefinieerd, staat bekend als: discreet data.

Op basis van de modaliteit (vorm) van je gegevens - om erachter te komen welke score je zou krijgen op basis van je studietijd - ga je presteren regressie or classificatie.

Regressie wordt uitgevoerd op continue gegevens, terwijl classificatie wordt uitgevoerd op discrete gegevens. Regressie kan van alles zijn, van het voorspellen van iemands leeftijd, het huis van een prijs of de waarde van een variabele. Classificatie omvat het voorspellen van wat klasse iets hoort (zoals of een tumor goedaardig of kwaadaardig is).

Opmerking: Het voorspellen van huizenprijzen en of er een kanker aanwezig is, is geen geringe taak, en beide omvatten doorgaans niet-lineaire relaties. Lineaire relaties zijn vrij eenvoudig te modelleren, zoals u zo zult zien.

Als je wilt leren door middel van praktijkgerichte, door voorbeelden geleide, praktische projecten, bekijk dan onze "Hands-on huizenprijsvoorspelling - machinaal leren in Python" en onze onderzoeksgraad "Borstkankerclassificatie met Deep Learning - Keras en Tensorflow"!

Voor zowel regressie als classificatie – we gebruiken gegevens om te voorspellen labels (paraplu-term voor de doelvariabelen). Labels kunnen van alles zijn, van "B" (klasse) voor classificatietaken tot 123 (getal) voor regressietaken. Omdat we ook de labels leveren – dit zijn leren onder toezicht algoritmen.

In deze beginnershandleiding - zullen we lineaire regressie uitvoeren in Python, gebruikmakend van de Scikit-Learn-bibliotheek. We doorlopen een end-to-end machine learning-pijplijn. We zullen eerst de gegevens laden waarvan we zullen leren en deze visualiseren, terwijl we tegelijkertijd presteren Verkennende gegevensanalyse. Vervolgens zullen we de gegevens voorverwerken en modellen bouwen die erop passen (als een handschoen). Dit model wordt vervolgens geëvalueerd en, indien gunstig, gebruikt om nieuwe waarden te voorspellen op basis van nieuwe invoer.

Verkennende gegevensanalyse

Opmerking: U kunt de uurscore-dataset downloaden hier.

Laten we beginnen met verkennende data-analyse. U wilt eerst uw gegevens leren kennen - dit omvat het laden ervan, het visualiseren van functies, het verkennen van hun relaties en het maken van hypothesen op basis van uw observaties. De dataset is een CSV-bestand (comma-separated values) dat de bestudeerde uren en de op basis van die uren behaalde scores bevat. We laden de gegevens in a DataFrame Panda's gebruiken:

import pandas as pd

Als je nieuw bent bij Panda's en DataFrames, lees onze "Gids voor Python met Panda's: DataFrame-zelfstudie met voorbeelden"!

Laten we het CSV-bestand lezen en verpakken in een DataFrame:


path_to_file = 'home/projects/datasets/student_scores.csv'
df = pd.read_csv(path_to_file)

Zodra de gegevens zijn geladen, laten we een snelle blik werpen op de eerste 5 waarden met behulp van de head() methode:

df.head()

Dit resulteert in:

   Hours  Scores
0    2.5      21
1    5.1      47
2    3.2      27
3    8.5      75
4    3.5      30

We kunnen de vorm van onze dataset ook controleren via de shape eigendom:

df.shape

Het kennen van de vorm van uw gegevens is over het algemeen vrij cruciaal om deze zowel te kunnen analyseren als er modellen omheen te kunnen bouwen:

(25, 2)

We hebben 25 rijen en 2 kolommen - dat zijn 25 items met een paar van een uur en partituur. Onze eerste vraag was of we een hogere score zouden halen als we langer hadden gestudeerd. In wezen vragen we om de relatie tussen uren en Partituren. Dus, wat is de relatie tussen deze variabelen? Een geweldige manier om relaties tussen variabelen te onderzoeken, is door middel van Scatterplots. We plotten de uren op de X-as en scores op de Y-as, en voor elk paar wordt een markering gepositioneerd op basis van hun waarden:

df.plot.scatter(x='Hours', y='Scores', title='Scatterplot of hours and scores percentages');

Als u nieuw bent bij Scatter Plots - lees onze "Matplotlib Scatter Plot - Zelfstudie en voorbeelden"!

Dit resulteert in:

Naarmate de uren toenemen, nemen ook de scores toe. Er is hier een vrij hoge positieve correlatie! Omdat de vorm van de lijn die de punten maken recht lijkt te zijn – we zeggen dat er een positieve lineaire correlatie tussen de variabelen Uren en Scores. Hoe gecorreleerd zijn ze? De corr() methode berekent en toont de correlaties tussen numerieke variabelen in a DataFrame:

print(df.corr())
           Hours    Scores
Hours   1.000000  0.976191
Scores  0.976191  1.000000

In deze tabel hebben Uren en Uren een 1.0 (100%) correlatie, net zoals Scores natuurlijk een 100% correlatie met Scores hebben. Elke variabele heeft een 1:1-toewijzing met zichzelf! De correlatie tussen scores en uren is echter: 0.97. Alles hierboven 0.8 wordt als een sterke positieve correlatie beschouwd.

Als u meer wilt lezen over de correlatie tussen lineaire variabelen in detail, evenals over verschillende correlatiecoëfficiënten, lees dan onze "Berekenen van Pearson-correlatiecoëfficiënt in Python met Numpy"!

Het hebben van een hoge lineaire correlatie betekent dat we over het algemeen de waarde van het ene kenmerk kunnen bepalen op basis van het andere. Zelfs zonder berekening kun je zien dat als iemand 5 uur studeert, hij ongeveer 50% als score krijgt. Omdat deze relatie erg sterk is, kunnen we een eenvoudig maar nauwkeurig lineair regressie-algoritme bouwen om de score te voorspellen op basis van de studietijd, op deze dataset.

Als we een lineair verband hebben tussen twee variabelen, kijken we naar een lijn. Als er een lineair verband is tussen drie, vier, vijf (of meer) variabelen, kijken we naar een snijpunt van vliegtuigen. In elk geval wordt dit soort kwaliteit in de algebra gedefinieerd als lineariteit.

Panda's worden ook geleverd met een geweldige hulpmethode voor statistische samenvattingen, en dat kunnen we describe() de dataset om een ​​idee te krijgen van de gemiddelde, maximum, minimum, etc. waarden van onze kolommen:

print(df.describe())
           Hours     Scores
count  25.000000  25.000000
mean    5.012000  51.480000
std     2.525094  25.286887
min     1.100000  17.000000
25%     2.700000  30.000000
50%     4.800000  47.000000
75%     7.400000  75.000000
max     9.200000  95.000000

Lineaire regressietheorie

Onze variabelen drukken een lineair verband uit. We kunnen intuïtief het scorepercentage schatten op basis van het aantal bestudeerde uren. Kunnen we echter een meer formele manier definiëren om dit te doen? We zouden een lijn tussen onze punten kunnen trekken en de waarde van "Score" kunnen lezen als we een verticale lijn van een gegeven waarde van "Uren" kunnen volgen:

Studie-uren en testscores plot

De vergelijking die een rechte lijn beschrijft is:
$$
y = a*x+b
$$
In deze vergelijking, y vertegenwoordigt het scorepercentage, x vertegenwoordigen de bestudeerde uren. b is waar de lijn begint op de Y-as, ook wel de Y-as genoemd onderscheppen en a bepaalt of de lijn meer naar het bovenste of onderste deel van de grafiek gaat (de hoek van de lijn), dus het wordt de helling van de lijn.

Door het aanpassen van de helling en onderscheppen van de lijn, kunnen we deze in elke richting verplaatsen. Dus - door de hellings- en snijwaarden te berekenen, kunnen we een lijn aanpassen aan onze gegevens!

Dat is het! Dat is het hart van lineaire regressie en een algoritme berekent eigenlijk alleen de waarden van de helling en het snijpunt. Het gebruikt de waarden van x en y die we al hebben en varieert de waarden van a en b. Door dat te doen, past het meerdere lijnen op de gegevenspunten en retourneert het de lijn die het dichtst bij alle gegevenspunten ligt, of de best passende lijn. Door die lineaire relatie te modelleren, wordt ons regressie-algoritme ook wel a . genoemd model. In dit proces, wanneer we proberen te bepalen, of voorspellen het percentage op basis van de uren, betekent dit dat onze y variabele hangt af van de waarden van onze x variabel.

Opmerking: In Statistieken, het is gebruikelijk om te bellen y de afhankelijk variabel, en x de onafhankelijk variabel. In Computer Science, y wordt meestal genoemd doel, label en x kenmerkenof attribuut. Je zult zien dat de namen onderling verwisselen, houd er rekening mee dat er meestal een variabele is die we willen voorspellen en een andere die wordt gebruikt om de waarde ervan te vinden. Het is ook een conventie om hoofdletters te gebruiken X in plaats van kleine letters, zowel in Statistics als CS.

Lineaire regressie met Python's Scikit-learn

Met de theorie onder onze riem - laten we een Linear Regression-algoritme implementeren met Python en de Scikit-Learn-bibliotheek! We beginnen met een eenvoudiger lineaire regressie en breiden dan uit naar Meerdere lineaire regressie met een nieuwe dataset.

Data Preprocessing

In de vorige sectie hebben we Panda's al geïmporteerd, ons bestand in a . geladen DataFrame en een grafiek uitgezet om te zien of er een indicatie was van een lineair verband. Nu kunnen we onze gegevens in twee arrays verdelen: een voor de afhankelijke functie en een voor de onafhankelijke of doelfunctie. Omdat we het scorepercentage afhankelijk van de bestudeerde uren willen voorspellen, is onze y zal het zijn "Score" column en onze X zal de “Uren” kolom.

Om het doel en de functies te scheiden, kunnen we de kolomwaarden van het dataframe toeschrijven aan onze y en X variabelen:

y = df['Scores'].values.reshape(-1, 1)
X = df['Hours'].values.reshape(-1, 1)

Opmerking: df['Column_Name'] geeft een panda terug Series. Sommige bibliotheken kunnen werken aan een Series net zoals ze zouden doen op een NumPy-array, maar niet alle bibliotheken hebben dit bewustzijn. In sommige gevallen wilt u de onderliggende NumPy-array extraheren die uw gegevens beschrijft. Dit doe je eenvoudig via de values gebied van de Series.

Het lineaire regressiemodel van Scikit-Learn verwacht een 2D-invoer, en we bieden echt een 1D-array aan als we alleen de waarden extraheren:

print(df['Hours'].values)
print(df['Hours'].values.shape)

Er wordt een 2D-invoer verwacht omdat de LinearRegression() class (later meer hierover) verwacht items die meer dan een enkele waarde kunnen bevatten (maar ook een enkele waarde kunnen zijn). In beide gevallen moet het een 2D-array zijn, waarbij elk element (uur) in feite een array met 1 element is:

print(X.shape)
print(X)

Bekijk onze praktische, praktische gids voor het leren van Git, met best-practices, door de industrie geaccepteerde normen en bijgevoegd spiekbriefje. Stop met Googlen op Git-commando's en eigenlijk leren het!

We konden onze al voeden X en y gegevens rechtstreeks naar ons lineaire regressiemodel, maar als we al onze gegevens tegelijk gebruiken, hoe kunnen we dan weten of onze resultaten goed zijn? Net als bij leren, gebruiken we een deel van de gegevens om trein ons model en een ander deel ervan, om proef het.

Als je meer wilt lezen over de vuistregels, het belang van het splitsen van sets, validatiesets en de train_test_split() helper-methode, lees onze gedetailleerde gids over: "Scikit-Learn's train_test_split() - Trainings-, test- en validatiesets"!

Dit wordt gemakkelijk bereikt door de helper train_test_split() methode, die onze . accepteert X en y arrays (werkt ook op DataFrames en splitst een single DataFrame in trainings- en testsets), en a test_size. De test_size is het percentage van de totale gegevens die we zullen gebruiken voor het testen:

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2)

De methode neemt willekeurig steekproeven met inachtneming van het percentage dat we hebben gedefinieerd, maar respecteert de Xy-paren, om te voorkomen dat de steekproef de relatie volledig zou verwisselen. Enkele veel voorkomende trein-testsplitsingen zijn: 80/20 en 70/30.

Aangezien het bemonsteringsproces inherent is: willekeurige, zullen we altijd verschillende resultaten hebben bij het uitvoeren van de methode. Om dezelfde resultaten te krijgen, of reproduceerbaar resultaten, kunnen we een constante definiëren met de naam SEED dat de waarde heeft van de zin van het leven (42):

SEED = 42

Opmerking: De seed kan elk geheel getal zijn en wordt gebruikt als de seed voor de willekeurige sampler. Het zaad is meestal willekeurig en levert verschillende resultaten op. Als u het echter handmatig instelt, geeft de sampler dezelfde resultaten. Het is een conventie om te gebruiken 42 als het zaad als verwijzing naar de populaire romanreeks "The Hitchhiker's Guide to the Galaxy".

Dat kunnen we dan doorgeven SEEDaan de random_state parameter van onze train_test_split methode:

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

Als u nu uw X_train array - je vindt de studie-uren, en y_train bevat de scorepercentages:

print(X_train)
print(y_train)

Een lineair regressiemodel trainen

We hebben onze trein- en testsets klaar staan. Scikit-Learn heeft een overvloed aan modeltypes die we gemakkelijk kunnen importeren en trainen, LinearRegression een van hen zijn:

from sklearn.linear_model import LinearRegression
regressor = LinearRegression()

Nu moeten we de regel aanpassen aan onze gegevens, dat doen we met behulp van de .fit() methode samen met onze X_train en y_train data:

regressor.fit(X_train, y_train)

Als er geen fouten worden gegenereerd, heeft de regressor de best passende regel gevonden! De lijn wordt bepaald door onze kenmerken en het snijpunt/helling. In feite kunnen we het snijpunt en de helling inspecteren door de af te drukken regressor.intecept_ en regressor.coef_ attributen, respectievelijk:

print(regressor.intercept_)
2.82689235

Voor het ophalen van de helling (die ook de coëfficiënt van x):

print(regressor.coef_)

Het resultaat zou moeten zijn:

[9.68207815]

Dit kan letterlijk van vroeger in onze formule worden ingeplugd:

$$
score = 9.68207815*uur+2.82689235
$$

Laten we snel kijken of dit overeenkomt met onze schatting:

h
o
u
r
s
=
5

s
c
o
r
e
=
9.68207815
*
h
o
u
r
s
+
2.82689235

s
c
o
r
e
=
51.2672831

Met 5 uur studeren kun je ongeveer 51% als score verwachten! Een andere manier om de interceptiewaarde te interpreteren is: als een student een uur meer studeert dan hij eerder voor een examen heeft gestudeerd, kan hij een toename van 9.68% gezien het scorepercentage dat ze eerder hadden behaald.

Met andere woorden, de hellingswaarde toont wat gebeurt er met de afhankelijke variabele? wanneer er een is stijging of daling) of een eenheid van de onafhankelijke variabele.

Voorspellingen doen

Om te voorkomen dat we zelf berekeningen uitvoeren, kunnen we onze eigen formule schrijven die de waarde berekent:

def calc(slope, intercept, hours):
    return slope*hours+intercept

score = calc(regressor.coef_, regressor.intercept_, 9.5)
print(score)

Echter – een veel handigere manier om voorspellen nieuwe waarden met behulp van ons model is om een ​​beroep te doen op de predict() functie:


score = regressor.predict([[9.5]])
print(score)

Ons resultaat is: 94.80663482of ongeveer 95%. Nu hebben we een schatting van het scorepercentage voor elk uur dat we kunnen bedenken. Maar kunnen we die schattingen vertrouwen? In het antwoord op die vraag staat de reden waarom we de data in de eerste plaats splitsen in trein en test. Nu kunnen we voorspellen met behulp van onze testgegevens en de voorspelde vergelijken met onze werkelijke resultaten - de grond waarheid resultaten.

Om voorspellingen te doen op de testgegevens, passeren we de X_test waarden naar de predict() methode. We kunnen de resultaten toewijzen aan de variabele y_pred:

y_pred = regressor.predict(X_test)

De y_pred variabele bevat nu alle voorspelde waarden voor de invoerwaarden in de X_test. We kunnen nu de werkelijke uitvoerwaarden vergelijken voor: X_test met de voorspelde waarden, door ze naast elkaar te rangschikken in een dataframestructuur:

df_preds = pd.DataFrame({'Actual': y_test.squeeze(), 'Predicted': y_pred.squeeze()})
print(df_preds

De uitvoer ziet er zo uit:

   Actual  Predicted
0      81  83.188141
1      30  27.032088
2      21  27.032088
3      76  69.633232
4      62  59.951153

Hoewel ons model niet erg nauwkeurig lijkt te zijn, liggen de voorspelde percentages dicht bij de werkelijke. Laten we het verschil tussen de werkelijke en voorspelde waarden kwantificeren om een ​​objectief beeld te krijgen van hoe het daadwerkelijk presteert.

Het model evalueren

Na het bekijken van de gegevens, het zien van een lineaire relatie, het trainen en testen van ons model, kunnen we begrijpen hoe goed het voorspelt door enkele metriek. Voor regressiemodellen, drie evaluatiestatistieken worden voornamelijk gebruikt:

  1. Gemiddelde absolute fout (MAE): Wanneer we de voorspelde waarden aftrekken van de werkelijke waarden, de fouten verkrijgen, de absolute waarden van die fouten optellen en hun gemiddelde krijgen. Deze metriek geeft een idee van de totale fout voor elke voorspelling van het model, hoe kleiner (dichter bij 0), hoe beter.

$$
mae = (frac{1}{n})sum_{i=1}^{n}links | Werkelijk – Voorspeld juist |
$$

Opmerking: Het kan ook zijn dat u de y en ŷ notatie in de vergelijkingen. De y verwijst naar de werkelijke waarden en de ŷ naar de voorspelde waarden.

  1. Gemiddelde kwadratische fout (MSE): Het is vergelijkbaar met de MAE-statistiek, maar het kwadraat van de absolute waarden van de fouten. Ook geldt, net als bij MAE, hoe kleiner of dichter bij 0, hoe beter. De MSE-waarde wordt gekwadrateerd om grote fouten nog groter te maken. Een ding om goed op te letten, is dat het meestal moeilijk te interpreteren is vanwege de grootte van de waarden en het feit dat ze zich niet in dezelfde schaal van de gegevens bevinden.

$$
mse = sum_{i=1}^{D}(Eigenlijk – Voorspeld)^2
$$

  1. Root Mean Squared Error (RMSE): probeert het interpretatieprobleem van de MSE op te lossen door de vierkantswortel van de uiteindelijke waarde te krijgen, zodat deze wordt teruggeschaald naar dezelfde eenheden van de gegevens. Het is gemakkelijker te interpreteren en goed wanneer we de werkelijke waarde van de gegevens met de fout moeten weergeven of weergeven. Het laat zien hoeveel de gegevens kunnen variëren, dus als we een RMSE van 4.35 hebben, kan ons model een fout maken omdat het 4.35 aan de werkelijke waarde toevoegde, of 4.35 nodig had om tot de werkelijke waarde te komen. Hoe dichter bij 0, hoe beter.

$$
rmse = sqrt{ sum_{i=1}^{D}(Eigenlijk – Voorspeld)^2}
$$

We kunnen elk van deze drie metrische gegevens gebruiken om: vergelijken modellen (als we er een moeten kiezen). We kunnen hetzelfde regressiemodel ook vergelijken met verschillende argumentwaarden of met verschillende gegevens en dan de evaluatiestatistieken in overweging nemen. Dit staat bekend als afstemming van hyperparameters – afstemmen van de hyperparameters die een leeralgoritme beïnvloeden en het observeren van de resultaten.

Bij het kiezen tussen modellen presteren de modellen met de kleinste fouten meestal beter. Als bij het monitoren van modellen de statistieken slechter werden, was een eerdere versie van het model beter, of was er een significante wijziging in de gegevens waardoor het model slechter presteerde dan het presteerde.

Gelukkig hoeven we de metrische berekeningen niet handmatig uit te voeren. Het Scikit-Learn-pakket wordt al geleverd met functies die kunnen worden gebruikt om de waarden van deze metrics voor ons te achterhalen. Laten we de waarden voor deze statistieken zoeken met behulp van onze testgegevens. Eerst importeren we de benodigde modules voor het berekenen van de MAE- en MSE-fouten. Respectievelijk de mean_absolute_error en mean_squared_error:

from sklearn.metrics import mean_absolute_error, mean_squared_error

Nu kunnen we de MAE en MSE berekenen door de y_test (werkelijk) en y_pred (voorspeld) naar de methoden. De RMSE kan worden berekend door de vierkantswortel van de MSE te nemen, daarvoor gebruiken we NumPy's sqrt() methode:

import numpy as np

Voor de metrische berekeningen:

mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)

We zullen de meetresultaten ook afdrukken met behulp van de f string en de 2-cijferige precisie na de komma met :.2f:

print(f'Mean absolute error: {mae:.2f}')
print(f'Mean squared error: {mse:.2f}')
print(f'Root mean squared error: {rmse:.2f}')

De resultaten van de metrieken zien er als volgt uit:

Mean absolute error: 3.92
Mean squared error: 18.94
Root mean squared error: 4.35

Al onze fouten zijn laag - en we missen de werkelijke waarde met maximaal 4.35 (lager of hoger), wat een vrij klein bereik is gezien de gegevens die we hebben.

Meerdere lineaire regressie

Tot nu toe hebben we een waarde met lineaire regressie voorspeld met slechts één variabele. Er is een ander scenario dat we kunnen overwegen, waar we kunnen voorspellen met behulp van veel variabelen in plaats van één, en dit is ook een veel gebruikelijker scenario in het echte leven, waar veel dingen een resultaat kunnen beïnvloeden.

Als we bijvoorbeeld het gasverbruik in Amerikaanse staten willen voorspellen, zou het beperkend zijn om daarvoor slechts één variabele te gebruiken, bijvoorbeeld gasbelastingen, aangezien meer dan alleen gasbelastingen van invloed zijn op het verbruik. Er zijn meer zaken bij het gasverbruik betrokken dan alleen gasbelastingen, zoals het inkomen per hoofd van de mensen in een bepaald gebied, de uitbreiding van verharde snelwegen, het aandeel van de bevolking dat een rijbewijs heeft en vele andere factoren. Sommige factoren hebben meer invloed op het verbruik dan andere - en hier helpen correlatiecoëfficiënten echt!

In een geval als dit, wanneer het zinvol is om meerdere variabelen te gebruiken, wordt lineaire regressie een Meerdere lineaire regressie.

Note: Een andere nomenclatuur voor de lineaire regressie met één onafhankelijke variabele is univariate lineaire regressie. En voor de meervoudige lineaire regressie, met veel onafhankelijke variabelen, is multivariate lineaire regressie.

Gewoonlijk gegevens uit de echte wereld, door veel meer variabelen te hebben met een groter waardenbereik, of meer veranderlijkheid, en ook complexe relaties tussen variabelen - zal meervoudige lineaire regressie inhouden in plaats van een eenvoudige lineaire regressie.

Dat wil zeggen, op een dagelijkse basis, als er lineariteit in uw gegevens is, zult u waarschijnlijk een meervoudige lineaire regressie op uw gegevens toepassen.

Verkennende gegevensanalyse

Laten we, om een ​​praktisch idee te krijgen van meervoudige lineaire regressie, blijven werken met ons voorbeeld van gasverbruik en een dataset gebruiken met gasverbruiksgegevens over 48 Amerikaanse staten.

Opmerking: U kunt de dataset gasverbruik downloaden op: Kaggle. U kunt meer te weten komen over de details van de dataset hier.

In navolging van wat we met de lineaire regressie hebben gedaan, willen we ook onze gegevens weten voordat we meervoudige lineaire regressie toepassen. Ten eerste kunnen we de gegevens importeren met panda's read_csv() methode:

path_to_file = 'home/projects/datasets/petrol_consumption.csv'
df = pd.read_csv(path_to_file)

We kunnen nu de eerste vijf rijen bekijken met df.head():

df.head()

Dit resulteert in:

	Petrol_tax	Average_income	Paved_Highways	Population_Driver_licence(%)  Petrol_Consumption
0	9.0			3571			1976			0.525						  541
1	9.0			4092			1250			0.572						  524
2	9.0			3865			1586			0.580						  561
3	7.5			4870			2351			0.529						  414
4	8.0			4399			431				0.544						  410

We kunnen zien hoeveel rijen en kolommen onze gegevens hebben met shape:

df.shape

Welke wordt weergegeven:

(48, 5)

In deze dataset hebben we 48 rijen en 5 kolommen. Bij het classificeren van de grootte van een dataset zijn er ook verschillen tussen statistiek en informatica.

In Statistieken kan een dataset met meer dan 30 of met meer dan 100 rijen (of observatie) wordt al als groot beschouwd, terwijl in de informatica een dataset meestal minimaal 1,000-3,000 rijen moet hebben om als "groot" te worden beschouwd. "Groot" is ook erg subjectief - sommigen beschouwen 3,000 als groot, terwijl sommigen 3,000,000 groot vinden.

Er is geen consensus over de omvang van onze dataset. Laten we het blijven verkennen en de beschrijvende statistieken van deze nieuwe gegevens bekijken. Deze keer zullen we de vergelijking van de statistieken vergemakkelijken door de waarden naar boven af ​​te ronden op twee decimalen met de round() methode, en het transponeren van de tabel met de T eigendom:

print(df.describe().round(2).T)

Onze tabel is nu kolombreed in plaats van rijbreed:

							 count mean	   std	   min	   25%	   50%	   75%	   max
Petrol_tax					 48.0  7.67	   0.95	   5.00	   7.00	   7.50	   8.12	   10.00
Average_income				 48.0  4241.83 573.62  3063.00 3739.00 4298.00 4578.75 5342.00
Paved_Highways				 48.0  5565.42 3491.51 431.00  3110.25 4735.50 7156.00 17782.00
Population_Driver_licence(%) 48.0  0.57	   0.06	   0.45	   0.53	   0.56	   0.60	   0.72
Petrol_Consumption			 48.0  576.77  111.89  344.00  509.50  568.50  632.75  968.00

Opmerking: De getransponeerde tabel is beter als we statistieken willen vergelijken, en de originele tabel is beter als we variabelen willen vergelijken.

Door naar de Min en max kolommen van de tabel beschrijven, zien we dat de minimumwaarde in onze gegevens is 0.45, en de maximale waarde is 17,782. Dit betekent dat ons gegevensbereik: 17,781.55 (17,782 – 0.45 = 17,781.55), zeer breed – wat impliceert dat onze gegevensvariabiliteit ook hoog is.

Ook door de waarden van de . te vergelijken gemiddelde en soa kolommen, zoals 7.67 en 0.95, 4241.83 en 573.62, enz., kunnen we zien dat de gemiddelden echt ver verwijderd zijn van de standaarddeviaties. Dat betekent dat onze gegevens verre van het gemiddelde zijn, gedecentraliseerde – wat ook bijdraagt ​​aan de variabiliteit.

We hebben al twee aanwijzingen dat onze gegevens verspreid zijn, wat niet in ons voordeel is, omdat het moeilijker wordt om een ​​lijn te hebben die past van 0.45 tot 17,782 – in statistische termen, om leg die variabiliteit uit.

Hoe dan ook, het is altijd belangrijk dat we de gegevens plotten. Gegevens met verschillende vormen (relaties) kunnen dezelfde beschrijvende statistiek hebben. Laten we dus doorgaan en onze punten in een grafiek bekijken.

Opmerking: Het probleem van het hebben van gegevens met verschillende vormen die dezelfde beschrijvende statistiek hebben, wordt gedefinieerd als: Kwartet van Anscombe. Je kunt er voorbeelden van zien hier.

Een ander voorbeeld van een coëfficiënt die hetzelfde is tussen verschillende relaties is Pearson Correlation (die controleert op: lineaire correlatie):

Deze gegevens hebben duidelijk een patroon! Hoewel het niet-lineair is en de gegevens geen lineaire correlatie hebben, is de Pearson-coëfficiënt 0 voor de meeste van hen. Het zou zijn 0 ook voor willekeurige ruis.

Nogmaals, als je meer wilt lezen over Pearson's Coëfficiënt, lees dan diepgaand: "Berekenen van Pearson-correlatiecoëfficiënt in Python met Numpy"!

In ons eenvoudige regressiescenario hebben we een spreidingsdiagram van de afhankelijke en onafhankelijke variabelen gebruikt om te zien of de vorm van de punten dicht bij een lijn lag. In ons huidige scenario hebben we vier onafhankelijke variabelen en één afhankelijke variabele. Om een ​​scatterplot met alle variabelen te maken, zou één dimensie per variabele nodig zijn, wat resulteert in een 5D-plot.

We zouden een 5D-plot kunnen maken met alle variabelen, wat een tijdje zou duren en een beetje moeilijk te lezen zou zijn - of we zouden één scatterplot kunnen plotten voor elk van onze onafhankelijke variabelen en afhankelijke variabele om te zien of er een lineair verband tussen is.

volgend Ockhams scheermes (ook bekend als het scheermes van Occam) en Python's PEP20 - “eenvoudig is beter dan complex” – we zullen een for-lus maken met een plot voor elke variabele.

Opmerking: Het scheermes van Ockham/Occam is een filosofisch en wetenschappelijk principe dat stelt dat de eenvoudigste theorie of verklaring de voorkeur verdient boven complexe theorieën of verklaringen.

Deze keer gebruiken we zeegeborene, een uitbreiding van Matplotlib die Pandas onder de motorkap gebruikt bij het plotten:

import seaborn as sns

variables = ['Petrol_tax', 'Average_income', 'Paved_Highways','Population_Driver_licence(%)']

for var in variables:
    plt.figure()



    sns.regplot(x=var, y='Petrol_Consumption', data=df).set(title=f'Regression plot of {var} and Petrol Consumption');

Merk in de bovenstaande code op dat we Seaborn importeren, een lijst maken met de variabelen die we willen plotten en die lijst doorlopen om elke onafhankelijke variabele met onze afhankelijke variabele te plotten.

De Seaborn-plot die we gebruiken is regplot, wat kort is van regressieplot. Het is een scatterplot die de verspreide gegevens al samen met de regressielijn plot. Als je liever naar een scatterplot kijkt zonder de regressielijn, gebruik dan sns.scatteplot gebruiken.

Dit zijn onze vier percelen:

Als we naar de regplots kijken, lijkt het erop dat de Petrol_tax en Average_income een zwak negatief lineair verband hebben met Petrol_Consumption. Het lijkt er ook op dat de Population_Driver_license(%) heeft een sterke positieve lineaire relatie met Petrol_Consumptionen dat de Paved_Highways variabele heeft geen relatie met Petrol_Consumption.

We kunnen ook de correlatie van de nieuwe variabelen berekenen, dit keer met behulp van Seaborn's heatmap() om ons te helpen de sterkste en zwakkere correlaties te ontdekken op basis van warmere (rode) en koelere (blauwe) tonen:

correlations = df.corr()

sns.heatmap(correlations, annot=True).set(title='Heatmap of Consumption Data - Pearson Correlations');

Het lijkt erop dat de heatmap onze eerdere analyse bevestigt! Petrol_tax en Average_income een zwak negatief lineair verband hebben van respectievelijk -0.45 en -0.24 Met Petrol_Consumption. Population_Driver_license(%) heeft een sterke positieve lineaire relatie van 0.7 Met Petrol_Consumption en Paved_Highways correlatie is van 0.019 – wat aangeeft dat er geen relatie is met Petrol_Consumption.

De correlatie impliceert geen oorzakelijk verband, maar we zouden een oorzakelijk verband kunnen vinden als we de verschijnselen met succes kunnen verklaren met ons regressiemodel.

Een ander belangrijk ding om op te merken in de regplots is dat er enkele punten zijn die heel ver verwijderd zijn van waar de meeste punten zich concentreren, we verwachtten al zoiets na het grote verschil tussen de gemiddelde en standaardkolommen - die punten kunnen gegevens zijn uitschieters en extreme waarden.

Opmerking: Uitbijters en extreme waarden hebben verschillende definities. Hoewel uitbijters niet de natuurlijke richting van de gegevens volgen en wegdrijven van de vorm die ze vormen, liggen extreme waarden in dezelfde richting als andere punten, maar zijn ze ofwel te hoog of te laag in die richting, ver weg naar de extremen in de grafiek.

Een lineair regressiemodel, uni of multivariate, houdt rekening met deze uitbijter en extreme waarden bij het bepalen van de helling en coëfficiënten van de regressielijn. Gezien wat ze al weten van de lineaire regressieformule:

$$
score = 9.68207815*uur+2.82689235
$$

Als we een uitschieter van 200 uur hebben, kan dat een typefout zijn geweest - het wordt nog steeds gebruikt om de eindscore te berekenen:

s
c
o
r
e
=
9.68207815
*
200
+
2.82689235

s
c
o
r
e
=
1939.24252235

Slechts één uitbijter kan onze hellingswaarde 200 keer groter maken. Hetzelfde geldt voor meervoudige lineaire regressie. De formule voor meervoudige lineaire regressie is in feite een uitbreiding van de formule voor lineaire regressie met meer hellingswaarden:

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

Het belangrijkste verschil tussen deze formule en onze vorige, is dat het beschrijft als: vliegtuig, in plaats van een lijn te beschrijven. we weten hebben bn *xn coëfficiënten in plaats van alleen een * x.

Opmerking: Er is een fout toegevoegd aan het einde van de meervoudige lineaire regressieformule, wat een fout is tussen voorspelde en werkelijke waarden - of restfout. Deze fout is meestal zo klein, dat deze in de meeste formules wordt weggelaten:

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

Op dezelfde manier, als we een extreme waarde van 17,000 hebben, zal het onze helling 17,000 groter maken:

$$
y = b_0 + 17,000 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n
$$

Met andere woorden, univariate en multivariate lineaire modellen zijn: gevoelig tot uitschieters en extreme gegevenswaarden.

Note: Het valt buiten het bestek van deze handleiding, maar u kunt verder gaan in de gegevensanalyse en gegevensvoorbereiding voor het model door naar boxplots te kijken, uitbijters en extreme waarden te behandelen.

Als je meer wilt weten over vioolplots en boxplots, lees dan onze Box Perceel en Vioolplot gidsen!

We hebben veel geleerd over lineaire modellen en verkennende data-analyse, nu is het tijd om de Average_income, Paved_Highways, Population_Driver_license(%) en Petrol_tax als onafhankelijke variabelen van ons model en kijk wat er gebeurt.

De gegevens voorbereiden

In navolging van wat er is gedaan met de eenvoudige lineaire regressie, kunnen we de gegevens na het laden en verkennen van de gegevens in kenmerken en doelen verdelen. Het belangrijkste verschil is dat onze functies nu 4 kolommen hebben in plaats van één.

We kunnen dubbele haakjes gebruiken [[ ]] om ze uit het dataframe te selecteren:

y = df['Petrol_Consumption']
X = df[['Average_income', 'Paved_Highways',
       'Population_Driver_licence(%)', 'Petrol_tax']]

Na het instellen van onze X en y sets kunnen we onze data onderverdelen in trein- en testsets. We zullen hetzelfde zaad en 20% van onze gegevens gebruiken voor training:

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

Het multivariate model trainen

Na het splitsen van de gegevens kunnen we ons meervoudige regressiemodel trainen. Merk op dat het nu niet nodig is om onze X gegevens, zodra deze al meer dan één dimensie heeft:

X.shape

Om ons model te trainen kunnen we dezelfde code uitvoeren als voorheen, en de . gebruiken fit() methode van de LinearRegression klasse:

regressor = LinearRegression()
regressor.fit(X_train, y_train)

Nadat we het model hebben aangepast en onze optimale oplossing hebben gevonden, kunnen we ook naar het snijpunt kijken:

regressor.intercept_
361.45087906668397

En bij de coëfficiënten van de kenmerken

regressor.coef_
[-5.65355145e-02, -4.38217137e-03,  1.34686930e+03, -3.69937459e+01]

Die vier waarden zijn de coëfficiënten voor elk van onze kenmerken in dezelfde volgorde als we ze in onze . hebben X gegevens. Om een ​​lijst met hun namen te zien, kunnen we het dataframe gebruiken columns attribuut:

feature_names = X.columns

Die code zal uitvoeren:

['Average_income', 'Paved_Highways', 'Population_Driver_licence(%)', 'Petrol_tax']

Aangezien het een beetje moeilijk is om zowel kenmerken als coëfficiënten op deze manier samen te zien, kunnen we ze beter organiseren in een tabelindeling.

Om dat te doen, kunnen we onze kolomnamen toewijzen aan a feature_names variabele, en onze coëfficiënten tot a model_coefficients variabel. Daarna kunnen we een dataframe maken met onze functies als een index en onze coëfficiënten als kolomwaarden, genaamd coefficients_df:

feature_names = X.columns
model_coefficients = regressor.coef_

coefficients_df = pd.DataFrame(data = model_coefficients,
                              index = feature_names,
                              columns = ['Coefficient value'])
print(coefficients_df)

De uiteindelijke DataFrame Zou er als volgt uitzien:

                              Coefficient value
Average_income                        -0.056536
Paved_Highways                        -0.004382
Population_Driver_licence(%)        1346.869298
Petrol_tax                           -36.993746

Als we in het lineaire regressiemodel 1 variabele en 1 coëfficiënt hadden, hebben we nu in het meervoudige lineaire regressiemodel 4 variabelen en 4 coëfficiënten. Wat kunnen die coëfficiënten betekenen? Volgens dezelfde interpretatie van de coëfficiënten van de lineaire regressie betekent dit dat voor een eenheidsstijging van het gemiddelde inkomen, er een daling is van 0.06 dollar in het gasverbruik.

Evenzo is er voor een eenheidstoename van verharde snelwegen een afname van 0.004 mijl in het gasverbruik; en voor een eenheidstoename van het aandeel van de bevolking met een rijbewijs, is er een toename van 1,346 miljard gallons gasverbruik.

En ten slotte, voor een verhoging van de benzinebelasting per eenheid, is er een daling van 36,993 miljoen gallons in het gasverbruik.

Door naar het dataframe voor coëfficiënten te kijken, kunnen we ook zien dat, volgens ons model, de Average_income en Paved_Highways kenmerken zijn degenen die dichter bij 0 liggen, wat betekent dat ze de hebben minste impact op het gasverbruik. Terwijl de Population_Driver_license(%) en Petrol_tax, met de coëfficiënten van respectievelijk 1,346.86 en -36.99, hebben de grootste impact op onze doelvoorspelling.

Met andere woorden, het gasverbruik is meestal uitgelegd door het percentage van de bevolking met een rijbewijs en het bedrag van de benzinebelasting, verrassend (of niet verrassend) genoeg.

We kunnen zien hoe dit resultaat verband houdt met wat we hadden gezien in de correlatie-heatmap. Het percentage rijbewijs had de sterkste correlatie, dus de verwachting was dat het het gasverbruik zou kunnen verklaren, en de benzinebelasting had een zwakke negatieve correlatie – maar vergeleken met het gemiddelde inkomen dat ook een zwakke negatieve correlatie had – was het de negatieve correlatie die het dichtst bij -1 lag en uiteindelijk het model verklaarde.

Toen alle waarden werden toegevoegd aan de meervoudige regressieformule, kwamen de verharde snelwegen en hellingen met gemiddeld inkomen dichter bij 0, terwijl het percentage rijbewijs en het belastinginkomen verder van 0 af kwamen. Met die variabelen werd dus meer rekening gehouden toen het vinden van de best passende lijn.

Opmerking: In de datawetenschap hebben we vooral te maken met hypotese en onzekerheden. Het is geen 100% zekerheid en er is altijd een fout. Als je 0 fouten of 100% scores hebt, word dan verdacht. We hebben slechts één model getraind met een steekproef van gegevens, het is te vroeg om aan te nemen dat we een eindresultaat hebben. Om verder te gaan, kunt u restanalyses uitvoeren, het model trainen met verschillende monsters met behulp van a kruisvalidatie techniek. U kunt ook meer gegevens en meer variabelen krijgen om te verkennen en het model in te pluggen om resultaten te vergelijken.

Het lijkt erop dat onze analyse tot nu toe zinvol is. Nu is het tijd om te bepalen of ons huidige model gevoelig is voor fouten.

Voorspellingen maken met het multivariate regressiemodel

Om te begrijpen of en hoe ons model fouten maakt, kunnen we het gasverbruik voorspellen met behulp van onze testgegevens en vervolgens naar onze statistieken kijken om te zien hoe goed ons model zich gedraagt.

Op dezelfde manier die we hadden gedaan voor het eenvoudige regressiemodel, laten we voorspellen met de testgegevens:

y_pred = regressor.predict(X_test)

Nu we onze testvoorspellingen hebben, kunnen we ze beter vergelijken met de werkelijke uitvoerwaarden voor X_test door ze te organiseren in een DataFrameformaat:

results = pd.DataFrame({'Actual': y_test, 'Predicted': y_pred})
print(results)

De uitvoer zou er als volgt uit moeten zien:

    Actual   Predicted
27     631  606.692665
40     587  673.779442
26     577  584.991490
43     591  563.536910
24     460  519.058672
37     704  643.461003
12     525  572.897614
19     640  687.077036
4      410  547.609366
25     566  530.037630

Hier hebben we de index van de rij van elke testgegevens, een kolom voor de werkelijke waarde en een andere voor de voorspelde waarden. Als we kijken naar het verschil tussen de werkelijke en voorspelde waarden, zoals tussen 631 en 607, dat is 24, of tussen 587 en 674, dat is -87, dan lijkt er enige afstand tussen beide waarden te zijn, maar is die afstand te groot ?

Het multivariate model evalueren

Na het verkennen, trainen en bekijken van onze modelvoorspellingen, is onze laatste stap het evalueren van de prestaties van onze meervoudige lineaire regressie. We willen begrijpen of onze voorspelde waarden te ver van onze werkelijke waarden liggen. We doen dit op dezelfde manier als voorheen, door de MAE-, MSE- en RMSE-statistieken te berekenen.

Laten we dus de volgende code uitvoeren:

mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)

print(f'Mean absolute error: {mae:.2f}')
print(f'Mean squared error: {mse:.2f}')
print(f'Root mean squared error: {rmse:.2f}')

De output van onze statistieken zou moeten zijn:

Mean absolute error: 53.47
Mean squared error: 4083.26
Root mean squared error: 63.90

We kunnen zien dat de waarde van de RMSE 63.90 is, wat betekent dat ons model zijn voorspelling verkeerd kan krijgen door 63.90 op te tellen bij of af te trekken van de werkelijke waarde. Het zou beter zijn om deze fout dichter bij 0 te hebben, en 63.90 is een groot getal - dit geeft aan dat ons model misschien niet zo goed voorspelt.

Onze MAE ligt ook ver van 0. We kunnen een significant verschil in grootte zien in vergelijking met onze vorige eenvoudige regressie waarbij we een beter resultaat hadden.

Om verder te graven in wat er met ons model gebeurt, kunnen we kijken naar een metriek die het model op een andere manier meet, het houdt geen rekening met onze individuele gegevenswaarden zoals MSE, RMSE en MAE, maar neemt een meer algemene benadering van de fout, de R2:

$$
R^2 = 1 – frac{som(werkelijk – voorspeld)^2}{som(werkelijk – feitelijk gemiddelde)^2}
$$

De R2 vertelt ons niet hoe ver of hoe dicht elke voorspelde waarde is van de echte gegevens - het vertelt ons hoeveel van ons doel wordt vastgelegd door ons model.

Met andere woorden, R2 kwantificeert hoeveel van de variantie van de afhankelijke variabele door het model wordt verklaard.

De R2 metriek varieert van 0% tot 100%. Hoe dichter bij 100%, hoe beter. Als de R2 waarde negatief is, betekent dit dat het het doel helemaal niet verklaart.

We kunnen R . berekenen2 in Python om een ​​beter begrip te krijgen van hoe het werkt:

actual_minus_predicted = sum((y_test - y_pred)**2)
actual_minus_actual_mean = sum((y_test - y_test.mean())**2)
r2 = 1 - actual_minus_predicted/actual_minus_actual_mean
print('R²:', r2)
R²: 0.39136640014305457

R2 wordt ook standaard geïmplementeerd in de score methode van de lineaire regressorklasse van Scikit-Learn. We kunnen het als volgt berekenen:

regressor.score(X_test, y_test)

Dit resulteert in:

0.39136640014305457

Tot nu toe lijkt het erop dat ons huidige model slechts 39% van onze testgegevens verklaart, wat geen goed resultaat is, het betekent dat 61% van de testgegevens onverklaard blijft.

Laten we ook begrijpen hoeveel ons model onze treingegevens verklaart:

regressor.score(X_train, y_train)

Welke outputs:

0.7068781342155135

We hebben een probleem met ons model gevonden. Het verklaart 70% van de treingegevens, maar slechts 39% van onze testgegevens, wat belangrijker is om goed te krijgen dan onze treingegevens. Het past heel goed bij de treingegevens, en niet in staat om de testgegevens te passen - wat betekent dat we een overfit meervoudig lineair regressiemodel.

Er zijn veel factoren die hieraan hebben bijgedragen, een paar hiervan kunnen zijn:

  1. Behoefte aan meer gegevens: we hebben slechts één jaar aan gegevens (en slechts 48 rijen), wat niet zo veel is, terwijl het hebben van meerdere jaren aan gegevens de voorspellingsresultaten behoorlijk had kunnen verbeteren.
  2. Overfitting overwinnen: we kunnen een kruisvalidatie gebruiken die ons model past bij verschillende geschudde voorbeelden van onze dataset om te proberen een einde te maken aan overfitting.
  3. Aannames die niet opgaan: we zijn ervan uitgegaan dat de gegevens een lineair verband hadden, maar dat is misschien niet het geval. Het visualiseren van de gegevens met behulp van boxplots, het begrijpen van de gegevensverdeling, het behandelen van de uitbijters en het normaliseren ervan kan daarbij helpen.
  4. Slechte functies: we hebben mogelijk andere of meer functies nodig die de sterkste relatie hebben met waarden die we proberen te voorspellen.

Conclusie

In dit artikel hebben we een van de meest fundamentele machine learning-algoritmen bestudeerd, namelijk lineaire regressie. We hebben zowel eenvoudige lineaire regressie als meervoudige lineaire regressie geïmplementeerd met behulp van de Scikit-learn machine learning-bibliotheek.

spot_img

Laatste intelligentie

spot_img

Chat met ons

Hallo daar! Hoe kan ik u helpen?