Lineaire regressie wordt gebruikt wanneer we een numerieke waarde willen voorspellen (bijvoorbeeld de prijs van een huis, temperatuur of verkoopcijfers).
Het werkt door een rechte lijn te vinden die het beste de relatie tussen invoerkenmerken en de uitvoer weergeeft.
In deze les richten we ons op het begrijpen van het concept voordat we meer geavanceerde regressietechnieken verkennen.

Infographic door Dasani Madipalli
Tot nu toe heb je verkend wat regressie is met voorbeeldgegevens verzameld uit de dataset van pompoenprijzen die we in deze les zullen gebruiken. Je hebt dit ook gevisualiseerd met Matplotlib.
Nu ben je klaar om dieper in regressie voor ML te duiken. Visualisatie helpt je om data te begrijpen, maar de echte kracht van Machine Learning komt van het trainen van modellen. Modellen worden getraind op historische data om automatisch afhankelijkheden in de data vast te leggen en stellen je in staat uitkomsten te voorspellen voor nieuwe data die het model nog niet eerder heeft gezien.
In deze les leer je meer over twee soorten regressie: basis lineaire regressie en polynomiale regressie, samen met wat van de wiskunde achter deze technieken. Deze modellen stellen ons in staat om pompoenprijzen te voorspellen op basis van verschillende invoerdata.
🎥 Klik op de afbeelding hierboven voor een korte video-overzicht van lineaire regressie.
Gedurende dit curriculum gaan we uit van minimale wiskundige voorkennis, en streven we ernaar het toegankelijk te maken voor studenten uit andere disciplines. Let daarom op notities, 🧮 uitlegpaaltjes, diagrammen en andere leermiddelen om het begrip te ondersteunen.
Je zou nu bekend moeten zijn met de structuur van de pompoen data die we onderzoeken. Je kunt deze vooraf geladen en voorbewerkt vinden in het bestand notebook.ipynb van deze les. In het bestand wordt de pompoenprijs per bushel weergegeven in een nieuw DataFrame. Zorg ervoor dat je deze notebooks kunt draaien in kernels in Visual Studio Code.
Even ter herinnering, je laadt deze data om er vragen over te kunnen stellen.
- Wanneer is het beste moment om pompoenen te kopen?
- Welke prijs kan ik verwachten van een doos mini-pompoenen?
- Moet ik ze kopen in halve bushel manden of per 1 1/9 bushel doos?
Laten we deze data verder onderzoeken.
In de vorige les maakte je een Pandas DataFrame en vulde je die met een deel van de originele dataset, waarbij je de prijzen standaardiseerde per bushel. Daarmee kon je echter slechts ongeveer 400 datapunten ophalen en alleen voor de herfstmaanden.
Bekijk de data die we vooraf geladen hebben in het bijbehorende notebook van deze les. De gegevens zijn vooraf geladen en er is een eerste scatterplot gemaakt om maanddata te tonen. Misschien kunnen we meer details over de aard van de data krijgen door deze verder te schonen.
Zoals je in les 1 hebt geleerd, is het doel van een lineaire regressie oefening het kunnen plotten van een lijn om:
- Relaties tussen variabelen te tonen. Toon de relatie tussen variabelen
- Voorspellingen te maken. Maak accurate voorspellingen waar een nieuw datapunt zou vallen ten opzichte van die lijn.
Typisch voor de Least-Squares Regression is om dit soort lijn te tekenen. De term "Least-Squares" verwijst naar het proces van het minimaliseren van de totale fout in ons model. Voor elk datapunt meten we de verticale afstand (residueel genoemd) tussen het daadwerkelijke punt en onze regressielijn.
We kwadrateren deze afstanden om twee belangrijke redenen:
-
Grootte boven richting: We willen een fout van -5 hetzelfde behandelen als een fout van +5. Kwadrateren zorgt ervoor dat alle waarden positief worden.
-
Straffen van uitschieters: Kwadrateren geeft meer gewicht aan grotere fouten, waardoor de lijn dichter bij veraf liggende punten blijft.
We tellen vervolgens al deze gekwadrateerde waarden op. Ons doel is om die specifieke lijn te vinden waarbij deze som het kleinst is (de kleinste mogelijke waarde)—vandaar de naam "Least-Squares".
🧮 Laat me de wiskunde zien
Deze lijn, genaamd de line of best fit, kan worden uitgedrukt door een vergelijking:
Y = a + bX
Xis de 'verklarende variabele'.Yis de 'afhankelijke variabele'. De helling van de lijn isbenais het snijpunt met de y-as, wat verwijst naar de waarde vanYwanneerX = 0.Bereken eerst de helling
b. Infographic door Jen LooperMet andere woorden, en verwijzend naar onze oorspronkelijke pompoendata-vraag: "voorspel de prijs van een pompoen per bushel per maand", zou
Xverwijzen naar de prijs enYnaar de verkoopmaand.Bereken de waarde van Y. Als je rond de $4 betaalt, moet het april zijn! Infographic door Jen Looper
De wiskunde die de lijn berekent moet de helling van de lijn tonen, die ook afhankelijk is van het intercept, oftewel waar
Yligt alsX = 0.Je kunt de methode voor het berekenen van deze waarden zien op de website Math is Fun. Bezoek ook deze Least-squares calculator om te zien hoe de waardes van getallen de lijn beïnvloeden.
Nog een term om te begrijpen is de Correlatiecoëfficiënt tussen gegeven X- en Y-variabelen. Met een scatterplot kun je deze coëfficiënt snel visualiseren. Een plot met datapunten netjes op een lijn wijzen op hoge correlatie, terwijl een plot waar punten overal verspreid liggen tussen X en Y op lage correlatie wijst.
Een goed lineair regressiemodel is er een met een hoge Correlatiecoëfficiënt (dichter bij 1 dan bij 0) met behulp van de Least-Squares Regression methode met een regressielijn.
✅ Draai het notebook bij deze les en bekijk de scatterplot van Maand tegen Prijs. Lijkt de data die Maand aan Prijs koppelt voor pompoenverkopen een hoge of lage correlatie te hebben, volgens jouw visuele interpretatie van de scatterplot? Verandert dat als je een fijnmaziger maat gebruikt in plaats van Maand, bijvoorbeeld dag van het jaar (d.w.z. aantal dagen sinds begin van het jaar)?
In onderstaande code gaan we ervan uit dat we de data hebben opgeschoond, en een DataFrame new_pumpkins hebben verkregen, vergelijkbaar met het volgende:
| ID | Maand | DagVanHetJaar | Variëteit | Stad | Verpakking | Lage Prijs | Hoge Prijs | Prijs |
|---|---|---|---|---|---|---|---|---|
| 70 | 9 | 267 | PIE TYPE | BALTIMORE | 1 1/9 bushel kartonnen dozen | 15.0 | 15.0 | 13.636364 |
| 71 | 9 | 267 | PIE TYPE | BALTIMORE | 1 1/9 bushel kartonnen dozen | 18.0 | 18.0 | 16.363636 |
| 72 | 10 | 274 | PIE TYPE | BALTIMORE | 1 1/9 bushel kartonnen dozen | 18.0 | 18.0 | 16.363636 |
| 73 | 10 | 274 | PIE TYPE | BALTIMORE | 1 1/9 bushel kartonnen dozen | 17.0 | 17.0 | 15.454545 |
| 74 | 10 | 281 | PIE TYPE | BALTIMORE | 1 1/9 bushel kartonnen dozen | 15.0 | 15.0 | 13.636364 |
De code om de data te schonen is beschikbaar in
notebook.ipynb. We hebben dezelfde schoonmaakstappen uitgevoerd als in de vorige les, en hebben de kolomDagVanHetJaarberekend met de volgende expressie:
day_of_year = pd.to_datetime(pumpkins['Date']).apply(lambda dt: (dt-datetime(dt.year,1,1)).days)Nu je inzicht hebt in de wiskunde achter lineaire regressie, laten we een regressiemodel maken om te zien of we kunnen voorspellen welke verpakking van pompoenen de beste pompoenprijzen zal hebben. Iemand die pompoenen koopt voor een pompoenveld voor de feestdagen wil deze informatie mogelijk gebruiken om hun aankopen van pompoenverpakkingen voor het veld te optimaliseren.
🎥 Klik op de afbeelding hierboven voor een korte video-overzicht over correlatie.
In de vorige les heb je waarschijnlijk gezien dat de gemiddelde prijs voor verschillende maanden er zo uitziet:
Dit suggereert dat er enige correlatie zou moeten zijn, en we kunnen proberen een lineair regressiemodel te trainen om de relatie tussen Maand en Prijs te voorspellen, of tussen DagVanHetJaar en Prijs. Hier is de scatterplot die de laatste relatie toont:
Laten we kijken of er een correlatie is met de corr functie:
print(new_pumpkins['Month'].corr(new_pumpkins['Price']))
print(new_pumpkins['DayOfYear'].corr(new_pumpkins['Price']))Het lijkt erop dat de correlatie vrij klein is, -0.15 op basis van Maand en -0.17 op basis van DagVanHetJaar, maar er zou een andere belangrijke relatie kunnen zijn. Het lijkt erop dat er verschillende clusters van prijzen zijn die overeenkomen met verschillende pompoenvariëteiten. Om deze hypothese te bevestigen, laten we elke pompoencategorie met een andere kleur plotten. Door een ax parameter door te geven aan de scatter plotfunctie kunnen we alle punten op dezelfde grafiek weergeven:
ax=None
colors = ['red','blue','green','yellow']
for i,var in enumerate(new_pumpkins['Variety'].unique()):
df = new_pumpkins[new_pumpkins['Variety']==var]
ax = df.plot.scatter('DayOfYear','Price',ax=ax,c=colors[i],label=var)Ons onderzoek suggereert dat variëteit meer effect heeft op de totale prijs dan de daadwerkelijke verkoopdatum. Dit kunnen we zien met een staafgrafiek:
new_pumpkins.groupby('Variety')['Price'].mean().plot(kind='bar')Laten we ons voor nu alleen richten op één pompoenvariëteit, het 'pie type', en kijken wat voor effect de datum heeft op de prijs:
pie_pumpkins = new_pumpkins[new_pumpkins['Variety']=='PIE TYPE']
pie_pumpkins.plot.scatter('DayOfYear','Price') Als we nu de correlatie berekenen tussen Prijs en DagVanHetJaar met de corr functie, krijgen we iets als -0.27 - wat betekent dat het trainen van een voorspellend model zinvol is.
Voordat je een lineair regressiemodel traint, is het belangrijk om ervoor te zorgen dat onze data schoon is. Lineaire regressie werkt niet goed met ontbrekende waarden, dus het is logisch om alle lege cellen kwijt te raken:
pie_pumpkins.dropna(inplace=True)
pie_pumpkins.info()Een andere aanpak is om die lege waarden op te vullen met gemiddelde waardes uit de corresponderende kolom.
🎥 Klik op de afbeelding hierboven voor een korte video-overzicht van lineaire en polynomiale regressie.
Om ons Lineaire Regressiemodel te trainen, gebruiken we de Scikit-learn bibliotheek.
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_splitWe beginnen met het scheiden van invoerwaarden (kenmerken) en de verwachte uitvoer (label) in aparte numpy arrays:
X = pie_pumpkins['DayOfYear'].to_numpy().reshape(-1,1)
y = pie_pumpkins['Price']Let op dat we
reshapeop de invoerdata moesten uitvoeren zodat het Linear Regression-pakket het correct begrijpt. Lineaire Regressie verwacht een 2D-array als invoer, waarbij elke rij van de array overeenkomt met een vector van invoerkenmerken. In ons geval, omdat we maar één invoer hebben, hebben we een array nodig met vorm N×1, waarbij N de datasetgrootte is.
Vervolgens moeten we de data splitsen in train- en testdatasets, zodat we ons model na het trainen kunnen valideren:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)Tot slot neemt het trainen van het daadwerkelijke Lineaire Regressiemodel slechts twee regels code in beslag. We definiëren het LinearRegression object, en passen het toe op onze data met de fit methode:
lin_reg = LinearRegression()
lin_reg.fit(X_train,y_train)Het LinearRegression-object na het fit-ten bevat alle coëfficiënten van de regressie, die toegankelijk zijn via de .coef_-eigenschap. In ons geval is er maar één coëfficiënt, die ongeveer -0.017 zou moeten zijn. Dit betekent dat de prijzen iets lijken te dalen in de loop van de tijd, maar niet te veel, ongeveer 2 cent per dag. We kunnen ook het snijpunt van de regressie met de Y-as benaderen met lin_reg.intercept_ - dit zal in ons geval rond 21 liggen, wat de prijs aan het begin van het jaar aangeeft.
Om te zien hoe nauwkeurig ons model is, kunnen we prijzen voorspellen op een testdataset en vervolgens meten hoe dicht onze voorspellingen bij de verwachte waarden liggen. Dit kan worden gedaan met behulp van de mean square error (MSE) metriek, wat het gemiddelde is van alle gekwadrateerde verschillen tussen verwachte en voorspelde waarde.
pred = lin_reg.predict(X_test)
mse = np.sqrt(mean_squared_error(y_test,pred))
print(f'Mean error: {mse:3.3} ({mse/np.mean(pred)*100:3.3}%)')Onze fout lijkt ongeveer 2 punten te zijn, wat ~17% is. Niet zo goed. Een andere indicator van modelkwaliteit is de coëfficiënt van determinatie, die op deze manier verkregen kan worden:
score = lin_reg.score(X_train,y_train)
print('Model determination: ', score)Als de waarde 0 is, betekent dit dat het model de invoergegevens niet meeneemt en fungeert als de slechtste lineaire voorspeller, wat gewoon de gemiddelde waarde van het resultaat is. De waarde 1 betekent dat we perfect alle verwachte uitkomsten kunnen voorspellen. In ons geval is de coëfficiënt ongeveer 0.06, wat vrij laag is.
We kunnen ook de testgegevens plotten samen met de regressielijn om beter te zien hoe regressie in ons geval werkt:
plt.scatter(X_test,y_test)
plt.plot(X_test,pred)Een ander type lineaire regressie is polynomiale regressie. Soms is er een lineair verband tussen variabelen - hoe groter de pompoen qua volume, hoe hoger de prijs - maar soms kunnen deze relaties niet worden weergegeven als een vlak of rechte lijn.
✅ Hier zijn nog meer voorbeelden van gegevens die baat zouden hebben bij polynomiale regressie
Kijk nog eens goed naar het verband tussen Datum en Prijs. Lijkt deze spreidingsgrafiek per se door een rechte lijn te moeten worden geanalyseerd? Kunnen prijzen niet schommelen? In dat geval kun je polynomiale regressie proberen.
✅ Polynomiale uitdrukkingen zijn wiskundige uitdrukkingen die uit een of meer variabelen en coëfficiënten kunnen bestaan
Polynomiale regressie creëert een gebogen lijn om niet-lineaire data beter te passen. In ons geval, als we een kwadratische DayOfYear variabele toevoegen aan de invoergegevens, zouden we onze data moeten kunnen passen met een parabolische kromme, die een minimumpunt heeft op een bepaald punt binnen het jaar.
Scikit-learn bevat een handige pipeline-API om verschillende stappen van gegevensverwerking te combineren. Een pipeline is een keten van schatters. In ons geval maken we een pipeline die eerst polynomiale kenmerken toevoegt aan ons model en vervolgens de regressie traint:
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
pipeline = make_pipeline(PolynomialFeatures(2), LinearRegression())
pipeline.fit(X_train,y_train)Met PolynomialFeatures(2) wordt bedoeld dat we alle tweedegraads polynomen van de invoergegevens opnemen. In ons geval betekent dat alleen DayOfYear2, maar gegeven twee invoervariabelen X en Y, worden ook X2, XY en Y2 toegevoegd. We kunnen ook hogere graads polynomen gebruiken als we dat willen.
Pipelines kunnen op dezelfde manier worden gebruikt als het oorspronkelijke LinearRegression-object, d.w.z. we kunnen de pipeline fitten en vervolgens predict gebruiken om de voorspellingen te krijgen. Hier is de grafiek met testgegevens en de benaderingscurve:
Met polynomiale regressie kunnen we iets lagere MSE en hogere determinatie krijgen, maar niet significant. We moeten andere kenmerken in rekening brengen!
Je kunt zien dat de minimale pompoenprijzen ergens rond Halloween worden waargenomen. Hoe kun je dat verklaren?
🎃 Gefeliciteerd, je hebt zojuist een model gemaakt dat kan helpen de prijs van taartpompoenen te voorspellen. Waarschijnlijk kun je dezelfde procedure herhalen voor alle pompoentypes, maar dat zou saai zijn. Laten we nu leren hoe we rekening kunnen houden met pompoensoorten in ons model!
In een ideale wereld willen we prijzen voor verschillende pompoensoorten voorspellen met hetzelfde model. Echter, de kolom Variety is anders dan kolommen zoals Month, omdat deze niet-numerieke waarden bevat. Dergelijke kolommen worden categorisch genoemd.
🎥 Klik op de afbeelding hierboven voor een korte video-overzicht van het gebruik van categorische kenmerken.
Hier zie je hoe de gemiddelde prijs afhangt van de soort:
Om rekening te houden met de soort, moeten we deze eerst omzetten in numerieke vorm, of encoderen. Er zijn verschillende manieren om dat te doen:
- Eenvoudige numerieke codering bouwt een tabel van verschillende soorten, en vervangt dan de soortnaam door een index in die tabel. Dit is niet het beste idee voor lineaire regressie, omdat lineaire regressie de numerieke waarde van de index neemt en optelt bij het resultaat, maal een coëfficiënt. In ons geval is de relatie tussen het indexnummer en de prijs duidelijk niet-lineair, zelfs als we de indices in een specifieke volgorde plaatsen.
- One-hot encoding vervangt de kolom
Varietydoor 4 verschillende kolommen, een voor elke soort. Elke kolom bevat1als de overeenkomstige rij van die betreffende soort is, en0anders. Dit betekent dat er vier coëfficiënten in lineaire regressie zijn, één voor elke pompoensoort, verantwoordelijk voor de "startprijs" (of liever gezegd "extra prijs") voor die specifieke soort.
De onderstaande code toont hoe we een soort one-hot kunnen encoderen:
pd.get_dummies(new_pumpkins['Variety'])| ID | FAIRYTALE | MINIATURE | MIXED HEIRLOOM VARIETIES | PIE TYPE |
|---|---|---|---|---|
| 70 | 0 | 0 | 0 | 1 |
| 71 | 0 | 0 | 0 | 1 |
| ... | ... | ... | ... | ... |
| 1738 | 0 | 1 | 0 | 0 |
| 1739 | 0 | 1 | 0 | 0 |
| 1740 | 0 | 1 | 0 | 0 |
| 1741 | 0 | 1 | 0 | 0 |
| 1742 | 0 | 1 | 0 | 0 |
Om lineaire regressie te trainen met one-hot gecodeerde variëteit als invoer, hoeven we alleen X en y correct te initialiseren:
X = pd.get_dummies(new_pumpkins['Variety'])
y = new_pumpkins['Price']De rest van de code is hetzelfde als wat we hierboven gebruikten om lineaire regressie te trainen. Als je het probeert, zul je zien dat de mean squared error ongeveer hetzelfde is, maar we krijgen een veel hogere coëfficiënt van determinatie (~77%). Om nog nauwkeurigere voorspellingen te krijgen, kunnen we nog meer categorische kenmerken overwegen, evenals numerieke kenmerken zoals Month of DayOfYear. Om één grote array van features te krijgen, kunnen we join gebruiken:
X = pd.get_dummies(new_pumpkins['Variety']) \
.join(new_pumpkins['Month']) \
.join(pd.get_dummies(new_pumpkins['City'])) \
.join(pd.get_dummies(new_pumpkins['Package']))
y = new_pumpkins['Price']Hier nemen we ook City en het type Package mee, wat ons een MSE van 2.84 (10%) en een determinatie van 0.94 geeft!
Om het beste model te maken, kunnen we gecombineerde (one-hot gecodeerde categorische + numerieke) gegevens uit het bovenstaande voorbeeld samen met polynomiale regressie gebruiken. Hier is de volledige code voor jouw gemak:
# trainingsgegevens instellen
X = pd.get_dummies(new_pumpkins['Variety']) \
.join(new_pumpkins['Month']) \
.join(pd.get_dummies(new_pumpkins['City'])) \
.join(pd.get_dummies(new_pumpkins['Package']))
y = new_pumpkins['Price']
# maak train-test splitsing
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
# stel de pijplijn in en train deze
pipeline = make_pipeline(PolynomialFeatures(2), LinearRegression())
pipeline.fit(X_train,y_train)
# voorspel resultaten voor testgegevens
pred = pipeline.predict(X_test)
# bereken MSE en bepaling
mse = np.sqrt(mean_squared_error(y_test,pred))
print(f'Mean error: {mse:3.3} ({mse/np.mean(pred)*100:3.3}%)')
score = pipeline.score(X_train,y_train)
print('Model determination: ', score)Dit zou ons de beste determinatiecoëfficiënt van bijna 97% en MSE=2.23 (~8% voorspellingsfout) moeten geven.
| Model | MSE | Determinatie |
|---|---|---|
DayOfYear Lineair |
2.77 (17.2%) | 0.07 |
DayOfYear Polynomiaal |
2.73 (17.0%) | 0.08 |
Variety Lineair |
5.24 (19.7%) | 0.77 |
| Alle kenmerken Lineair | 2.84 (10.5%) | 0.94 |
| Alle kenmerken Polynomiaal | 2.23 (8.25%) | 0.97 |
🏆 Goed gedaan! Je hebt vier regressiemodellen gemaakt in één les en de modelkwaliteit verbeterd tot 97%. In de laatste sectie over regressie leer je over logistische regressie om categorieën te bepalen.
Test verschillende variabelen in dit notebook om te zien hoe correlatie overeenkomt met modelnauwkeurigheid.
In deze les hebben we geleerd over lineaire regressie. Er zijn ook andere belangrijke soorten regressie. Lees over Stepwise, Ridge, Lasso en Elasticnet technieken. Een goede cursus om meer te leren is de Stanford Statistical Learning cursus
Disclaimer: Dit document is vertaald met behulp van de AI-vertalingsdienst Co-op Translator. Hoewel we streven naar nauwkeurigheid, dient u er rekening mee te houden dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het oorspronkelijke document in de oorspronkelijke taal moet als gezaghebbende bron worden beschouwd. Voor belangrijke informatie wordt een professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling.












