{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## ロジスティック回帰モデルを構築する - レッスン4\n", "\n", "![ロジスティック回帰と線形回帰のインフォグラフィック](../../../../../../translated_images/linear-vs-logistic.ba180bf95e7ee66721ba10ebf2dac2666acbd64a88b003c83928712433a13c7d.ja.png)\n", "\n", "#### **[講義前のクイズ](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/15/)**\n", "\n", "#### イントロダクション\n", "\n", "回帰に関する最後のレッスンでは、基本的な*クラシック*な機械学習技術の一つであるロジスティック回帰について学びます。この技術を使うことで、パターンを見つけて二値分類を予測することができます。このキャンディはチョコレートかどうか?この病気は伝染性かどうか?この顧客はこの商品を選ぶかどうか?\n", "\n", "このレッスンで学ぶ内容:\n", "\n", "- ロジスティック回帰の技術\n", "\n", "✅ このタイプの回帰を扱う理解を深めるために、この[学習モジュール](https://learn.microsoft.com/training/modules/introduction-classification-models/?WT.mc_id=academic-77952-leestott)を参照してください。\n", "\n", "## 前提条件\n", "\n", "かぼちゃのデータを扱ったことで、`Color`という二値分類が扱えることに気づいているはずです。\n", "\n", "いくつかの変数を基にして、*特定のかぼちゃの色が何色である可能性が高いか*(オレンジ 🎃 か白 👻)を予測するロジスティック回帰モデルを構築してみましょう。\n", "\n", "> なぜ回帰に関するレッスンで二値分類について話しているのでしょうか?それは言語的な便宜上の理由に過ぎません。ロジスティック回帰は[実際には分類方法](https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression)であり、線形ベースのものです。次のレッスングループでは、データを分類する他の方法について学びます。\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", "- `janitor`: [janitorパッケージ](https://github.com/sfirke/janitor)は、汚れたデータを調査し、クリーニングするためのシンプルなツールを提供します。\n", "\n", "- `ggbeeswarm`: [ggbeeswarmパッケージ](https://github.com/eclarke/ggbeeswarm)は、ggplot2を使用してビースウォームスタイルのプロットを作成する方法を提供します。\n", "\n", "以下のコマンドでこれらをインストールできます:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"ggbeeswarm\"))`\n", "\n", "または、以下のスクリプトを使用して、必要なパッケージがインストールされているか確認し、欠けている場合はインストールすることもできます。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\n", "\n", "pacman::p_load(tidyverse, tidymodels, janitor, ggbeeswarm)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **質問を定義する**\n", "\n", "今回の目的では、質問を「白」または「白ではない」という二択で表現します。データセットには「縞模様」というカテゴリもありますが、該当するデータが少ないため使用しません。そもそも、データセットから欠損値を除去すると、このカテゴリは消えてしまいます。\n", "\n", "> 🎃 面白い事実として、白いカボチャを「ゴースト」カボチャと呼ぶことがあります。彫刻するのが難しいため、オレンジ色のカボチャほど人気はありませんが、見た目はとてもクールです!したがって、質問を「ゴースト」または「ゴーストではない」と再構成することもできます。👻\n", "\n", "## **ロジスティック回帰について**\n", "\n", "ロジスティック回帰は、以前学んだ線形回帰とはいくつか重要な点で異なります。\n", "\n", "#### **二値分類**\n", "\n", "ロジスティック回帰は、線形回帰と同じ機能を提供するわけではありません。ロジスティック回帰は「二値カテゴリ」(例:「オレンジかオレンジではない」)について予測を行いますが、線形回帰は「連続値」を予測することができます。例えば、カボチャの産地と収穫時期を基にして、*価格がどれだけ上昇するか*を予測することが可能です。\n", "\n", "![Dasani Madipalliによるインフォグラフィック](../../../../../../translated_images/pumpkin-classifier.562771f104ad5436b87d1c67bca02a42a17841133556559325c0a0e348e5b774.ja.png)\n", "\n", "### その他の分類\n", "\n", "ロジスティック回帰には、他にも多項式回帰や順序回帰といった種類があります。\n", "\n", "- **多項式回帰**: 複数のカテゴリがある場合に使用します(例:「オレンジ、白、縞模様」)。\n", "\n", "- **順序回帰**: 順序付けされたカテゴリを扱う場合に使用します。例えば、カボチャのサイズを有限のサイズ(mini, sm, med, lg, xl, xxl)で論理的に順序付けする場合に役立ちます。\n", "\n", "![多項式回帰 vs 順序回帰](../../../../../../translated_images/multinomial-vs-ordinal.36701b4850e37d86c9dd49f7bef93a2f94dbdb8fe03443eb68f0542f97f28f29.ja.png)\n", "\n", "#### **変数が相関している必要はない**\n", "\n", "線形回帰が相関の強い変数でより良い結果を出すのに対し、ロジスティック回帰は逆で、変数が必ずしも一致している必要はありません。このデータセットのように、相関がやや弱い場合でも適しています。\n", "\n", "#### **大量のクリーンなデータが必要**\n", "\n", "ロジスティック回帰は、データが多いほど正確な結果を出します。この小規模なデータセットはこのタスクには最適ではないため、その点を考慮してください。\n", "\n", "✅ ロジスティック回帰に適したデータの種類について考えてみましょう。\n", "\n", "## 演習 - データを整理する\n", "\n", "まず、データを少し整理し、欠損値を削除して特定の列だけを選択します。\n", "\n", "1. 次のコードを追加してください:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Load the core tidyverse packages\n", "library(tidyverse)\n", "\n", "# Import the data and clean column names\n", "pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\") %>% \n", " clean_names()\n", "\n", "# Select desired columns\n", "pumpkins_select <- pumpkins %>% \n", " select(c(city_name, package, variety, origin, item_size, color)) \n", "\n", "# Drop rows containing missing values and encode color as factor (category)\n", "pumpkins_select <- pumpkins_select %>% \n", " drop_na() %>% \n", " mutate(color = factor(color))\n", "\n", "# View the first few rows\n", "pumpkins_select %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "新しいデータフレームを確認するには、以下のように[*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html)関数を使用すると便利です。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "pumpkins_select %>% \n", " glimpse()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "バイナリ分類問題を実際に行うことを確認しましょう:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Subset distinct observations in outcome column\n", "pumpkins_select %>% \n", " distinct(color)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 可視化 - カテゴリカルプロット\n", "これまでに、再びパンプキンデータを読み込み、いくつかの変数(Colorを含む)を保持するようにデータセットをクリーンアップしました。ggplotライブラリを使用して、ノートブック内でデータフレームを可視化してみましょう。\n", "\n", "ggplotライブラリは、データを視覚化するための便利な方法を提供します。例えば、カテゴリカルプロットで各VarietyやColorごとのデータ分布を比較することができます。\n", "\n", "1. geombar関数を使用して、パンプキンデータを使い、各パンプキンカテゴリ(オレンジまたは白)に対して色のマッピングを指定することで、このようなプロットを作成します:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "# Specify colors for each value of the hue variable\n", "palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n", "\n", "# Create the bar plot\n", "ggplot(pumpkins_select, aes(y = variety, fill = color)) +\n", " geom_bar(position = \"dodge\") +\n", " scale_fill_manual(values = palette) +\n", " labs(y = \"Variety\", fill = \"Color\") +\n", " theme_minimal()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "データを観察すると、ColorデータがVarietyとどのように関連しているかがわかります。\n", "\n", "✅ このカテゴリカルプロットを基に、どのような興味深い探求が考えられますか?\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### データ前処理: 特徴量エンコーディング\n", "\n", "私たちのカボチャのデータセットには、すべての列に文字列値が含まれています。人間にとってカテゴリカルデータを扱うのは直感的ですが、機械にとってはそうではありません。機械学習アルゴリズムは数値データでうまく機能します。そのため、エンコーディングはデータ前処理の段階で非常に重要なステップとなります。これにより、カテゴリカルデータを数値データに変換し、情報を失うことなく処理できるようになります。適切なエンコーディングは、良いモデルを構築するための鍵となります。\n", "\n", "特徴量エンコーディングには、主に以下の2種類のエンコーダがあります:\n", "\n", "1. **Ordinalエンコーダ**: 順序変数に適しています。順序変数とは、データが論理的な順序に従うカテゴリカル変数のことです。例えば、データセットの`item_size`列が該当します。このエンコーダは、各カテゴリを数値で表すマッピングを作成します。この数値は、列内でのカテゴリの順序を表します。\n", "\n", "2. **カテゴリカルエンコーダ**: 名義変数に適しています。名義変数とは、データが論理的な順序に従わないカテゴリカル変数のことです。データセット内の`item_size`以外のすべての特徴量が該当します。このエンコーディングは「ワンホットエンコーディング」と呼ばれ、各カテゴリがバイナリ列で表されます。エンコードされた変数は、カボチャがその品種に属している場合は1、そうでない場合は0となります。\n", "\n", "Tidymodelsにはもう一つ便利なパッケージがあります:[recipes](https://recipes.tidymodels.org/) - データ前処理用のパッケージです。このパッケージを使って、すべての予測子列を整数にエンコードする`recipe`を定義し、`prep`を使って必要な量や統計を推定し、最後に`bake`を使って新しいデータに計算を適用します。\n", "\n", "> 通常、recipesはモデリングのための前処理として使用されます。この場合、データセットをモデリングに適した状態にするためにどのステップを適用するべきかを定義します。この場合、`prep`と`bake`を手動で使用してレシピを推定するのではなく、`workflow()`を使用することを**強く推奨**します。この内容についてはすぐに説明します。\n", ">\n", "> しかし、今回はrecipes + prep + bakeを使用して、データセットに適用すべきステップを指定し、前処理済みデータをステップ適用後に抽出する方法を学びます。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Preprocess and extract data to allow some data analysis\n", "baked_pumpkins <- recipe(color ~ ., data = pumpkins_select) %>%\n", " # Define ordering for item_size column\n", " step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n", " # Convert factors to numbers using the order defined above (Ordinal encoding)\n", " step_integer(item_size, zero_based = F) %>%\n", " # Encode all other predictors using one hot encoding\n", " step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE) %>%\n", " prep(data = pumpkin_select) %>%\n", " bake(new_data = NULL)\n", "\n", "# Display the first few rows of preprocessed data\n", "baked_pumpkins %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "✅ アイテムサイズ列に対して順序エンコーダーを使用する利点は何ですか?\n", "\n", "### 変数間の関係を分析する\n", "\n", "データの前処理が完了したので、特徴量とラベルの関係を分析し、特徴量を基にモデルがラベルをどの程度予測できるかの見通しを得ることができます。この種の分析を行う最良の方法は、データをプロットすることです。 \n", "ここでは再び、ggplotのgeom_boxplot_関数を使用して、アイテムサイズ、品種、色の関係をカテゴリカルプロットで視覚化します。データをより良くプロットするために、エンコードされたアイテムサイズ列とエンコードされていない品種列を使用します。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Define the color palette\n", "palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n", "\n", "# We need the encoded Item Size column to use it as the x-axis values in the plot\n", "pumpkins_select_plot<-pumpkins_select\n", "pumpkins_select_plot$item_size <- baked_pumpkins$item_size\n", "\n", "# Create the grouped box plot\n", "ggplot(pumpkins_select_plot, aes(x = `item_size`, y = color, fill = color)) +\n", " geom_boxplot() +\n", " facet_grid(variety ~ ., scales = \"free_x\") +\n", " scale_fill_manual(values = palette) +\n", " labs(x = \"Item Size\", y = \"\") +\n", " theme_minimal() +\n", " theme(strip.text = element_text(size = 12)) +\n", " theme(axis.text.x = element_text(size = 10)) +\n", " theme(axis.title.x = element_text(size = 12)) +\n", " theme(axis.title.y = element_blank()) +\n", " theme(legend.position = \"bottom\") +\n", " guides(fill = guide_legend(title = \"Color\")) +\n", " theme(panel.spacing = unit(0.5, \"lines\"))+\n", " theme(strip.text.y = element_text(size = 4, hjust = 0)) \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### スウォームプロットを使う\n", "\n", "Colorは二値カテゴリ(WhiteまたはNot)であるため、視覚化には「[特別なアプローチ](https://github.com/rstudio/cheatsheets/blob/main/data-visualization.pdf)」が必要です。\n", "\n", "`swarm plot`を試して、item_sizeに対するColorの分布を表示してみましょう。\n", "\n", "ここでは、[ggbeeswarmパッケージ](https://github.com/eclarke/ggbeeswarm)を使用します。このパッケージは、ggplot2を使ってビースウォームスタイルのプロットを作成するためのメソッドを提供します。ビースウォームプロットは、通常は重なってしまうポイントを隣り合わせに配置することで視覚化する方法です。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Create beeswarm plots of color and item_size\n", "baked_pumpkins %>% \n", " mutate(color = factor(color)) %>% \n", " ggplot(mapping = aes(x = color, y = item_size, color = color)) +\n", " geom_quasirandom() +\n", " scale_color_brewer(palette = \"Dark2\", direction = -1) +\n", " theme(legend.position = \"none\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "これで、色の二値カテゴリとサイズの大きなグループとの関係についての理解が深まりました。次に、ロジスティック回帰を使って、特定のカボチャの色を予測する方法を探ってみましょう。\n", "\n", "## モデルを構築する\n", "\n", "分類モデルで使用する変数を選択し、データをトレーニングセットとテストセットに分割します。Tidymodelsのパッケージである[rsample](https://rsample.tidymodels.org/)は、効率的なデータ分割とリサンプリングのためのインフラを提供します。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Split data into 80% for training and 20% for testing\n", "set.seed(2056)\n", "pumpkins_split <- pumpkins_select %>% \n", " initial_split(prop = 0.8)\n", "\n", "# Extract the data in each split\n", "pumpkins_train <- training(pumpkins_split)\n", "pumpkins_test <- testing(pumpkins_split)\n", "\n", "# Print out the first 5 rows of the training set\n", "pumpkins_train %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "🙌 さあ、トレーニング特徴量をトレーニングラベル(色)に適合させることで、モデルのトレーニングを始めましょう。\n", "\n", "まず、データをモデリングに適した状態にするための前処理ステップを指定するレシピを作成します。例えば、カテゴリ変数を整数値にエンコードするなどです。`baked_pumpkins`と同様に、`pumpkins_recipe`を作成しますが、ここでは`prep`や`bake`は行いません。これらはワークフローにまとめられるためです。この後のステップでその詳細を確認できます。\n", "\n", "Tidymodelsではロジスティック回帰モデルを指定する方法がいくつかあります。`?logistic_reg()`を参照してください。今回は、デフォルトの`stats::glm()`エンジンを使用してロジスティック回帰モデルを指定します。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Create a recipe that specifies preprocessing steps for modelling\n", "pumpkins_recipe <- recipe(color ~ ., data = pumpkins_train) %>% \n", " step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n", " step_integer(item_size, zero_based = F) %>% \n", " step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE)\n", "\n", "# Create a logistic model specification\n", "log_reg <- logistic_reg() %>% \n", " set_engine(\"glm\") %>% \n", " set_mode(\"classification\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "レシピとモデル仕様が揃ったので、それらを一つのオブジェクトにまとめる方法を見つける必要があります。このオブジェクトは、まずデータを前処理(裏でprep+bakeを実行)、前処理済みデータにモデルを適合させ、さらに必要に応じて後処理を行うことができます。\n", "\n", "Tidymodelsでは、この便利なオブジェクトは[`workflow`](https://workflows.tidymodels.org/)と呼ばれ、モデリングの構成要素を効率的に保持します。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Bundle modelling components in a workflow\n", "log_reg_wf <- workflow() %>% \n", " add_recipe(pumpkins_recipe) %>% \n", " add_model(log_reg)\n", "\n", "# Print out the workflow\n", "log_reg_wf\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ワークフローが*指定*された後、モデルは[`fit()`](https://tidymodels.github.io/parsnip/reference/fit.html)関数を使用して`訓練`することができます。ワークフローはレシピを評価し、データを前処理してから訓練を行うため、prepやbakeを手動で実行する必要はありません。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Train the model\n", "wf_fit <- log_reg_wf %>% \n", " fit(data = pumpkins_train)\n", "\n", "# Print the trained workflow\n", "wf_fit\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "モデルのトレーニング中に学習された係数が出力されます。\n", "\n", "トレーニングデータを使ってモデルを訓練したので、[parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html) を使用してテストデータに対する予測を行うことができます。まず、モデルを使ってテストセットのラベルと各ラベルの確率を予測してみましょう。確率が0.5を超える場合、予測クラスは `WHITE` となり、それ以外の場合は `ORANGE` となります。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Make predictions for color and corresponding probabilities\n", "results <- pumpkins_test %>% select(color) %>% \n", " bind_cols(wf_fit %>% \n", " predict(new_data = pumpkins_test)) %>%\n", " bind_cols(wf_fit %>%\n", " predict(new_data = pumpkins_test, type = \"prob\"))\n", "\n", "# Compare predictions\n", "results %>% \n", " slice_head(n = 10)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "とても良いですね!これでロジスティック回帰の仕組みについてさらに理解が深まりました。\n", "\n", "### 混同行列を使ったより良い理解\n", "\n", "各予測値を対応する「正解データ」と比較するだけでは、モデルの予測精度を判断する効率的な方法とは言えません。幸いなことに、Tidymodelsにはさらに便利なツールがあります。それが、パフォーマンス指標を使ってモデルの効果を測定するためのパッケージ [`yardstick`](https://yardstick.tidymodels.org/) です。\n", "\n", "分類問題に関連するパフォーマンス指標の1つに、[`混同行列`](https://wikipedia.org/wiki/Confusion_matrix) があります。混同行列は、分類モデルの性能を示すものです。混同行列は、各クラスの例がモデルによって正しく分類された数を集計します。今回のケースでは、オレンジ色のカボチャがオレンジ色として分類された数や、白いカボチャが白として分類された数を示します。また、**誤った**カテゴリに分類された数も表示されます。\n", "\n", "yardstickの [**`conf_mat()`**](https://tidymodels.github.io/yardstick/reference/conf_mat.html) 関数を使うと、観測されたクラスと予測されたクラスのクロスタブを計算することができます。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Confusion matrix for prediction results\n", "conf_mat(data = results, truth = color, estimate = .pred_class)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "混同行列を解釈してみましょう。私たちのモデルは、カボチャを2つの二値カテゴリ、`white`(白)と`not-white`(白以外)に分類するよう求められています。\n", "\n", "- モデルがカボチャを白と予測し、実際にそのカボチャがカテゴリ「white」に属している場合、それを`true positive`(真陽性)と呼びます。これは左上の数字で示されます。\n", "\n", "- モデルがカボチャを白以外と予測し、実際にそのカボチャがカテゴリ「white」に属している場合、それを`false negative`(偽陰性)と呼びます。これは左下の数字で示されます。\n", "\n", "- モデルがカボチャを白と予測し、実際にそのカボチャがカテゴリ「not-white」に属している場合、それを`false positive`(偽陽性)と呼びます。これは右上の数字で示されます。\n", "\n", "- モデルがカボチャを白以外と予測し、実際にそのカボチャがカテゴリ「not-white」に属している場合、それを`true negative`(真陰性)と呼びます。これは右下の数字で示されます。\n", "\n", "| 真実 |\n", "|:-----:|\n", "\n", "| | | |\n", "|---------------|--------|-------|\n", "| **予測** | WHITE | ORANGE |\n", "| WHITE | TP | FP |\n", "| ORANGE | FN | TN |\n", "\n", "ご想像の通り、`true positive`と`true negative`の数が多く、`false positive`と`false negative`の数が少ない方が望ましいです。これにより、モデルの性能が良いことを意味します。\n", "\n", "混同行列は、分類モデルの性能をより良く評価するための他の指標を生み出すために役立ちます。それらをいくつか見ていきましょう:\n", "\n", "🎓 精度(Precision): `TP/(TP + FP)` \n", "予測された陽性のうち、実際に陽性である割合として定義されます。別名:[陽性予測値](https://en.wikipedia.org/wiki/Positive_predictive_value \"Positive predictive value\")\n", "\n", "🎓 再現率(Recall): `TP/(TP + FN)` \n", "実際に陽性であるサンプルのうち、陽性結果の割合として定義されます。別名:`感度(Sensitivity)`\n", "\n", "🎓 特異度(Specificity): `TN/(TN + FP)` \n", "実際に陰性であるサンプルのうち、陰性結果の割合として定義されます。\n", "\n", "🎓 正確度(Accuracy): `TP + TN/(TP + TN + FP + FN)` \n", "サンプルに対して正確に予測されたラベルの割合。\n", "\n", "🎓 F値(F Measure): \n", "精度と再現率の加重平均で、最良が1、最悪が0。\n", "\n", "これらの指標を計算してみましょう!\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Combine metric functions and calculate them all at once\n", "eval_metrics <- metric_set(ppv, recall, spec, f_meas, accuracy)\n", "eval_metrics(data = results, truth = color, estimate = .pred_class)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## このモデルのROC曲線を視覚化する\n", "\n", "もう一つの視覚化を行い、いわゆる[`ROC曲線`](https://en.wikipedia.org/wiki/Receiver_operating_characteristic)を確認してみましょう:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Make a roc_curve\n", "results %>% \n", " roc_curve(color, .pred_ORANGE) %>% \n", " autoplot()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ROC曲線は、分類器の出力を真陽性と偽陽性の観点から視覚化するためによく使用されます。ROC曲線では通常、Y軸に`True Positive Rate`(感度)、X軸に`False Positive Rate`(1-特異度)が表示されます。そのため、曲線の急峻さや、中央の直線と曲線の間の空間が重要です。理想的には、曲線がすぐに上昇し、直線を越える形になります。今回の場合、最初に偽陽性が発生し、その後、曲線が適切に上昇して直線を越えます。\n", "\n", "最後に、`yardstick::roc_auc()`を使用して、実際の曲線下面積(AUC)を計算してみましょう。AUCの解釈方法の一つとして、モデルがランダムな正の例をランダムな負の例よりも高くランク付けする確率として捉えることができます。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Calculate area under curve\n", "results %>% \n", " roc_auc(color, .pred_ORANGE)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "結果は約`0.975`です。AUCは0から1の範囲で表されるため、スコアが高いほど良いモデルと言えます。予測が100%正確なモデルはAUCが1になります。この場合、モデルは*かなり良い*と言えるでしょう。\n", "\n", "今後の分類に関するレッスンでは、このスコアを改善する方法(例えば、このケースでは不均衡なデータへの対処など)を学ぶことになります。\n", "\n", "## 🚀チャレンジ\n", "\n", "ロジスティック回帰にはまだまだ学ぶべきことがたくさんあります!しかし、最良の学習方法は実際に試してみることです。このタイプの分析に適したデータセットを見つけて、それを使ってモデルを構築してみましょう。何を学びましたか?ヒント: [Kaggle](https://www.kaggle.com/search?q=logistic+regression+datasets)で興味深いデータセットを探してみてください。\n", "\n", "## 復習と自己学習\n", "\n", "[スタンフォード大学のこの論文](https://web.stanford.edu/~jurafsky/slp3/5.pdf)の最初の数ページを読んで、ロジスティック回帰の実用的な利用例について学びましょう。これまで学んだ回帰タスクの中で、どのタスクがどのタイプの回帰に適しているかを考えてみてください。どちらが最適でしょうか?\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**免責事項**: \nこの文書は、AI翻訳サービス [Co-op Translator](https://github.com/Azure/co-op-translator) を使用して翻訳されています。正確性を追求しておりますが、自動翻訳には誤りや不正確さが含まれる可能性があります。元の言語で記載された原文が正式な情報源と見なされるべきです。重要な情報については、専門の人間による翻訳を推奨します。この翻訳の使用に起因する誤解や誤認について、当社は一切の責任を負いません。\n" ] } ], "metadata": { "anaconda-cloud": "", "kernelspec": { "display_name": "R", "langauge": "R", "name": "ir" }, "language_info": { "codemirror_mode": "r", "file_extension": ".r", "mimetype": "text/x-r-source", "name": "R", "pygments_lexer": "r", "version": "3.4.1" }, "coopTranslator": { "original_hash": "feaf125f481a89c468fa115bf2aed580", "translation_date": "2025-09-04T01:22:33+00:00", "source_file": "2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb", "language_code": "ja" } }, "nbformat": 4, "nbformat_minor": 1 }