Sztuczna_inteligencja_i_jej.../regresja liniowa/regresja_liniowa_NMI.ipynb

579 lines
20 KiB
Plaintext
Raw Normal View History

2023-10-18 11:29:12 +02:00
{
"cells": [
{
"cell_type": "markdown",
"id": "4814259a-4af7-4839-a1dd-7f0e02837c3f",
"metadata": {},
"source": [
"# Regresja liniowa"
]
},
{
"cell_type": "markdown",
"id": "62ab7b17-f761-4723-8992-9620630fdaa6",
"metadata": {},
"source": [
"Na dzisiejszych zajęciach omówimy problem predykcji informacji i jego rozwiązanie poprzez wykorzystanie regresji liniowej."
]
},
{
"cell_type": "markdown",
"id": "b01eb137-5b7d-4f09-abac-0410366df4a9",
"metadata": {},
"source": [
"Zadaniem regresji liniowej jest po prostu dopasowanie prostej linii do danych. Warto podkreślić, że regresja liniowa przyjmuje założenie, że związek między cechami a zmienną objaśnianą jest mniej więcej liniowy. Regresja liniowa nie jest jedynym rodzajem regresji aczkolwiek jest to najprostsza wersja."
]
},
{
"cell_type": "markdown",
"id": "5dd39b3d-1a4b-44e5-9300-5ad796f7bb4c",
"metadata": {},
"source": [
"Regresja może nam pomóc w predykcji (przewidzeniu) wartości jakiejś zmiennej objaśnianej (zależnej) na podstawie jakiś cech (zmiennych niezależnych)."
]
},
{
"cell_type": "markdown",
"id": "3e618a4a-4088-4c3c-8f98-64c8a3ae0b57",
"metadata": {},
"source": [
"## Rozgrzewka"
]
},
{
"cell_type": "markdown",
"id": "c4a323d0-e71f-48a9-bda0-17ca379b71da",
"metadata": {},
"source": [
"Przeanalizuj poniższy wykres:"
]
},
2023-10-18 12:01:42 +02:00
{
"cell_type": "markdown",
"id": "1c26ec9b-3e87-4cbc-810a-78d61936f28d",
"metadata": {},
"source": [
"![](reglin.png)"
]
},
{
"cell_type": "markdown",
"id": "f38c977c-490c-49d8-8853-8c24c8d7cc43",
"metadata": {},
"source": [
"1. Dlaczego możemy zastosować regresję liniową do przewidywania informacji o danych?\n",
"\n",
"2. Co musimy znaleźć, aby móc dokonywać predykcji informacji? Co musimy mieć na uwadze, aby to znaleźć?"
]
},
{
"cell_type": "markdown",
"id": "8f70342d-6503-4810-ba02-e0f4a6208bfc",
"metadata": {},
"source": [
"## Przykład"
]
},
{
"cell_type": "markdown",
"id": "ebe61c55-c441-433d-8ba9-ec657ff5cc51",
"metadata": {},
"source": [
"Załóżmy, że mamy uczniów, którzy pracują w kursie e-learningowym i ciekawi nas, czy zakończą pracę w tym kursie z sukcesem, tzn. zdobędą jak najlepszy wynik w końcowym teście zaliczeniowym. Aktualne informacje, które posiadamy, to czas spędzony w tym kursie, liczba rozwiązanych ćwiczeń, liczba elementów, których uczeń jeszcze nie odwiedził. Wiemy też, kiedy uczeń zaczął się uczyć i ile razy wchodził do kursu. Każdy uczeń ma też świadomość, że mają określony termin, do kiedy muszą podejść do końcowego testu zaliczeniowego."
]
},
{
"cell_type": "markdown",
"id": "e29d4510-b276-4697-bc68-2b9f497bbc9e",
"metadata": {},
"source": [
"Powiedzmy, że na początek przyjrzymy się jednej z informacji - liczbie rozwiązanych ćwiczeń. Załóżmy, że w kursie jest 20 ćwiczeń do rozwiązania a wynik w końcowym teście zaliczeniowym badamy w procentach. Rok temu mieliśmy innych uczniów, którzy też pracowali z tym kursem e-learningowym i mamy informację o ich wynikach:"
]
},
2023-10-18 12:39:32 +02:00
{
"cell_type": "markdown",
"id": "960ec22d-236f-41b8-9f58-295ede47335a",
"metadata": {},
"source": [
"![](wyniki.png)"
]
},
{
"cell_type": "markdown",
"id": "be26d14d-2356-4e45-b0d0-b1bb6ece9526",
"metadata": {},
"source": [
"Zauważmy, że mamy tutaj pewien trend. W przybliżeniu możemy stwierdzić, że im większa liczba rozwiązanych ćwiczeń w kursie tym większy wynik w końcowym teście zaliczeniowym. Zatem moglibyśmy spróbować wyznaczyć funkcję, która pokazywałaby ten trend. Najprościej będzie wyznaczyć zależność liniową, czyli pewną funkcję liniową, która nam przybliży trend. Musimy znaleźć taką funkcję, dla której będziemy mieć sytuację, że dla jak największej liczby argumentów będziemy mieć jak najmniejszą różnicę pomiędzy wartością, którą zwróci funkcja a wartością rzeczywistą, którą mamy na powyższym wykresie."
]
},
{
"cell_type": "markdown",
"id": "020d9194-8fb5-450d-b642-71701c853c21",
"metadata": {},
"source": [
"Zatem naszym zadaniem jest wyznaczenie pewnej funkcji liniowej postaci:\n",
"$f(x)=ax+b$, gdzie:\n",
"\n",
"$x$ - liczba rozwiązanych ćwiczeń w kursie\n",
"\n",
"$f(x)$ - przybliżony wynik osiągnięty w końcowym teście zaliczeniowym\n",
"\n",
"$a$ - współczynnik kierunkowy naszej funkcji **regresji liniowej**\n",
"\n",
"$b$ - wyraz wolny"
]
},
{
"cell_type": "markdown",
"id": "05f37fe3-da73-46f3-b4b3-3cba82dbf546",
"metadata": {},
"source": [
"Powstaje pytanie jak wyznaczyć wartości $a$ i $b$. Istnieją algorytmy numeryczne, które pozwalają znaleźć przybliżone wartości. Jednym z nich jest tzw. algorytm gradientu prostego. Natomiast nie będziemy go w tym momencie omawiać.\n",
"\n",
"Na zajęciach ze statystyki będziecie Państwo (jeśli jeszcze nie mieliście statystyki) uczyć się jak wyznaczać te szukane wartości wg pewnych wzorów i teraz z nich skorzystamy:\n",
"\n",
"$a=\\frac{\\sum_{i=1}^{n}\\left ( x_{i}-\\overline{x} \\right )\\left ( y_{i}-\\overline{y} \\right )}{\\sum_{i=1}^{n}\\left ( x_{i}-\\overline{x} \\right )^{2}}$\n",
"\n",
"$b=\\overline{y}-a\\overline{x}$\n",
"\n",
"gdzie:\n",
"\n",
2023-10-18 12:53:38 +02:00
"$n$ - liczba punktów na naszym wykresie\n",
"\n",
2023-10-18 12:39:32 +02:00
"$(x_{i}, y_{i})$ to i-ty punkt na naszym wykresie\n",
"\n",
"$\\overline{x}$ to średnia arytmetyczna wszystkich argumentów z naszego wykresu (liczby rozwiązanych ćwiczeń)\n",
"\n",
"$\\overline{y}$ to średnia arytmetyczna wszystkich wartości z naszego wykresu (wyników w teście)"
]
},
{
"cell_type": "markdown",
"id": "efdfa37b-292f-45c1-b18a-605b426b495a",
"metadata": {},
"source": [
"Co do zasady te wzory będą (lub były) wyjaśniane na zajęciach ze statystyki, natomiast na ten moment powinna wystarczyć nam informacja, że wynikają one z faktu, że szukamy takiej funkcji, dla której różnice między obliczoną a rzeczywistą wartością są jak najmniejsze. Różnice te mogą być ujemne, dlatego bada się kwadraty różnic, żeby nie było sytuacji, że różnice pewnych wartości się wyzerują i przez to znajdziemy błędną funkcję regresji. Taką metodę nazywa się **metodą najmniejszych kwadratów** a same różnice nazywa się **resztami** lub **residuami**."
]
},
{
"cell_type": "markdown",
"id": "9c2ebd9c-3b53-470a-8f62-1099c128cf15",
"metadata": {},
"source": [
"Gdybyśmy dla naszych danych wyznaczyli zgodnie z powyższymi wzorami wartość funkcji regresji liniowej otrzymalibyśmy prostą jak na poniższym wykresie:\n",
"\n",
"![](wyniki_reglin.png)"
]
},
{
"cell_type": "markdown",
"id": "b8f03bcd-8ace-4d2e-8942-678e92dda4e4",
"metadata": {},
"source": [
"Można to interpretować następująco:\n",
"\n",
2023-10-18 12:56:34 +02:00
"- ponieważ wyraz wolny $b$ w przybliżeniu wynosi 11,94 to można powiedzieć, że jeśli uczeń nie rozwiąże ćwiczeń, to jego wynik na teście końcowym wyniesie właśnie ok. 12%;\n",
2023-10-18 12:39:32 +02:00
"- ponieważ współczynnik kierunkowy $a$ jest dodatni to oznacza, że wraz ze wzrostem liczby rozwiązanych ćwiczeń będzie rósł wynik na teście końcowym;\n",
2023-10-18 12:56:34 +02:00
"- ponieważ współczynnik kierunkowy $a$ wynosi ok. 4,89, oznacza to, że wraz z każdym kolejnym rozwiązanym ćwiczeniem wynik w teście końcowym wzrasta o ok. 4,89%.\n",
2023-10-18 12:39:32 +02:00
"\n",
"To, czy powyższe wnioski są w naszym problemie sensowne to inna sprawa. Regresja liniowa ma swoje plusy i minusy:\n",
"\n",
"### Zalety:\n",
"- Prostota dzięki swojej prostocie wykorzystywana jest w wielu dziedzinach: od matematyki, poprzez ekonomię, aż po geodezję,\n",
"- interpretowalność dzięki prostym wzorom bardzo łatwo wyjaśnić biznesowi lub innym osobom, jak dana cecha wpływa na wynik modelu,\n",
"- szybkość nawet przy dużej liczbie danych dla prostych algorytmów wyniki dostajemy prawie od razu.\n",
"\n",
"### Wady:\n",
"- Prostota (wcześniej zaleta ;P) świat nie składa się z prostych liniowych zależności. Gdyby tak było, to pewnie nie byłoby takiego rozwoju uczenia maszynowego.\n",
"\n"
]
},
2023-10-18 12:53:38 +02:00
{
"cell_type": "markdown",
"id": "f54542e5-d2c2-4192-8cbb-2d42737955f2",
"metadata": {},
"source": [
"<figure>\n",
" <img src=\"mem.png\">\n",
" <figcaption>https://xkcd.com/</figcaption>\n",
"</figure>"
]
},
{
"cell_type": "markdown",
"id": "56ca2bb6-eff7-4fe3-9d09-9e5955acc18e",
"metadata": {},
"source": [
"Oczywiście mamy więcej informacji niż liczba rozwiązanych ćwiczeń, więc można by było spróbować wyznaczyć funkcję wielu zmiennych, w której każdy ze składników byłby jakąś funkcją liniową. To już spróbujemy zrobić korzystając z możliwości języka Python i dostępnych dla niego bibliotek."
]
},
2023-10-18 12:56:34 +02:00
{
"cell_type": "markdown",
"id": "3b482f8e-e70e-4a61-a2a5-37d42cf9656b",
"metadata": {},
"source": [
"## Przykład kodu na regresję liniową"
]
},
2023-10-18 14:37:13 +02:00
{
"cell_type": "markdown",
"id": "1c1dd0af-74e4-4f7a-93bf-64a9d2be14c3",
"metadata": {},
"source": [
"Zaczynamy od importu pewnych bibliotek, które ułatwiają pracę z danymi i uruchamianie algorytmów uczenia maszynowego:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "74d886ec-b819-48fa-aac2-e69c6160287b",
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
" \n",
"from sklearn.linear_model import LinearRegression\n",
"from sklearn.metrics import mean_squared_error"
]
},
{
"cell_type": "markdown",
"id": "d9e1ee83-3b9d-439f-9aee-5ac095ded83a",
"metadata": {},
"source": [
"Wczytajmy dane i podejrzyjmy nasz zbiór danych:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "f1111528-20ce-4ed5-9c5a-511f2c1041d2",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>cwiczenia</th>\n",
" <th>czas_min</th>\n",
" <th>wejscia</th>\n",
" <th>nieodwiedzone</th>\n",
" <th>czas_do_testu_godziny</th>\n",
" <th>test</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>4</td>\n",
" <td>12</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>20</td>\n",
" <td>20.00</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>8</td>\n",
" <td>25</td>\n",
" <td>3</td>\n",
" <td>3</td>\n",
" <td>36</td>\n",
" <td>60.00</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>14</td>\n",
" <td>48</td>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>33</td>\n",
" <td>92.86</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>11</td>\n",
" <td>37</td>\n",
" <td>5</td>\n",
" <td>0</td>\n",
" <td>42</td>\n",
" <td>65.34</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>5</td>\n",
" <td>29</td>\n",
" <td>2</td>\n",
" <td>0</td>\n",
" <td>22</td>\n",
" <td>42.35</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>2</td>\n",
" <td>5</td>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" <td>5</td>\n",
" <td>13.14</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>16</td>\n",
" <td>36</td>\n",
" <td>7</td>\n",
" <td>1</td>\n",
" <td>47</td>\n",
" <td>85.13</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>18</td>\n",
" <td>55</td>\n",
" <td>5</td>\n",
" <td>0</td>\n",
" <td>39</td>\n",
" <td>98.33</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>20</td>\n",
" <td>48</td>\n",
" <td>4</td>\n",
" <td>0</td>\n",
" <td>45</td>\n",
" <td>100.00</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>10</td>\n",
" <td>42</td>\n",
" <td>7</td>\n",
" <td>1</td>\n",
" <td>37</td>\n",
" <td>70.00</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" cwiczenia czas_min wejscia nieodwiedzone czas_do_testu_godziny test\n",
"0 4 12 1 1 20 20.00\n",
"1 8 25 3 3 36 60.00\n",
"2 14 48 3 1 33 92.86\n",
"3 11 37 5 0 42 65.34\n",
"4 5 29 2 0 22 42.35\n",
"5 2 5 1 4 5 13.14\n",
"6 16 36 7 1 47 85.13\n",
"7 18 55 5 0 39 98.33\n",
"8 20 48 4 0 45 100.00\n",
"9 10 42 7 1 37 70.00"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data = pd.read_csv('data.csv', sep=';')\n",
"data"
]
},
{
"cell_type": "markdown",
"id": "2158a205-2c9e-41b9-9fe0-d56dd7b97213",
"metadata": {},
"source": [
"Teraz obliczamy podstawowy model regresji liniowej i wyliczamy błąd (czyli jak bardzo obliczone wartości funkcji regresji różnią się od tych rzeczywistych) - weźmy miarę RMSE (omówimy ją na późniejszych zajęciach - na razie zapamiętajmy: im niższy błąd tym lepiej):"
]
},
{
"cell_type": "code",
"execution_count": 36,
"id": "f7eade7c-def7-4944-8eea-7cba985e5bf5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Współczynnik a: 4.8869552414605435\n",
"Wyraz wolny: 11.935883392226131\n",
"Błąd: Root Mean Squared Error (RMSE): 8.27\n"
]
}
],
"source": [
"model = LinearRegression()\n",
" \n",
"X = data[['cwiczenia']]\n",
"y = data['test']\n",
" \n",
"model.fit(X,y, sample_weight=None)\n",
"y_pred = model.predict(X)\n",
" \n",
"print('Współczynnik a: ', model.coef_[0])\n",
"print('Wyraz wolny: ', model.intercept_)\n",
"print('Błąd: Root Mean Squared Error (RMSE): %.2f'% np.sqrt(mean_squared_error(y, y_pred)))\n"
]
},
{
"cell_type": "markdown",
"id": "04bf6923-da81-40ca-96bd-33f1ad973ddc",
"metadata": {},
"source": [
"A co by było jakbyśmy wzięli dodatkowo pod uwagę czas spędzony w kursie:"
]
},
{
"cell_type": "code",
"execution_count": 48,
"id": "2b232e81-9d0e-4817-ac0a-5f7b1d293666",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Współczynnik przy argumencie \"cwiczenia\": 2.793448759670846\n",
"Współczynnik przy argumencie \"czas_min\": 0.9017691542564438\n",
"Wyraz wolny: 4.156132897112705\n",
"Błąd: Root Mean Squared Error (RMSE): 5.19\n"
]
}
],
"source": [
"X = data[['cwiczenia', 'czas_min']]\n",
"y = data['test']\n",
" \n",
"model.fit(X,y, sample_weight=None)\n",
"y_pred = model.predict(X)\n",
" \n",
"print('Współczynnik przy argumencie \"cwiczenia\": ', model.coef_[0])\n",
"print('Współczynnik przy argumencie \"czas_min\": ', model.coef_[1])\n",
"print('Wyraz wolny: ', model.intercept_)\n",
"print('Błąd: Root Mean Squared Error (RMSE): %.2f'% np.sqrt(mean_squared_error(y, y_pred)))\n"
]
},
{
"cell_type": "markdown",
"id": "e49fa078-6216-4d83-bbbd-db0b58aa7c8e",
"metadata": {},
"source": [
"Mamy lepszy wynik - błąd jest niższy :)"
]
},
{
"cell_type": "markdown",
"id": "d501bcc0-d3bf-4552-bf2b-c78753b4d5d6",
"metadata": {},
"source": [
"A jak wyglądają nasze wyznaczone wartości funkcji regresji?"
]
},
{
"cell_type": "code",
"execution_count": 49,
"id": "e539d645-86c6-42c0-9059-7a3c310cc2a3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 26.15115779, 49.04795183, 86.54933494, 68.24952796,\n",
" 44.27468217, 14.25187619, 81.31500261, 104.03551406,\n",
" 103.31002749, 69.96492497])"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data_with_y_pred = data.copy()\n",
"data_with_y_pred['y_pred'] = y_pred\n",
"data_with_y_pred\n",
"y_pred"
]
},
{
"cell_type": "markdown",
"id": "7ea9c2cb-b654-4190-9e4f-972e4d3bf92f",
"metadata": {},
"source": [
"## Zadanie 1.\n",
"\n",
"Dla całego zbioru danych oblicz sumę kwadratów róźnic pomiędzy kolumnami **test** i **y_pred**. Wynik zaokrąglij do dwóch miejsc po przecinku (pamiętaj, że od 5 zaokrąglamy w górę). Podpowiedź:"
]
},
{
"cell_type": "markdown",
"id": "90d8f306-e823-4552-8f41-6aac1ee37611",
"metadata": {},
"source": [
"- `data_with_y_pred['nazwa_kolumny'].size` - liczba elementów (wierszy) w danej kolumnie\n",
"\n",
"- `data_with_y_pred['nazwa_kolumny'][0]` - pierwszy (indeksujemy od zera) element (wiersz) kolumny"
]
},
{
"cell_type": "markdown",
"id": "8d9c213b-5758-409b-a73d-1012a3709032",
"metadata": {},
"source": [
"Konkretne zadanie: napisz funkcję o nazwie `fun1()`, która zwróci oczekiwany wynik. Kod tej funkcji wklej na Moodle'u w aktywności o nazwie **Regresja liniowa - zadanie 1**. Na Moodle'u poza powyższym zbiorem danych kod będzie sprawdzony na innym zbiorze danych, więc nie można napisać prostej funkcji, która zwróci wartość obliczoną np. na kartce - niestety trzeba napisać funkcję obliczającą poszukiwaną wartość ;)"
]
},
2023-10-18 11:29:12 +02:00
{
"cell_type": "code",
"execution_count": null,
2023-10-18 14:37:13 +02:00
"id": "7d1a8edd-0a16-4504-8383-1e9240504306",
2023-10-18 11:29:12 +02:00
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}