{ "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:53+00:00", "source_file": "2-Regression/1-Tools/solution/R/lesson_1-R.ipynb", "language_code": "ko" } }, "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`를 포함하고 있습니다. 결과 변수 `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", "\n", "> 🎓 기억하세요, 이는 지도 학습(supervised learning)이며, '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/) 패키지의 함수입니다. Tidyverse의 일부인 dplyr은 데이터 조작을 위한 문법으로, 가장 일반적인 데이터 조작 문제를 해결하는 데 도움을 주는 일관된 동사 세트를 제공합니다.\n", "\n", "
\n", "\n", "이제 데이터를 확보했으니, 이번 연습에서는 특정 특징(`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", "지도 학습에서는 데이터를 두 개의 하위 집합으로 *분할*하는 것이 일반적인 관행입니다. 하나는 모델을 학습시키는 데 사용하는 (일반적으로 더 큰) 데이터 세트이고, 다른 하나는 모델의 성능을 확인하기 위해 사용하는 더 작은 \"보류\" 데이터 세트입니다.\n", "\n", "이제 데이터를 준비했으니, 이 데이터 세트에서 숫자들을 논리적으로 분할하는 데 머신이 도움을 줄 수 있는지 확인해 봅시다. 이를 위해 Tidymodels 프레임워크의 일부인 [rsample](https://tidymodels.github.io/rsample/) 패키지를 사용할 수 있습니다. 이 패키지를 사용하면 데이터를 *어떻게* 분할할지에 대한 정보를 포함하는 객체를 생성할 수 있으며, 이후 두 개의 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()`을 사용하여 세 가지 개념을 지정함으로써 모델을 정의합니다:\n", "\n", "- 모델 **유형(type)**: 선형 회귀, 로지스틱 회귀, 결정 트리 모델 등과 같은 모델을 구분합니다.\n", "\n", "- 모델 **모드(mode)**: 회귀(regression)와 분류(classification)와 같은 일반적인 옵션을 포함하며, 일부 모델 유형은 둘 중 하나를 지원하거나 하나의 모드만 가질 수 있습니다.\n", "\n", "- 모델 **엔진(engine)**: 모델을 학습시키는 데 사용되는 계산 도구입니다. 종종 **`\"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`를 예측 값/목표로 설정하고, 모든 예측 변수/특징(즉, `.`)에 의해 설명된다는 것을 의미합니다. (이 경우, 우리는 하나의 예측 변수인 `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" ] } ] }