{ "nbformat": 4, "nbformat_minor": 2, "metadata": { "colab": { "name": "lesson_1-R.ipynb", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "c18d3bd0bd8ae3878597e89dcd1fa5c1", "translation_date": "2025-09-04T01:32:04+00:00", "source_file": "2-Regression/1-Tools/solution/R/lesson_1-R.ipynb", "language_code": "ja" } }, "cells": [ { "cell_type": "markdown", "source": [], "metadata": { "id": "YJUHCXqK57yz" } }, { "cell_type": "markdown", "source": [ "## 回帰の入門 - レッスン1\n", "\n", "#### 視点を広げてみよう\n", "\n", "✅ 回帰にはさまざまな方法があり、どの方法を選ぶかは求めている答えによります。たとえば、特定の年齢の人の身長を予測したい場合は、**数値的な値**を求めているので `線形回帰` を使用します。一方、ある料理がビーガン料理と見なされるべきかどうかを知りたい場合は、**カテゴリの割り当て**を求めているので `ロジスティック回帰` を使用します。ロジスティック回帰については後ほど学びます。データに対してどのような質問ができるか、そしてこれらの方法のどれが適切かを少し考えてみてください。\n", "\n", "このセクションでは、[糖尿病に関する小さなデータセット](https://www4.stat.ncsu.edu/~boos/var.select/diabetes.html)を使用します。糖尿病患者に対する治療をテストしたいと想像してみてください。機械学習モデルは、変数の組み合わせに基づいて、どの患者が治療により良く反応するかを判断するのに役立つかもしれません。非常に基本的な回帰モデルであっても、視覚化することで、理論的な臨床試験を整理するのに役立つ変数に関する情報を示すことができます。\n", "\n", "それでは、このタスクに取り組んでみましょう!\n", "\n", "

\n", " \n", "

イラスト: @allison_horst
\n", "\n", "\n" ], "metadata": { "id": "LWNNzfqd6feZ" } }, { "cell_type": "markdown", "source": [ "## 1. ツールセットの準備\n", "\n", "このタスクでは、以下のパッケージが必要です:\n", "\n", "- `tidyverse`: [tidyverse](https://www.tidyverse.org/) は、データサイエンスをより速く、簡単で楽しいものにするために設計された[Rパッケージのコレクション](https://www.tidyverse.org/packages)です。\n", "\n", "- `tidymodels`: [tidymodels](https://www.tidymodels.org/) フレームワークは、モデリングと機械学習のための[パッケージのコレクション](https://www.tidymodels.org/packages/)です。\n", "\n", "以下のコマンドでインストールできます:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\"))`\n", "\n", "以下のスクリプトは、このモジュールを完了するために必要なパッケージがインストールされているかを確認し、足りない場合は自動的にインストールします。\n" ], "metadata": { "id": "FIo2YhO26wI9" } }, { "cell_type": "code", "execution_count": 2, "source": [ "suppressWarnings(if(!require(\"pacman\")) install.packages(\"pacman\"))\n", "pacman::p_load(tidyverse, tidymodels)" ], "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "Loading required package: pacman\n", "\n" ] } ], "metadata": { "id": "cIA9fz9v7Dss", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "2df7073b-86b2-4b32-cb86-0da605a0dc11" } }, { "cell_type": "markdown", "source": [ "では、これらの素晴らしいパッケージを読み込み、現在のRセッションで利用可能にしましょう。(これは単なる例示のためであり、`pacman::p_load()`はすでにそれを行っています)\n" ], "metadata": { "id": "gpO_P_6f9WUG" } }, { "cell_type": "code", "execution_count": null, "source": [ "# load the core Tidyverse packages\r\n", "library(tidyverse)\r\n", "\r\n", "# load the core Tidymodels packages\r\n", "library(tidymodels)\r\n" ], "outputs": [], "metadata": { "id": "NLMycgG-9ezO" } }, { "cell_type": "markdown", "source": [ "## 2. 糖尿病データセット\n", "\n", "この演習では、糖尿病データセットを使って回帰スキルを活用し、予測を行います。[糖尿病データセット](https://www4.stat.ncsu.edu/~boos/var.select/diabetes.rwrite1.txt)には、糖尿病に関する`442件のサンプル`が含まれており、10個の予測変数(`年齢`、`性別`、`体格指数`、`平均血圧`、および`6つの血清測定値`)と、結果変数`y`(ベースラインから1年後の疾患進行の定量的な指標)が含まれています。\n", "\n", "|観測数|442|\n", "|----------------------|:---|\n", "|予測変数の数|最初の10列は数値型の予測変数|\n", "|結果/ターゲット|11列目はベースラインから1年後の疾患進行の定量的な指標|\n", "|予測変数の情報|- 年齢(年単位)\n", "||- 性別\n", "||- bmi 体格指数\n", "||- bp 平均血圧\n", "||- s1 tc 総血清コレステロール\n", "||- s2 ldl 低密度リポタンパク質\n", "||- s3 hdl 高密度リポタンパク質\n", "||- s4 tch 総コレステロール / HDL\n", "||- s5 ltg おそらく血清トリグリセリドレベルの対数\n", "||- s6 glu 血糖値|\n", "\n", "> 🎓 覚えておいてください、これは教師あり学習であり、'y'という名前のターゲットが必要です。\n", "\n", "Rでデータを操作する前に、データをRのメモリにインポートするか、Rがリモートでデータにアクセスできるようにする接続を構築する必要があります。\n", "\n", "> [readr](https://readr.tidyverse.org/)パッケージは、Tidyverseの一部であり、Rに長方形データを高速かつ簡単に読み込む方法を提供します。\n", "\n", "では、このソースURLで提供されている糖尿病データセットを読み込みましょう: \n", "\n", "また、`glimpse()`を使ってデータの健全性チェックを行い、`slice()`を使って最初の5行を表示します。\n", "\n", "さらに進む前に、Rコードで頻繁に遭遇するものを紹介します 🥁🥁: パイプ演算子 `%>%`\n", "\n", "パイプ演算子 (`%>%`) は、オブジェクトを関数や呼び出し式に順序立てて渡すことで、論理的な順序で操作を行います。コード内で「そして次に」と言っているようなものだと考えることができます。\n" ], "metadata": { "id": "KM6iXLH996Cl" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Import the data set\r\n", "diabetes <- read_table2(file = \"https://www4.stat.ncsu.edu/~boos/var.select/diabetes.rwrite1.txt\")\r\n", "\r\n", "\r\n", "# Get a glimpse and dimensions of the data\r\n", "glimpse(diabetes)\r\n", "\r\n", "\r\n", "# Select the first 5 rows of the data\r\n", "diabetes %>% \r\n", " slice(1:5)" ], "outputs": [], "metadata": { "id": "Z1geAMhM-bSP" } }, { "cell_type": "markdown", "source": [ "`glimpse()` を使うと、このデータには 442 行と 11 列があり、すべての列がデータ型 `double` であることがわかります。\n", "\n", "
\n", "\n", "> `glimpse()` と `slice()` は [`dplyr`](https://dplyr.tidyverse.org/) の関数です。Dplyr は Tidyverse の一部であり、データ操作の文法を提供します。一貫性のある一連の動詞を通じて、最も一般的なデータ操作の課題を解決するのに役立ちます。\n", "\n", "
\n", "\n", "データが揃ったので、この演習のターゲットとして 1 つの特徴量(`bmi`)に絞り込みましょう。そのためには、必要な列を選択する必要があります。では、どうやってこれを行うのでしょうか?\n", "\n", "[`dplyr::select()`](https://dplyr.tidyverse.org/reference/select.html) を使うと、データフレーム内の列を*選択*(必要に応じて名前を変更)することができます。\n" ], "metadata": { "id": "UwjVT1Hz-c3Z" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Select predictor feature `bmi` and outcome `y`\r\n", "diabetes_select <- diabetes %>% \r\n", " select(c(bmi, y))\r\n", "\r\n", "# Print the first 5 rows\r\n", "diabetes_select %>% \r\n", " slice(1:10)" ], "outputs": [], "metadata": { "id": "RDY1oAKI-m80" } }, { "cell_type": "markdown", "source": [ "## 3. トレーニングデータとテストデータ\n", "\n", "教師あり学習では、データを2つのサブセットに*分割*することが一般的です。通常は、モデルをトレーニングするための(一般的に大きな)セットと、モデルの性能を確認するための小さな「保持」セットに分けます。\n", "\n", "データの準備が整ったので、このデータセット内の数値を論理的に分割する方法を機械が助けてくれるかどうか確認してみましょう。Tidymodelsフレームワークの一部である[rsample](https://tidymodels.github.io/rsample/)パッケージを使用して、データを*どのように*分割するかの情報を含むオブジェクトを作成し、その後、作成されたトレーニングセットとテストセットを抽出するために2つのrsample関数を使用します。\n" ], "metadata": { "id": "SDk668xK-tc3" } }, { "cell_type": "code", "execution_count": null, "source": [ "set.seed(2056)\r\n", "# Split 67% of the data for training and the rest for tesing\r\n", "diabetes_split <- diabetes_select %>% \r\n", " initial_split(prop = 0.67)\r\n", "\r\n", "# Extract the resulting train and test sets\r\n", "diabetes_train <- training(diabetes_split)\r\n", "diabetes_test <- testing(diabetes_split)\r\n", "\r\n", "# Print the first 3 rows of the training set\r\n", "diabetes_train %>% \r\n", " slice(1:10)" ], "outputs": [], "metadata": { "id": "EqtHx129-1h-" } }, { "cell_type": "markdown", "source": [ "## 4. Tidymodelsで線形回帰モデルをトレーニングする\n", "\n", "さあ、モデルをトレーニングする準備が整いました!\n", "\n", "Tidymodelsでは、`parsnip()`を使って以下の3つの概念を指定することでモデルを定義します:\n", "\n", "- モデルの**タイプ**は、線形回帰、ロジスティック回帰、決定木モデルなど、モデルの種類を区別します。\n", "\n", "- モデルの**モード**には、回帰や分類といった一般的なオプションが含まれます。一部のモデルタイプはこれらの両方をサポートしていますが、片方のみを持つものもあります。\n", "\n", "- モデルの**エンジン**は、モデルを適合させるために使用される計算ツールです。これには、**`\"lm\"`** や **`\"ranger\"`** のようなRパッケージが含まれることが多いです。\n", "\n", "これらのモデリング情報はモデル仕様にまとめられます。それでは、モデル仕様を作成してみましょう!\n" ], "metadata": { "id": "sBOS-XhB-6v7" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Build a linear model specification\r\n", "lm_spec <- \r\n", " # Type\r\n", " linear_reg() %>% \r\n", " # Engine\r\n", " set_engine(\"lm\") %>% \r\n", " # Mode\r\n", " set_mode(\"regression\")\r\n", "\r\n", "\r\n", "# Print the model specification\r\n", "lm_spec" ], "outputs": [], "metadata": { "id": "20OwEw20--t3" } }, { "cell_type": "markdown", "source": [ "モデルが*指定*された後、通常は式とデータを使用して、[`fit()`](https://parsnip.tidymodels.org/reference/fit.html)関数を使ってモデルを`推定`または`訓練`することができます。\n", "\n", "`y ~ .`は、`y`を予測される量/ターゲットとしてフィットし、すべての予測因子/特徴量、つまり`.`によって説明されることを意味します(この場合、予測因子は1つだけで、それは`bmi`です)。\n" ], "metadata": { "id": "_oDHs89k_CJj" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Build a linear model specification\r\n", "lm_spec <- linear_reg() %>% \r\n", " set_engine(\"lm\") %>%\r\n", " set_mode(\"regression\")\r\n", "\r\n", "\r\n", "# Train a linear regression model\r\n", "lm_mod <- lm_spec %>% \r\n", " fit(y ~ ., data = diabetes_train)\r\n", "\r\n", "# Print the model\r\n", "lm_mod" ], "outputs": [], "metadata": { "id": "YlsHqd-q_GJQ" } }, { "cell_type": "markdown", "source": [ "トレーニング中に学習された係数をモデルの出力から確認できます。これらの係数は、実際の値と予測値の間の全体的な誤差を最小化する最適な直線の係数を表しています。\n", "
\n", "\n", "## 5. テストセットで予測を行う\n", "\n", "モデルをトレーニングしたので、これを使用してテストデータセットの疾患進行 y を予測できます。[parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html) を使って予測を行い、データグループ間の線を描画します。\n" ], "metadata": { "id": "kGZ22RQj_Olu" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make predictions for the test set\r\n", "predictions <- lm_mod %>% \r\n", " predict(new_data = diabetes_test)\r\n", "\r\n", "# Print out some of the predictions\r\n", "predictions %>% \r\n", " slice(1:5)" ], "outputs": [], "metadata": { "id": "nXHbY7M2_aao" } }, { "cell_type": "markdown", "source": [ "やったー!💃🕺 モデルをトレーニングして、予測を行いました!\n", "\n", "予測を行う際、tidymodelsの慣例では、標準化された列名を持つ結果のtibble/データフレームを常に生成します。これにより、元のデータと予測結果を使いやすい形式で結合し、プロットなどの後続の操作に活用することが簡単になります。\n", "\n", "`dplyr::bind_cols()`は複数のデータフレームを効率的に列として結合します。\n" ], "metadata": { "id": "R_JstwUY_bIs" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Combine the predictions and the original test set\r\n", "results <- diabetes_test %>% \r\n", " bind_cols(predictions)\r\n", "\r\n", "\r\n", "results %>% \r\n", " slice(1:5)" ], "outputs": [], "metadata": { "id": "RybsMJR7_iI8" } }, { "cell_type": "markdown", "source": [ "## 6. モデリング結果のプロット\n", "\n", "さて、これを視覚的に確認する時間です 📈。テストセットのすべての `y` と `bmi` の値を散布図で描画し、予測値を使ってモデルのデータグループ間で最適な位置に線を引きます。\n", "\n", "Rにはグラフを作成するためのいくつかのシステムがありますが、`ggplot2` はその中でも最もエレガントで汎用性の高いものの一つです。これにより、**独立したコンポーネントを組み合わせる**ことでグラフを作成することができます。\n" ], "metadata": { "id": "XJbYbMZW_n_s" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Set a theme for the plot\r\n", "theme_set(theme_light())\r\n", "# Create a scatter plot\r\n", "results %>% \r\n", " ggplot(aes(x = bmi)) +\r\n", " # Add a scatter plot\r\n", " geom_point(aes(y = y), size = 1.6) +\r\n", " # Add a line plot\r\n", " geom_line(aes(y = .pred), color = \"blue\", size = 1.5)" ], "outputs": [], "metadata": { "id": "R9tYp3VW_sTn" } }, { "cell_type": "markdown", "source": [ "✅ ここで何が起きているのか少し考えてみましょう。一本の直線が多数の小さなデータ点を通り抜けていますが、具体的に何をしているのでしょうか?この直線を使って、新しい未確認のデータポイントがプロットのy軸に対してどの位置に収まるべきか予測できる方法が見えてきますか?このモデルの実際の用途を言葉で説明してみてください。\n", "\n", "おめでとうございます!初めて線形回帰モデルを構築し、それを使って予測を行い、プロットに表示することができました!\n" ], "metadata": { "id": "zrPtHIxx_tNI" } }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**免責事項**: \nこの文書は、AI翻訳サービス [Co-op Translator](https://github.com/Azure/co-op-translator) を使用して翻訳されています。正確性を期すよう努めておりますが、自動翻訳には誤りや不正確な表現が含まれる可能性があります。元の言語で記載された原文を公式な情報源としてご参照ください。重要な情報については、専門の人間による翻訳を推奨します。本翻訳の利用に起因する誤解や誤認について、当社は一切の責任を負いません。\n" ] } ] }