{ "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-04T01:39:34+00:00", "source_file": "2-Regression/2-Data/solution/R/lesson_2-R.ipynb", "language_code": "ja" } }, "cells": [ { "cell_type": "markdown", "source": [ "# 回帰モデルの構築: データの準備と可視化\n", "\n", "## **カボチャの線形回帰 - レッスン2**\n", "#### はじめに\n", "\n", "TidymodelsとTidyverseを使って機械学習モデルの構築を始める準備が整った今、データに対して質問を投げかける準備ができました。データを扱い、機械学習のソリューションを適用する際には、適切な質問をすることでデータセットの可能性を最大限に引き出すことが非常に重要です。\n", "\n", "このレッスンでは以下を学びます:\n", "\n", "- モデル構築のためのデータ準備方法。\n", "\n", "- `ggplot2`を使ったデータの可視化方法。\n", "\n", "解きたい質問によって使用する機械学習アルゴリズムの種類が決まります。そして、得られる答えの質はデータの性質に大きく依存します。\n", "\n", "これを実際の演習を通じて確認してみましょう。\n", "\n", "\n", "
\n",
" \n",
"
\n",
"\n",
"> おさらい: パイプ演算子(`%>%`)は、オブジェクトを関数や呼び出し式に順次渡すことで、論理的な順序で操作を実行します。コード内でパイプ演算子は「そして次に」と言っているようなものだと考えることができます。\n"
],
"metadata": {
"id": "REWcIv9yX29v"
}
},
{
"cell_type": "markdown",
"source": [
"## 2. データの欠損を確認する\n",
"\n",
"データサイエンティストがよく直面する問題の一つに、不完全または欠損しているデータがあります。Rでは、欠損値や不明な値を特別なセントネル値 `NA` (Not Available) で表します。\n",
"\n",
"では、データフレームに欠損値が含まれているかどうかをどうやって確認するのでしょうか?\n",
"
\n",
"- 一つの簡単な方法は、ベースRの関数 `anyNA` を使用することです。この関数は論理オブジェクト `TRUE` または `FALSE` を返します。\n"
],
"metadata": {
"id": "Zxfb3AM5YbUe"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" anyNA()"
],
"outputs": [],
"metadata": {
"id": "G--DQutAYltj"
}
},
{
"cell_type": "markdown",
"source": [
"素晴らしいですね、いくつかのデータが欠けているようです!そこから始めるのが良いでしょう。\n",
"\n",
"- 別の方法として、`is.na()`関数を使用することができます。この関数は、各列の要素が欠けているかどうかを論理値`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": [
"大きなデータフレームの場合、このようにすべての行と列を個別に確認するのは非効率的で、実質的に不可能です😴。\n",
"\n",
"- より直感的な方法としては、各列の欠損値の合計を計算することです:\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": [
"データが欠けている部分はありますが、今回の作業には影響がないかもしれません。さらに分析を進めてみましょう。\n",
"\n",
"> 素晴らしいパッケージや関数のセットに加えて、Rには非常に優れたドキュメントがあります。例えば、`help(colSums)` または `?colSums` を使用して、その関数について詳しく調べることができます。\n"
],
"metadata": {
"id": "9gv-crB6ZD1Y"
}
},
{
"cell_type": "markdown",
"source": [
"## 3. Dplyr: データ操作の文法\n",
"\n",
"
\n",
" \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": [
"イエス!💪\n",
"\n",
"「でも待って!」と、`View(pumpkins)`でデータセット全体をざっと見た後に言うかもしれません。「ここ、何かおかしくない?」🤔\n",
"\n",
"`Package`列を見てみると、カボチャはさまざまな形態で販売されていることがわかります。一部は`1 1/9 bushel`の単位で、一部は`1/2 bushel`の単位で、一部はカボチャ1個ごと、一部はポンドごと、さらに幅の異なる大きな箱で販売されているものもあります。\n",
"\n",
"これを確認してみましょう:\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": [
"素晴らしいですね!👏\n",
"\n",
"カボチャは一貫して重さを測るのが非常に難しいようですので、`Package`列に*bushel*という文字列が含まれるカボチャだけを選択し、新しいデータフレーム`new_pumpkins`に入れましょう。\n"
],
"metadata": {
"id": "7sMjiVujaZxY"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::filter() と stringr::str_detect()\n",
"\n",
"[`dplyr::filter()`](https://dplyr.tidyverse.org/reference/filter.html): 条件を満たす**行**のみを含むデータのサブセットを作成します。この場合、`Package`列に文字列 *bushel* を含むかどうかでカボチャをフィルタリングします。\n",
"\n",
"[stringr::str_detect()](https://stringr.tidyverse.org/reference/str_detect.html): 文字列内で特定のパターンが存在するかどうかを検出します。\n",
"\n",
"[`stringr`](https://github.com/tidyverse/stringr) パッケージは、一般的な文字列操作を簡単に行うための関数を提供します。\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": [
"私たちは、バスケット単位でカボチャを含む約415行のデータに絞り込んだことがわかります。🤩 \n",
"
\n"
],
"metadata": {
"id": "VrDwF031avlR"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::case_when()\n",
"\n",
"**でも、もう一つやるべきことがあります**\n",
"\n",
"バスケットの量が行ごとに異なることに気づきましたか?価格を1 1/9や1/2バスケットではなく、1バスケットあたりの価格として正規化する必要があります。標準化するために少し計算をしましょう。\n",
"\n",
"[`case_when()`](https://dplyr.tidyverse.org/reference/case_when.html) 関数を使って、条件に応じてPrice列を*変換*します。`case_when`を使うと、複数の`if_else()`ステートメントをベクトル化することができます。\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": [
"さて、私たちはバスケット単位での価格分析を行うことができます。しかし、このカボチャのバスケットに関する研究は、「データの性質を理解すること」がいかに`重要`であるかを示しています!\n",
"\n",
"> ✅ [The Spruce Eats](https://www.thespruceeats.com/how-much-is-a-bushel-1389308)によると、バスケットの重さはその中身の種類によって異なります。これは体積の測定方法だからです。「例えば、トマトのバスケットは56ポンドの重さがあるとされています... 葉物や緑の野菜はスペースを多く取り、重さが少ないため、ほうれん草のバスケットはたった20ポンドです。」かなり複雑ですね!バスケットからポンドへの換算はやめて、バスケット単位で価格を設定しましょう。このカボチャのバスケットに関する研究は、データの性質を理解することがいかに重要であるかを示しています!\n",
"\n",
"> ✅ 半バスケット単位で販売されているカボチャが非常に高価であることに気づきましたか?その理由を考えられますか?ヒント:小さなカボチャは大きなカボチャよりもずっと高価です。おそらく、大きな空洞のあるパイ用カボチャが1つ占めるスペースに比べて、小さなカボチャがバスケットにたくさん詰め込まれるためでしょう。\n"
],
"metadata": {
"id": "pS2GNPagbSdb"
}
},
{
"cell_type": "markdown",
"source": [
"さて、最後に、ちょっとした冒険のために 💁♀️、Month列を最初の位置、つまり`Package`列の「前」に移動させましょう。\n",
"\n",
"列の位置を変更するには、`dplyr::relocate()`を使用します。\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": [
"よくできました!👌 これで、新しい回帰モデルを構築するためのクリーンで整然としたデータセットが手に入りましたね! \n",
"
\n"
],
"metadata": {
"id": "y8TJ0Za_bn5Y"
}
},
{
"cell_type": "markdown",
"source": [
"## 4. ggplot2を使ったデータ可視化\n",
"\n",
"
\n",
" \n",
"
\n"
],
"metadata": {
"id": "Ml7SDCLQcPvE"
}
},
{
"cell_type": "markdown",
"source": [
"### **どうすれば役立つものにできるのか?**\n",
"\n",
"チャートに有益なデータを表示させるには、通常データを何らかの方法でグループ化する必要があります。例えば、私たちの場合、各月ごとのカボチャの平均価格を見つけることで、データの基礎的なパターンについてより深い洞察を得ることができます。このことから、もう一つの**dplyr**の便利な機能にたどり着きます:\n",
"\n",
"#### `dplyr::group_by() %>% summarize()`\n",
"\n",
"Rでのグループ化集計は以下の方法で簡単に計算できます:\n",
"\n",
"`dplyr::group_by() %>% summarize()`\n",
"\n",
"- `dplyr::group_by()`は、分析単位をデータセット全体から月ごとなどの個別のグループに変更します。\n",
"\n",
"- `dplyr::summarize()`は、グループ化変数ごとに1つの列、指定した集計統計ごとに1つの列を持つ新しいデータフレームを作成します。\n",
"\n",
"例えば、`dplyr::group_by() %>% summarize()`を使用して、**Month**列に基づいてカボチャをグループ化し、各月の**平均価格**を求めることができます。\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": [
"簡潔に!✨\n",
"\n",
"月のようなカテゴリカルな特徴は、棒グラフ📊で表現するのが適しています。棒グラフを作成するためのレイヤーは `geom_bar()` と `geom_col()` です。詳細を知りたい場合は `?geom_bar` を参照してください。\n",
"\n",
"さあ、作ってみましょう!\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": [
"🤩🤩これは、より役立つデータビジュアライゼーションですね!9月と10月にカボチャの価格が最も高くなることを示しているようです。これはあなたの予想に合っていますか?なぜそう思いますか、またはなぜそうではないですか?\n",
"\n",
"第2レッスンの完了、おめでとうございます👏!データをモデル構築のために準備し、その後、ビジュアライゼーションを使ってさらに多くの洞察を得ることができましたね!\n"
],
"metadata": {
"id": "zDm0VOzzcuzR"
}
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**免責事項**: \nこの文書はAI翻訳サービス[Co-op Translator](https://github.com/Azure/co-op-translator)を使用して翻訳されています。正確性を追求しておりますが、自動翻訳には誤りや不正確な部分が含まれる可能性があります。元の言語で記載された文書が正式な情報源とみなされるべきです。重要な情報については、専門の人間による翻訳を推奨します。この翻訳の使用に起因する誤解や誤解釈について、当社は責任を負いません。\n"
]
}
]
}