{ "nbformat": 4, "nbformat_minor": 2, "metadata": { "colab": { "name": "lesson_2-R.ipynb", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "f3c335f9940cfd76528b3ef918b9b342", "translation_date": "2025-09-04T07:18:51+00:00", "source_file": "2-Regression/2-Data/solution/R/lesson_2-R.ipynb", "language_code": "fi" } }, "cells": [ { "cell_type": "markdown", "source": [ "# Rakenna regressiomalli: valmistele ja visualisoi data\n", "\n", "## **Lineaarinen regressio kurpitsoille - Oppitunti 2**\n", "#### Johdanto\n", "\n", "Nyt kun sinulla on käytössäsi työkalut koneoppimismallien rakentamiseen Tidymodelsin ja Tidyversen avulla, olet valmis aloittamaan kysymysten esittämisen datallesi. Kun työskentelet datan kanssa ja sovellat koneoppimisratkaisuja, on erittäin tärkeää ymmärtää, miten esittää oikea kysymys, jotta voit hyödyntää datasettiäsi parhaalla mahdollisella tavalla.\n", "\n", "Tässä oppitunnissa opit:\n", "\n", "- Kuinka valmistella data mallin rakentamista varten.\n", "\n", "- Kuinka käyttää `ggplot2`:ta datan visualisointiin.\n", "\n", "Kysymys, johon tarvitset vastauksen, määrittää, millaisia koneoppimisalgoritmeja käytät. Ja saamasi vastauksen laatu riippuu vahvasti datasi luonteesta.\n", "\n", "Katsotaanpa tätä käytännön harjoituksen avulla.\n", "\n", "
\n",
" \n",
"
\n",
"\n",
"> Kertauksena: Pipe-operaattori (`%>%`) suorittaa operaatioita loogisessa järjestyksessä siirtämällä objektin eteenpäin funktioon tai kutsulausekkeeseen. Voit ajatella pipe-operaattorin tarkoittavan koodissasi \"ja sitten\".\n"
],
"metadata": {
"id": "REWcIv9yX29v"
}
},
{
"cell_type": "markdown",
"source": [
"## 2. Tarkista puuttuvat tiedot\n",
"\n",
"Yksi yleisimmistä ongelmista, joita datatieteilijät kohtaavat, on puutteelliset tai puuttuvat tiedot. R edustaa puuttuvia tai tuntemattomia arvoja erityisellä tunnusarvolla: `NA` (Not Available).\n",
"\n",
"Miten voisimme tietää, että data frame sisältää puuttuvia arvoja?\n",
"
\n",
"- Yksi suoraviivainen tapa olisi käyttää R:n perustoimintoa `anyNA`, joka palauttaa loogiset objektit `TRUE` tai `FALSE`.\n"
],
"metadata": {
"id": "Zxfb3AM5YbUe"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" anyNA()"
],
"outputs": [],
"metadata": {
"id": "G--DQutAYltj"
}
},
{
"cell_type": "markdown",
"source": [
"Hienoa, näyttää siltä, että joitakin tietoja puuttuu! Se on hyvä paikka aloittaa.\n",
"\n",
"- Toinen tapa olisi käyttää funktiota `is.na()`, joka osoittaa, mitkä yksittäiset sarake-elementit puuttuvat loogisella arvolla `TRUE`.\n"
],
"metadata": {
"id": "mU-7-SB6YokF"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" is.na() %>% \n",
" head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "W-DxDOR4YxSW"
}
},
{
"cell_type": "markdown",
"source": [
"Okei, tehtävä hoidettu, mutta näin suuren tietokehyksen kohdalla olisi tehotonta ja käytännössä mahdotonta käydä läpi kaikkia rivejä ja sarakkeita yksitellen😴.\n",
"\n",
"- Intuitiivisempi tapa olisi laskea puuttuvien arvojen summa kullekin sarakkeelle:\n"
],
"metadata": {
"id": "xUWxipKYY0o7"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" is.na() %>% \n",
" colSums()"
],
"outputs": [],
"metadata": {
"id": "ZRBWV6P9ZArL"
}
},
{
"cell_type": "markdown",
"source": [
"Paljon parempi! Joitakin tietoja puuttuu, mutta ehkä sillä ei ole merkitystä tehtävän kannalta. Katsotaan, mitä lisäanalyysi tuo tullessaan.\n",
"\n",
"> R:llä on erinomainen dokumentaatio mahtavien pakettien ja funktioiden lisäksi. Esimerkiksi, käytä `help(colSums)` tai `?colSums` saadaksesi lisätietoja funktiosta.\n"
],
"metadata": {
"id": "9gv-crB6ZD1Y"
}
},
{
"cell_type": "markdown",
"source": [
"## 3. Dplyr: Tiedon käsittelyn kielioppi\n",
"\n",
"
\n",
" \n",
"
\n"
],
"metadata": {
"id": "i5o33MQBZWWw"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::select()\n",
"\n",
"`select()` on `dplyr`-paketin funktio, joka auttaa valitsemaan sarakkeita säilytettäväksi tai poistettavaksi.\n",
"\n",
"Jotta tietokehystäsi olisi helpompi käsitellä, poista useita sen sarakkeita käyttämällä `select()`-funktiota ja säilytä vain tarvitsemasi sarakkeet.\n",
"\n",
"Esimerkiksi tässä harjoituksessa analyysimme keskittyy sarakkeisiin `Package`, `Low Price`, `High Price` ja `Date`. Valitaan nämä sarakkeet.\n"
],
"metadata": {
"id": "x3VGMAGBZiUr"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Select desired columns\n",
"pumpkins <- pumpkins %>% \n",
" select(Package, `Low Price`, `High Price`, Date)\n",
"\n",
"\n",
"# Print data set\n",
"pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "F_FgxQnVZnM0"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::mutate()\n",
"\n",
"`mutate()` on `dplyr`-paketin funktio, joka auttaa luomaan tai muokkaamaan sarakkeita säilyttäen olemassa olevat sarakkeet.\n",
"\n",
"`mutate`-funktion yleinen rakenne on:\n",
"\n",
"`data %>% mutate(new_column_name = what_it_contains)`\n",
"\n",
"Kokeillaan `mutate`-funktiota käyttämällä `Date`-saraketta ja tehdään seuraavat toimenpiteet:\n",
"\n",
"1. Muutetaan päivämäärät (jotka ovat tällä hetkellä merkkijonoja) kuukausimuotoon (nämä ovat Yhdysvaltain päivämääriä, joten muoto on `MM/DD/YYYY`).\n",
"\n",
"2. Poimitaan kuukausi päivämääristä uuteen sarakkeeseen.\n",
"\n",
"R:ssä [lubridate](https://lubridate.tidyverse.org/)-paketti helpottaa päivämäärä- ja aikadatan käsittelyä. Käytetään siis `dplyr::mutate()`, `lubridate::mdy()`, `lubridate::month()` ja katsotaan, miten yllä olevat tavoitteet saavutetaan. Voimme poistaa Date-sarakkeen, koska emme tarvitse sitä enää myöhemmissä toimenpiteissä.\n"
],
"metadata": {
"id": "2KKo0Ed9Z1VB"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Load lubridate\n",
"library(lubridate)\n",
"\n",
"pumpkins <- pumpkins %>% \n",
" # Convert the Date column to a date object\n",
" mutate(Date = mdy(Date)) %>% \n",
" # Extract month from Date\n",
" mutate(Month = month(Date)) %>% \n",
" # Drop Date column\n",
" select(-Date)\n",
"\n",
"# View the first few rows\n",
"pumpkins %>% \n",
" slice_head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "5joszIVSZ6xe"
}
},
{
"cell_type": "markdown",
"source": [
"Jee! 🤩\n",
"\n",
"Seuraavaksi luodaan uusi sarake `Price`, joka edustaa kurpitsan keskimääräistä hintaa. Lasketaan nyt `Low Price`- ja `High Price` -sarakkeiden keskiarvo, jotta saadaan täytettyä uusi Price-sarake.\n",
"
\n"
],
"metadata": {
"id": "nIgLjNMCZ-6Y"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Create a new column Price\n",
"pumpkins <- pumpkins %>% \n",
" mutate(Price = (`Low Price` + `High Price`)/2)\n",
"\n",
"# View the first few rows of the data\n",
"pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "Zo0BsqqtaJw2"
}
},
{
"cell_type": "markdown",
"source": [
"Jep!💪\n",
"\n",
"\"Mutta hetkinen!\", sanot selailtuasi koko aineiston `View(pumpkins)`-komennolla, \"Tässä on jotain outoa!\"🤔\n",
"\n",
"Jos katsot `Package`-saraketta, kurpitsat myydään monissa eri muodoissa. Joitakin myydään `1 1/9 bushel` -yksiköissä, toisia `1/2 bushel` -yksiköissä, joitakin kappaleittain, joitakin painon mukaan ja joitakin suurissa laatikoissa, joiden leveydet vaihtelevat.\n",
"\n",
"Varmistetaan tämä:\n"
],
"metadata": {
"id": "p77WZr-9aQAR"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Verify the distinct observations in Package column\n",
"pumpkins %>% \n",
" distinct(Package)"
],
"outputs": [],
"metadata": {
"id": "XISGfh0IaUy6"
}
},
{
"cell_type": "markdown",
"source": [
"Upeaa!👏\n",
"\n",
"Kurpitsojen punnitseminen tasaisesti näyttää olevan todella haastavaa, joten suodatetaan niitä valitsemalla vain kurpitsat, joiden `Package`-sarakkeessa on merkkijono *bushel*, ja tallennetaan tämä uuteen tietokehykseen `new_pumpkins`.\n"
],
"metadata": {
"id": "7sMjiVujaZxY"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::filter() ja stringr::str_detect()\n",
"\n",
"[`dplyr::filter()`](https://dplyr.tidyverse.org/reference/filter.html): luo datasta alijoukon, joka sisältää vain **rivit**, jotka täyttävät ehtosi, tässä tapauksessa kurpitsat, joiden `Package`-sarake sisältää merkkijonon *bushel*.\n",
"\n",
"[stringr::str_detect()](https://stringr.tidyverse.org/reference/str_detect.html): tunnistaa, esiintyykö jokin kuvio merkkijonossa vai ei.\n",
"\n",
"[`stringr`](https://github.com/tidyverse/stringr)-paketti tarjoaa yksinkertaisia funktioita yleisiin merkkijono-operaatioihin.\n"
],
"metadata": {
"id": "L8Qfcs92ageF"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Retain only pumpkins with \"bushel\"\n",
"new_pumpkins <- pumpkins %>% \n",
" filter(str_detect(Package, \"bushel\"))\n",
"\n",
"# Get the dimensions of the new data\n",
"dim(new_pumpkins)\n",
"\n",
"# View a few rows of the new data\n",
"new_pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "hy_SGYREampd"
}
},
{
"cell_type": "markdown",
"source": [
"Voit nähdä, että olemme rajanneet noin 415 riviin dataa, joka sisältää kurpitsoja tynnyrillisinä.🤩 \n",
"
\n"
],
"metadata": {
"id": "VrDwF031avlR"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::case_when()\n",
"\n",
"**Mutta odota! Vielä yksi asia tehtävänä**\n",
"\n",
"Huomasitko, että korimäärä vaihtelee rivikohtaisesti? Sinun täytyy normalisoida hinnoittelu niin, että näytät hinnan per kori, ei per 1 1/9 tai 1/2 kori. On aika tehdä hieman matematiikkaa standardisoinnin vuoksi.\n",
"\n",
"Käytämme funktiota [`case_when()`](https://dplyr.tidyverse.org/reference/case_when.html) *muuttaaksemme* Price-saraketta tiettyjen ehtojen mukaan. `case_when` mahdollistaa useiden `if_else()`-lauseiden vektorisoinnin.\n"
],
"metadata": {
"id": "mLpw2jH4a0tx"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Convert the price if the Package contains fractional bushel values\n",
"new_pumpkins <- new_pumpkins %>% \n",
" mutate(Price = case_when(\n",
" str_detect(Package, \"1 1/9\") ~ Price/(1 + 1/9),\n",
" str_detect(Package, \"1/2\") ~ Price/(1/2),\n",
" TRUE ~ Price))\n",
"\n",
"# View the first few rows of the data\n",
"new_pumpkins %>% \n",
" slice_head(n = 30)"
],
"outputs": [],
"metadata": {
"id": "P68kLVQmbM6I"
}
},
{
"cell_type": "markdown",
"source": [
"Nyt voimme analysoida yksikköhinnan perustuen niiden mittaukseen bushel-mitoilla. Kaikki tämä kurpitsabushelien tutkiminen kuitenkin osoittaa, kuinka `tärkeää` on `ymmärtää datasi luonne`!\n",
"\n",
"> ✅ [The Spruce Eats](https://www.thespruceeats.com/how-much-is-a-bushel-1389308) -sivuston mukaan bushelin paino riippuu tuotteen tyypistä, koska se on tilavuusmitta. \"Esimerkiksi tomaattibushelin pitäisi painaa 56 paunaa... Lehdet ja vihreät vievät enemmän tilaa mutta painavat vähemmän, joten pinaattibushel painaa vain 20 paunaa.\" Tämä on aika monimutkaista! Ei vaivauduta tekemään bushelista paunoihin -muunnosta, vaan hinnoitellaan bushelin mukaan. Kaikki tämä kurpitsabushelien tutkiminen kuitenkin osoittaa, kuinka tärkeää on ymmärtää datasi luonne!\n",
">\n",
"> ✅ Huomasitko, että puolibushelilla myydyt kurpitsat ovat todella kalliita? Voitko selvittää miksi? Vinkki: pienet kurpitsat ovat paljon kalliimpia kuin isot, luultavasti siksi, että niitä on bushelissa paljon enemmän, kun yksi iso ontto piirakkakurpitsa vie käyttämätöntä tilaa.\n"
],
"metadata": {
"id": "pS2GNPagbSdb"
}
},
{
"cell_type": "markdown",
"source": [
"Nyt viimeiseksi, seikkailun vuoksi 💁♀️, siirretään Kuukausi-sarake ensimmäiseksi eli `ennen` saraketta `Paketti`.\n",
"\n",
"`dplyr::relocate()` -funktiota käytetään sarakkeiden sijainnin muuttamiseen.\n"
],
"metadata": {
"id": "qql1SowfbdnP"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Create a new data frame new_pumpkins\n",
"new_pumpkins <- new_pumpkins %>% \n",
" relocate(Month, .before = Package)\n",
"\n",
"new_pumpkins %>% \n",
" slice_head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "JJ1x6kw8bixF"
}
},
{
"cell_type": "markdown",
"source": [
"Hyvää työtä!👌 Sinulla on nyt siisti ja järjestelmällinen aineisto, jonka pohjalta voit rakentaa uuden regressiomallisi!\n",
"
\n"
],
"metadata": {
"id": "y8TJ0Za_bn5Y"
}
},
{
"cell_type": "markdown",
"source": [
"## 4. Datavisualisointi ggplot2:lla\n",
"\n",
"
\n",
" \n",
"
\n"
],
"metadata": {
"id": "Ml7SDCLQcPvE"
}
},
{
"cell_type": "markdown",
"source": [
"### **Kuinka teemme siitä hyödyllisen?**\n",
"\n",
"Jotta kaaviot näyttäisivät hyödyllistä dataa, sinun täytyy yleensä ryhmitellä data jollain tavalla. Esimerkiksi meidän tapauksessamme, keskimääräisen kurpitsan hinnan löytäminen kuukausittain antaisi enemmän tietoa datamme taustalla olevista kuvioista. Tämä johdattaa meidät yhteen **dplyr**-pikakatsaukseen:\n",
"\n",
"#### `dplyr::group_by() %>% summarize()`\n",
"\n",
"R:ssä ryhmitelty aggregointi voidaan helposti laskea käyttämällä\n",
"\n",
"`dplyr::group_by() %>% summarize()`\n",
"\n",
"- `dplyr::group_by()` muuttaa analyysin yksikön koko datasetistä yksittäisiin ryhmiin, kuten kuukausittain.\n",
"\n",
"- `dplyr::summarize()` luo uuden dataframen, jossa on yksi sarake kutakin ryhmittelymuuttujaa varten ja yksi sarake kutakin määrittelemääsi yhteenvetotilastoa varten.\n",
"\n",
"Esimerkiksi voimme käyttää `dplyr::group_by() %>% summarize()` ryhmitelläksemme kurpitsat **Kuukausi**-sarakkeen perusteella ja sitten laskea **keskimääräisen hinnan** kullekin kuukaudelle.\n"
],
"metadata": {
"id": "jMakvJZIcVkh"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Find the average price of pumpkins per month\r\n",
"new_pumpkins %>%\r\n",
" group_by(Month) %>% \r\n",
" summarise(mean_price = mean(Price))"
],
"outputs": [],
"metadata": {
"id": "6kVSUa2Bcilf"
}
},
{
"cell_type": "markdown",
"source": [
"Ytimekkäästi!✨\n",
"\n",
"Kategoriset ominaisuudet, kuten kuukaudet, esitetään paremmin pylväsdiagrammin avulla 📊. Pylväsdiagrammeista vastaavat kerrokset ovat `geom_bar()` ja `geom_col()`. Katso `?geom_bar` saadaksesi lisätietoja.\n",
"\n",
"Tehdään yksi!\n"
],
"metadata": {
"id": "Kds48GUBcj3W"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Find the average price of pumpkins per month then plot a bar chart\r\n",
"new_pumpkins %>%\r\n",
" group_by(Month) %>% \r\n",
" summarise(mean_price = mean(Price)) %>% \r\n",
" ggplot(aes(x = Month, y = mean_price)) +\r\n",
" geom_col(fill = \"midnightblue\", alpha = 0.7) +\r\n",
" ylab(\"Pumpkin Price\")"
],
"outputs": [],
"metadata": {
"id": "VNbU1S3BcrxO"
}
},
{
"cell_type": "markdown",
"source": [
"🤩🤩Tämä on hyödyllisempi datavisualisointi! Näyttää siltä, että kurpitsojen korkein hinta esiintyy syys- ja lokakuussa. Vastaako tämä odotuksiasi? Miksi tai miksi ei?\n",
"\n",
"Onnittelut toisen oppitunnin suorittamisesta 👏! Valmistelit datasi mallin rakentamista varten ja löysit lisää oivalluksia visualisointien avulla!\n"
],
"metadata": {
"id": "zDm0VOzzcuzR"
}
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Vastuuvapauslauseke**: \nTämä asiakirja on käännetty käyttämällä tekoälypohjaista käännöspalvelua [Co-op Translator](https://github.com/Azure/co-op-translator). Pyrimme tarkkuuteen, mutta huomioithan, että automaattiset käännökset voivat sisältää virheitä tai epätarkkuuksia. Alkuperäistä asiakirjaa sen alkuperäisellä kielellä tulee pitää ensisijaisena lähteenä. Kriittisen tiedon osalta suositellaan ammattimaista ihmiskääntämistä. Emme ole vastuussa väärinkäsityksistä tai virhetulkinnoista, jotka johtuvat tämän käännöksen käytöstä.\n"
]
}
]
}