<jupyter_start><jupyter_text>Eksempel på lineær regresjonUnder vises en av mange metoder på hvordan man kan utføre lineær regresjon i Python.Her bruker vi to pakker for å gjøre regresjonen:* Vi bruker [matplotlib](https://matplotlib.org/) for å lage figurer.* Vi bruker [numpy](https://numpy.org/) for å utføre lineær regresjon.Vi begynner med å importere disse to pakkene:<jupyter_code># Importer pakker
import matplotlib.pyplot as plt  # matplotlib
import numpy as np  # og numpy
# Også forteller vi matplotlib at vi plotter i en notebook (dette gjør at vi kan zoome og flytte rundt i figurene):
%matplotlib notebook<jupyter_output><empty_output><jupyter_text>For å gjøre selve regresjonen trenger vi noen x- og y-verdier. Her tar vi de bare fra vedlegg 3 i labheftet, og siden det ikke er så mange verdier, så taster vi de rett inn:<jupyter_code>x = np.array([16, 20, 24, 28, 32, 36, 40, 44, 48, 52]) # Liste med eksperimentelle x-verdier
y = np.array([13, 18, 24, 37, 27, 30, 31, 35, 42, 43]) # Liste med eksperimentelle y-verdier<jupyter_output><empty_output><jupyter_text>Vi kan nå plotte disse verdiene for å se hvordan de ser ut. Et [scatter](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.scatter.html)-plot er egnet til dette. La oss lage et veldig enkelt plot:<jupyter_code># La oss plotte de målte verdiene for å se hvordan de ser ut:
plt.figure() # Lag ny figur.
plt.scatter(x, y); # Plot x og y i et "scatter" plot.<jupyter_output><empty_output><jupyter_text>Når vi plotter med matplotlib er ved **veldig** mye forskjellig vi kan stille på.Under er et eksempel der vi legger til tekst på aksene, endrer på symbolet og fargen vi bruker i plottet ogendrer på størrelsen på punktene.Matplotlib har et [stort galleri med eksempler](https://matplotlib.org/stable/gallery/index.html) for ulike typer plott. Hvis du syns figurene ser litt kjedelige ut, så kan du f.eks. prøve å endrepå "stilen". Dette kan gjøres med ``plt.style.use("navn-på-stil")``der ``navn-på-stil`` er en [matplotlib stil](https://matplotlib.org/stable/gallery/style_sheets/style_sheets_reference.html).<jupyter_code>plt.figure(constrained_layout=True) # Lag ny figur, men fjern litt tomrom ("constrained_layout=True") i figuren.
plt.scatter(x, y, marker='X', s=200, color='tomato') # Plot x og y i et "scatter" plot, endre symbol og størrelse.
plt.xlabel('Dette er x-aksen')  # Legg til tekst på x-aksen
plt.ylabel('Dette er y-aksen')  # Legg til tekst på y-aksen
plt.title('Min fantastiske figur!');  # Legg til tittel for hele figuren<jupyter_output><empty_output><jupyter_text>I figuren over ser det ut til at det kan passe bra med en rett linje!For å tilpasse linja bruker vi metodenmetoden [polyfit](https://numpy.org/doc/stable/reference/generated/numpy.polyfit.html) fra [numpy](https://numpy.org/). Denne metoden gjør tilpassing av polynomer ved minste kvadraters metode:<jupyter_code>fit = np.polyfit(x, y, deg=1) # Tilpasse rett linje, "fit" inneholder nå koeffisientene.<jupyter_output><empty_output><jupyter_text>For å bruke [polyfit](https://numpy.org/doc/stable/reference/generated/numpy.polyfit.html) gir vi inn x- og y-verdiene. I tillegg setter vi ``deg=1`` for å få en rett linje på formen $y = a + b x$. Metoden returnerer parameterne ($a$ og $b$), og over lagrer vi disse i variabelen ``fit``.Parameteren ``deg`` velger ordenen til polynomet vi tilpasser. Hvis vi har grunn til å tro at det f.eks.passer bedre med et 2. ordens polynom på formen $y = a_0 + a_1 x + a_2 x^2$, så kan vi tilpasse detteved å sette ``deg=2``.<jupyter_code># Som vi skrev over, så inneholder listen "fit" nå koeffisientene til linjen, altså a og b:
print(fit)
# Rekkefølgen på parameterne er: [stigningstall, skjæringspunkt]:
b, a = fit[0], fit[1]
print(f"Skjæringspunkt (a): {a:.2f}")
print(f"Stigningstall (b): {b:.2f}")<jupyter_output><empty_output><jupyter_text>For å plotte linjen, kan vi bruke skjæringspunktet og stigningstallet vi har funnet.I [numpy](https://numpy.org/)er det en egen metode, [polyval](https://numpy.org/doc/stable/reference/generated/numpy.polyval.html), som kan hjelpe oss med dette. Vi kan da regne ut y-verdier for den rette linjen for hver opprinnelig x-verdi:<jupyter_code>y_hat = np.polyval(fit, x) #"y_hat" inneholder alle y-verdiene til den rette linjen ved x-verdier gitt i listen vår "x".
# La oss plotte linjen og de opprinnelige punktene:
plt.figure() # Lag ny figur.
plt.scatter(x, y) # Vis de målte verdiene.
plt.plot(x, y_hat, color='black');  # Vis den tilpassede linjen.<jupyter_output><empty_output><jupyter_text>Det er god praksis å inkludere en eller flere parametere som sier noe om hvorbra den rette linjen vi har funnet er.Her kan vi bruke den såkalte $R^2$-verdien, så la oss regne den ut (her kan du sjekke om formlene vi bruker under stemmer med vedlegg 3 i laboratorieheftet):<jupyter_code># Regne ut R^2
SSE = np.sum((y - y_hat)**2)
SST = np.sum((y - np.average(y))**2)
R2_1 = 1 - SSE / SST
print(f"R² = {R2_1:.2f}")<jupyter_output><empty_output><jupyter_text>Merk: Siden vi bruker [numpy](https://numpy.org/), så gjøres operasjoner av typen ``y - y_hat`` element for element. Det betyr at dersom ``y = [1, 2, 3]`` og ``y_hat = [4, 5, 6]``,så blir  ``y - y_hat = [1-4, 2-5, 3-6] = [-3, -3, -3]``.Vi slipper altså å lage en løkke som går igjennom alle tallene, element for element. La oss lage en litt mer informativ figur der vi tar med de opprinnelige punktene, den tilpassede linjen, vi skriver inn $R^2$-verdien vi fant over, vi legger til tekst på aksene, vi fjerner rammen rundt figuren, og vi setter inn tegnforklaring:<jupyter_code># Lag ny figur der vi tar med de målte punktene, den rette linjen og viser R²:
fig, ax = plt.subplots()  # Her lager vi en figur og akser. Aksene (ax) bruker vi for å endre litt på stilen:
ax.spines['top'].set_visible(False)  # Skru av aksen i toppen av figuren.
ax.spines['right'].set_visible(False)  # Skru av aksen til høyre i figuren.

# Scatterplot av datasettet:
plt.scatter(x, y, label='Målinger')

# Regresjonslinjen:
plt.plot(x, y_hat, c='k', label='Tilpasset linje')

# R^2 i figur:
plt.text(16, 43, f"R²: {R2_1:.2f}", c="k")

# Aksetitler:
plt.xlabel("Temperatur [°C]")
plt.ylabel("Mengde av komponent Y [g]")

# Legg til tegnforklaring:
plt.legend(loc='lower right', frameon=False)

plt.show()<jupyter_output><empty_output><jupyter_text>(Her kan du f.eks. sjekke om du får byttet ut teksten "Tilpasset linje" med ligningen for den rette linja.) Ved å observere grafen over kan man tenke seg at et av punktene er en utligger da det skiller seg ut fra de andre punktene ved å ikke følge den rette linjen.Under har dette punktet blitt fjernet og en ny regresjon har blitt utført.<jupyter_code># Liste uten utligger
x2 = [16, 20, 24, 32, 36, 40, 44, 48, 52]
y2 = [13, 18, 24, 27, 30, 31, 35, 42, 43]

# Tilpasse linje til data
fit2 = np.polyfit(x2, y2, deg=1)
y_hat2 = np.polyval(fit, x2)

# Finne skjæringspunkt og stigningstall
b2, a2 = fit2[0], fit2[1]
print(f"Skjæringspunkt (a): {a2:.2f}")
print(f"Stigningstall (b): {b2:.2f}")

# Regne ut R²:
SSE2 = np.sum((y2 - y_hat2)**2)
SST2 = np.sum((y2 - np.average(y2))**2)
R2_2 = 1 - SSE2/SST2

# Lag ny figur:
fig, ax = plt.subplots()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

# Plot målte punkter og tilpasset linje:
plt.scatter(x2, y2, label='Målinger', s=100)
plt.plot(x2, y_hat2, c='k', label=f'Tilpasset linje (R² = {R2_2:.2f}): y = {a2:.2f} + {b2:.2f}x',
         linewidth=2.5)  # linewidth kan brukes for å endre tykkelsen på linjen

# Aksetitler:
plt.xlabel("Temperatur [°C]")
plt.ylabel("Mengde av komponent Y [g]")

plt.legend(frameon=False)

plt.show() # Vis figuren!<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12130678120525837, 'fraction_numerical': 0.022647403358063256, 'mean_word_length': 4.929012345679013, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 41, 'https://': 11, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '537657', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 3219, 'n_tokens_neox': 3053, 'n_words': 973, 'path': 'jupyter/regresjon/regresjon.ipynb', 'repo_name': 'andersle/kj1000', 'size': '7683'}