You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
725 lines
29 KiB
725 lines
29 KiB
{
|
|
"nbformat": 4,
|
|
"nbformat_minor": 2,
|
|
"metadata": {
|
|
"colab": {
|
|
"name": "lesson_10-R.ipynb",
|
|
"provenance": [],
|
|
"collapsed_sections": []
|
|
},
|
|
"kernelspec": {
|
|
"name": "ir",
|
|
"display_name": "R"
|
|
},
|
|
"language_info": {
|
|
"name": "R"
|
|
},
|
|
"coopTranslator": {
|
|
"original_hash": "2621e24705e8100893c9bf84e0fc8aef",
|
|
"translation_date": "2025-09-04T02:46:23+00:00",
|
|
"source_file": "4-Classification/1-Introduction/solution/R/lesson_10-R.ipynb",
|
|
"language_code": "ko"
|
|
}
|
|
},
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"# 분류 모델 구축: 맛있는 아시아 및 인도 요리\n"
|
|
],
|
|
"metadata": {
|
|
"id": "ItETB4tSFprR"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## 분류 소개: 데이터 정리, 준비, 시각화\n",
|
|
"\n",
|
|
"이 네 가지 강의에서는 고전적인 머신 러닝의 핵심 주제인 *분류*를 탐구합니다. 아시아와 인도의 다양한 요리를 다룬 데이터셋을 사용하여 여러 분류 알고리즘을 살펴볼 것입니다. 배고프지 않으신가요?\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/pinch.png\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>이 강의에서 범아시아 요리를 기념하세요! 이미지: Jen Looper</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"<!---->\n",
|
|
"\n",
|
|
"분류는 [지도 학습](https://wikipedia.org/wiki/Supervised_learning)의 한 형태로, 회귀 기법과 많은 공통점을 가지고 있습니다. 분류에서는 모델을 훈련시켜 특정 항목이 어떤 `카테고리`에 속하는지 예측합니다. 머신 러닝이 데이터셋을 사용하여 값이나 이름을 예측하는 것이라면, 분류는 일반적으로 *이진 분류*와 *다중 클래스 분류*로 나뉩니다.\n",
|
|
"\n",
|
|
"기억하세요:\n",
|
|
"\n",
|
|
"- **선형 회귀**는 변수 간의 관계를 예측하고 새로운 데이터 포인트가 그 선과 어떤 관계에 있는지 정확히 예측하는 데 도움을 줍니다. 예를 들어, *9월과 12월에 호박의 가격이 얼마일지*를 예측할 수 있습니다.\n",
|
|
"\n",
|
|
"- **로지스틱 회귀**는 \"이진 카테고리\"를 발견하는 데 도움을 줍니다. 예를 들어, 특정 가격에서 *이 호박이 주황색인지 아닌지*를 예측할 수 있습니다.\n",
|
|
"\n",
|
|
"분류는 다양한 알고리즘을 사용하여 데이터 포인트의 레이블이나 클래스를 결정하는 방법을 제공합니다. 이 요리 데이터를 사용하여 재료 그룹을 관찰함으로써 해당 요리가 어떤 지역에서 유래했는지 알아낼 수 있는지 살펴봅시다.\n",
|
|
"\n",
|
|
"### [**강의 전 퀴즈**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/19/)\n",
|
|
"\n",
|
|
"### **소개**\n",
|
|
"\n",
|
|
"분류는 머신 러닝 연구자와 데이터 과학자의 기본 활동 중 하나입니다. 간단한 이진 값 분류(\"이 이메일이 스팸인가 아닌가?\")에서부터 복잡한 이미지 분류 및 컴퓨터 비전을 사용한 세분화까지, 데이터를 클래스로 분류하고 질문을 던질 수 있는 능력은 항상 유용합니다.\n",
|
|
"\n",
|
|
"과정을 좀 더 과학적으로 설명하자면, 분류 방법은 입력 변수와 출력 변수 간의 관계를 매핑할 수 있는 예측 모델을 생성합니다.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/binary-multiclass.png\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>분류 알고리즘이 처리하는 이진 문제와 다중 클래스 문제. 인포그래픽: Jen Looper</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"데이터를 정리하고 시각화하며 머신 러닝 작업을 준비하는 과정을 시작하기 전에, 머신 러닝이 데이터를 분류하는 데 사용될 수 있는 다양한 방법에 대해 알아봅시다.\n",
|
|
"\n",
|
|
"[통계학](https://wikipedia.org/wiki/Statistical_classification)에서 파생된 고전적인 머신 러닝을 사용한 분류는 `흡연 여부`, `체중`, `나이`와 같은 특징을 사용하여 *질병 X에 걸릴 가능성*을 결정합니다. 이전에 수행한 회귀 연습과 유사한 지도 학습 기법으로, 데이터는 레이블이 지정되어 있으며, 머신 러닝 알고리즘은 이러한 레이블을 사용하여 데이터셋의 클래스(또는 '특징')를 분류하고 이를 그룹이나 결과에 할당합니다.\n",
|
|
"\n",
|
|
"✅ 요리에 대한 데이터셋을 상상해 보세요. 다중 클래스 모델은 어떤 질문에 답할 수 있을까요? 이진 모델은 어떤 질문에 답할 수 있을까요? 특정 요리가 호로파를 사용할 가능성을 결정하고 싶다면 어떻게 할까요? 아니면, 별미, 아티초크, 콜리플라워, 고추냉이가 가득 든 장바구니를 선물받았을 때, 전형적인 인도 요리를 만들 수 있을지 알고 싶다면 어떻게 할까요?\n",
|
|
"\n",
|
|
"### **'분류기'를 만나보세요**\n",
|
|
"\n",
|
|
"이 요리 데이터셋에서 우리가 던지고 싶은 질문은 사실 **다중 클래스 질문**입니다. 여러 국가 요리 중에서, 주어진 재료 묶음이 어떤 클래스에 속할지 데이터를 통해 알아낼 수 있을까요?\n",
|
|
"\n",
|
|
"Tidymodels는 문제 유형에 따라 데이터를 분류하는 데 사용할 수 있는 여러 알고리즘을 제공합니다. 다음 두 강의에서는 이러한 알고리즘 중 몇 가지를 배울 것입니다.\n",
|
|
"\n",
|
|
"#### **사전 요구 사항**\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",
|
|
"- `DataExplorer`: [DataExplorer 패키지](https://cran.r-project.org/web/packages/DataExplorer/vignettes/dataexplorer-intro.html)는 EDA(탐색적 데이터 분석) 과정과 보고서 생성을 단순화하고 자동화하기 위해 설계되었습니다.\n",
|
|
"\n",
|
|
"- `themis`: [themis 패키지](https://themis.tidymodels.org/)는 불균형 데이터 처리를 위한 추가 레시피 단계를 제공합니다.\n",
|
|
"\n",
|
|
"다음 명령어로 패키지를 설치할 수 있습니다:\n",
|
|
"\n",
|
|
"`install.packages(c(\"tidyverse\", \"tidymodels\", \"DataExplorer\", \"here\"))`\n",
|
|
"\n",
|
|
"또는 아래 스크립트를 사용하여 이 모듈을 완료하는 데 필요한 패키지가 설치되어 있는지 확인하고, 누락된 경우 설치할 수 있습니다.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "ri5bQxZ-Fz_0"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\r\n",
|
|
"\r\n",
|
|
"pacman::p_load(tidyverse, tidymodels, DataExplorer, themis, here)"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "KIPxa4elGAPI"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"나중에 이 멋진 패키지들을 로드하여 현재 R 세션에서 사용할 수 있도록 하겠습니다. (이는 단순한 예시일 뿐이며, `pacman::p_load()`가 이미 이를 수행했습니다)\n"
|
|
],
|
|
"metadata": {
|
|
"id": "YkKAxOJvGD4C"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## 연습 - 데이터를 정리하고 균형 맞추기\n",
|
|
"\n",
|
|
"이 프로젝트를 시작하기 전에 첫 번째로 해야 할 일은 데이터를 정리하고 **균형을 맞추는 것**입니다. 이렇게 하면 더 나은 결과를 얻을 수 있습니다.\n",
|
|
"\n",
|
|
"데이터를 살펴봅시다!🕵️\n"
|
|
],
|
|
"metadata": {
|
|
"id": "PFkQDlk0GN5O"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Import data\r\n",
|
|
"df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/4-Classification/data/cuisines.csv\")\r\n",
|
|
"\r\n",
|
|
"# View the first 5 rows\r\n",
|
|
"df %>% \r\n",
|
|
" slice_head(n = 5)\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "Qccw7okxGT0S"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"흥미롭네요! 보아하니 첫 번째 열은 일종의 `id` 열인 것 같아요. 데이터에 대해 조금 더 알아봅시다.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "XrWnlgSrGVmR"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Basic information about the data\r\n",
|
|
"df %>%\r\n",
|
|
" introduce()\r\n",
|
|
"\r\n",
|
|
"# Visualize basic information above\r\n",
|
|
"df %>% \r\n",
|
|
" plot_intro(ggtheme = theme_light())"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "4UcGmxRxGieA"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"출력 결과를 보면 `2448`개의 행과 `385`개의 열이 있으며, 결측값은 `0`개입니다. 또한, 하나의 이산형 열인 *cuisine*이 있습니다.\n",
|
|
"\n",
|
|
"## 연습 - 요리 유형에 대해 배우기\n",
|
|
"\n",
|
|
"이제 작업이 더 흥미로워지기 시작합니다. 요리 유형별로 데이터 분포를 알아봅시다.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "AaPubl__GmH5"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Count observations per cuisine\r\n",
|
|
"df %>% \r\n",
|
|
" count(cuisine) %>% \r\n",
|
|
" arrange(n)\r\n",
|
|
"\r\n",
|
|
"# Plot the distribution\r\n",
|
|
"theme_set(theme_light())\r\n",
|
|
"df %>% \r\n",
|
|
" count(cuisine) %>% \r\n",
|
|
" ggplot(mapping = aes(x = n, y = reorder(cuisine, -n))) +\r\n",
|
|
" geom_col(fill = \"midnightblue\", alpha = 0.7) +\r\n",
|
|
" ylab(\"cuisine\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "FRsBVy5eGrrv"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"요리 종류는 유한하지만 데이터 분포는 고르지 않습니다. 이를 수정할 수 있습니다! 수정하기 전에 조금 더 탐색해보세요.\n",
|
|
"\n",
|
|
"다음으로, 각 요리 종류를 개별 tibble로 할당하고, 요리 종류별로 사용 가능한 데이터(행, 열)가 얼마나 되는지 확인해봅시다.\n",
|
|
"\n",
|
|
"> [tibble](https://tibble.tidyverse.org/)은 현대적인 데이터 프레임입니다.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/dplyr_filter.jpg\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>@allison_horst의 작품</figcaption>\n"
|
|
],
|
|
"metadata": {
|
|
"id": "vVvyDb1kG2in"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Create individual tibble for the cuisines\r\n",
|
|
"thai_df <- df %>% \r\n",
|
|
" filter(cuisine == \"thai\")\r\n",
|
|
"japanese_df <- df %>% \r\n",
|
|
" filter(cuisine == \"japanese\")\r\n",
|
|
"chinese_df <- df %>% \r\n",
|
|
" filter(cuisine == \"chinese\")\r\n",
|
|
"indian_df <- df %>% \r\n",
|
|
" filter(cuisine == \"indian\")\r\n",
|
|
"korean_df <- df %>% \r\n",
|
|
" filter(cuisine == \"korean\")\r\n",
|
|
"\r\n",
|
|
"\r\n",
|
|
"# Find out how much data is available per cuisine\r\n",
|
|
"cat(\" thai df:\", dim(thai_df), \"\\n\",\r\n",
|
|
" \"japanese df:\", dim(japanese_df), \"\\n\",\r\n",
|
|
" \"chinese_df:\", dim(chinese_df), \"\\n\",\r\n",
|
|
" \"indian_df:\", dim(indian_df), \"\\n\",\r\n",
|
|
" \"korean_df:\", dim(korean_df))"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "0TvXUxD3G8Bk"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## **연습 - dplyr을 사용하여 요리별 주요 재료 발견하기**\n",
|
|
"\n",
|
|
"이제 데이터를 더 깊이 탐구하여 요리별로 대표적인 재료가 무엇인지 알아볼 수 있습니다. 요리 간 혼란을 일으키는 반복적인 데이터를 정리해야 하므로, 이 문제에 대해 배워봅시다.\n",
|
|
"\n",
|
|
"R에서 `create_ingredient()`라는 함수를 만들어 재료 데이터프레임을 반환하세요. 이 함수는 도움이 되지 않는 열을 제거하고, 재료를 개수에 따라 정렬하는 것으로 시작합니다.\n",
|
|
"\n",
|
|
"R 함수의 기본 구조는 다음과 같습니다:\n",
|
|
"\n",
|
|
"`myFunction <- function(arglist){`\n",
|
|
"\n",
|
|
"**`...`**\n",
|
|
"\n",
|
|
"**`return`**`(value)`\n",
|
|
"\n",
|
|
"`}`\n",
|
|
"\n",
|
|
"R 함수에 대한 깔끔한 소개는 [여기](https://skirmer.github.io/presentations/functions_with_r.html#1)에서 확인할 수 있습니다.\n",
|
|
"\n",
|
|
"바로 시작해봅시다! 이전 수업에서 배운 [dplyr 동사들](https://dplyr.tidyverse.org/)을 활용할 것입니다. 복습하자면:\n",
|
|
"\n",
|
|
"- `dplyr::select()`: **열**을 선택하거나 제외하는 데 도움을 줍니다.\n",
|
|
"\n",
|
|
"- `dplyr::pivot_longer()`: 데이터를 \"길게\" 만들어 행의 수를 늘리고 열의 수를 줄이는 데 도움을 줍니다.\n",
|
|
"\n",
|
|
"- `dplyr::group_by()`와 `dplyr::summarise()`: 그룹별로 요약 통계를 찾고, 이를 깔끔한 표로 정리하는 데 도움을 줍니다.\n",
|
|
"\n",
|
|
"- `dplyr::filter()`: 조건을 만족하는 행만 포함하는 데이터의 하위 집합을 만듭니다.\n",
|
|
"\n",
|
|
"- `dplyr::mutate()`: 열을 생성하거나 수정하는 데 도움을 줍니다.\n",
|
|
"\n",
|
|
"Allison Horst가 만든 [*예술*-가득한 learnr 튜토리얼](https://allisonhorst.shinyapps.io/dplyr-learnr/#section-welcome)을 확인해보세요. 이 튜토리얼은 dplyr *(Tidyverse의 일부)*의 유용한 데이터 정리 함수들을 소개합니다.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "K3RF5bSCHC76"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Creates a functions that returns the top ingredients by class\r\n",
|
|
"\r\n",
|
|
"create_ingredient <- function(df){\r\n",
|
|
" \r\n",
|
|
" # Drop the id column which is the first colum\r\n",
|
|
" ingredient_df = df %>% select(-1) %>% \r\n",
|
|
" # Transpose data to a long format\r\n",
|
|
" pivot_longer(!cuisine, names_to = \"ingredients\", values_to = \"count\") %>% \r\n",
|
|
" # Find the top most ingredients for a particular cuisine\r\n",
|
|
" group_by(ingredients) %>% \r\n",
|
|
" summarise(n_instances = sum(count)) %>% \r\n",
|
|
" filter(n_instances != 0) %>% \r\n",
|
|
" # Arrange by descending order\r\n",
|
|
" arrange(desc(n_instances)) %>% \r\n",
|
|
" mutate(ingredients = factor(ingredients) %>% fct_inorder())\r\n",
|
|
" \r\n",
|
|
" \r\n",
|
|
" return(ingredient_df)\r\n",
|
|
"} # End of function"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "uB_0JR82HTPa"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"이제 이 함수를 사용하여 요리별로 가장 인기 있는 재료 상위 10개를 알아볼 수 있습니다. `thai_df`로 한번 시험해 봅시다.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "h9794WF8HWmc"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Call create_ingredient and display popular ingredients\r\n",
|
|
"thai_ingredient_df <- create_ingredient(df = thai_df)\r\n",
|
|
"\r\n",
|
|
"thai_ingredient_df %>% \r\n",
|
|
" slice_head(n = 10)"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "agQ-1HrcHaEA"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"이전 섹션에서는 `geom_col()`을 사용했으며, 이제 `geom_bar`를 사용하여 막대 그래프를 만드는 방법을 살펴보겠습니다. 추가 읽기를 위해 `?geom_bar`를 사용하세요.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "kHu9ffGjHdcX"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Make a bar chart for popular thai cuisines\r\n",
|
|
"thai_ingredient_df %>% \r\n",
|
|
" slice_head(n = 10) %>% \r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"steelblue\") +\r\n",
|
|
" xlab(\"\") + ylab(\"\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "fb3Bx_3DHj6e"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [],
|
|
"metadata": {
|
|
"id": "RHP_xgdkHnvM"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Get popular ingredients for Japanese cuisines and make bar chart\r\n",
|
|
"create_ingredient(df = japanese_df) %>% \r\n",
|
|
" slice_head(n = 10) %>%\r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"darkorange\", alpha = 0.8) +\r\n",
|
|
" xlab(\"\") + ylab(\"\")\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "019v8F0XHrRU"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"중국 요리는 어떤가요?\n"
|
|
],
|
|
"metadata": {
|
|
"id": "iIGM7vO8Hu3v"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Get popular ingredients for Chinese cuisines and make bar chart\r\n",
|
|
"create_ingredient(df = chinese_df) %>% \r\n",
|
|
" slice_head(n = 10) %>%\r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"cyan4\", alpha = 0.8) +\r\n",
|
|
" xlab(\"\") + ylab(\"\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "lHd9_gd2HyzU"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [],
|
|
"metadata": {
|
|
"id": "ir8qyQbNH1c7"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Get popular ingredients for Indian cuisines and make bar chart\r\n",
|
|
"create_ingredient(df = indian_df) %>% \r\n",
|
|
" slice_head(n = 10) %>%\r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"#041E42FF\", alpha = 0.8) +\r\n",
|
|
" xlab(\"\") + ylab(\"\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "ApukQtKjH5FO"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"마침내 한국 재료를 플롯하세요.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "qv30cwY1H-FM"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Get popular ingredients for Korean cuisines and make bar chart\r\n",
|
|
"create_ingredient(df = korean_df) %>% \r\n",
|
|
" slice_head(n = 10) %>%\r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"#852419FF\", alpha = 0.8) +\r\n",
|
|
" xlab(\"\") + ylab(\"\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "lumgk9cHIBie"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"데이터 시각화를 통해 서로 다른 요리 간 혼란을 야기하는 가장 흔한 재료들을 이제 `dplyr::select()`를 사용하여 제거할 수 있습니다.\n",
|
|
"\n",
|
|
"모두가 쌀, 마늘, 생강을 좋아하죠!\n"
|
|
],
|
|
"metadata": {
|
|
"id": "iO4veMXuIEta"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Drop id column, rice, garlic and ginger from our original data set\r\n",
|
|
"df_select <- df %>% \r\n",
|
|
" select(-c(1, rice, garlic, ginger))\r\n",
|
|
"\r\n",
|
|
"# Display new data set\r\n",
|
|
"df_select %>% \r\n",
|
|
" slice_head(n = 5)"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "iHJPiG6rIUcK"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## 레시피를 사용한 데이터 전처리 👩🍳👨🍳 - 불균형 데이터 다루기 ⚖️\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/recipes.png\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>@allison_horst의 작품</figcaption>\n",
|
|
"\n",
|
|
"이 강의가 요리에 관한 것이므로, `recipes`를 맥락에 맞게 살펴봐야 합니다.\n",
|
|
"\n",
|
|
"Tidymodels는 또 하나의 깔끔한 패키지를 제공합니다: 데이터 전처리를 위한 패키지인 `recipes`입니다.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "kkFd-JxdIaL6"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"우리의 요리 분포를 다시 한번 살펴봅시다.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "6l2ubtTPJAhY"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Distribution of cuisines\r\n",
|
|
"old_label_count <- df_select %>% \r\n",
|
|
" count(cuisine) %>% \r\n",
|
|
" arrange(desc(n))\r\n",
|
|
"\r\n",
|
|
"old_label_count"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "1e-E9cb7JDVi"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"음식 종류의 수에서 상당히 불균형한 분포가 있다는 것을 알 수 있습니다. 한국 요리는 태국 요리의 거의 3배에 달합니다. 불균형한 데이터는 종종 모델 성능에 부정적인 영향을 미칩니다. 이진 분류를 생각해봅시다. 만약 대부분의 데이터가 한 클래스에 속한다면, 머신러닝 모델은 단순히 해당 클래스의 데이터가 더 많기 때문에 그 클래스를 더 자주 예측하게 됩니다. 데이터를 균형 있게 조정하면 이러한 불균형을 제거하는 데 도움이 됩니다. 많은 모델은 관측치의 수가 동일할 때 가장 잘 작동하며, 따라서 불균형한 데이터에서는 어려움을 겪는 경향이 있습니다.\n",
|
|
"\n",
|
|
"불균형 데이터 세트를 처리하는 주요 방법은 두 가지가 있습니다:\n",
|
|
"\n",
|
|
"- 소수 클래스에 관측치를 추가하는 방법: `오버샘플링` 예: SMOTE 알고리즘 사용\n",
|
|
"\n",
|
|
"- 다수 클래스에서 관측치를 제거하는 방법: `언더샘플링`\n",
|
|
"\n",
|
|
"이제 `recipe`를 사용하여 불균형 데이터 세트를 처리하는 방법을 시연해 보겠습니다. 레시피는 데이터 분석을 준비하기 위해 데이터 세트에 어떤 단계를 적용해야 하는지를 설명하는 청사진으로 생각할 수 있습니다.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "soAw6826JKx9"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Load themis package for dealing with imbalanced data\r\n",
|
|
"library(themis)\r\n",
|
|
"\r\n",
|
|
"# Create a recipe for preprocessing data\r\n",
|
|
"cuisines_recipe <- recipe(cuisine ~ ., data = df_select) %>% \r\n",
|
|
" step_smote(cuisine)\r\n",
|
|
"\r\n",
|
|
"cuisines_recipe"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "HS41brUIJVJy"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"우리의 전처리 단계를 살펴봅시다.\n",
|
|
"\n",
|
|
"- `recipe()`를 공식과 함께 호출하면, `df_select` 데이터를 참조하여 변수들의 *역할*을 레시피에 지정합니다. 예를 들어, `cuisine` 열은 `outcome` 역할로 지정되었고, 나머지 열들은 `predictor` 역할로 지정되었습니다.\n",
|
|
"\n",
|
|
"- [`step_smote(cuisine)`](https://themis.tidymodels.org/reference/step_smote.html)는 레시피 단계의 *명세*를 생성하며, 소수 클래스의 새로운 예제를 해당 사례의 가장 가까운 이웃을 사용해 합성적으로 생성합니다.\n",
|
|
"\n",
|
|
"이제, 전처리된 데이터를 확인하고 싶다면, [**`prep()`**](https://recipes.tidymodels.org/reference/prep.html)과 [**`bake()`**](https://recipes.tidymodels.org/reference/bake.html)를 사용해야 합니다.\n",
|
|
"\n",
|
|
"`prep()`: 훈련 데이터 세트에서 필요한 매개변수를 추정하여 이후 다른 데이터 세트에 적용할 수 있도록 준비합니다.\n",
|
|
"\n",
|
|
"`bake()`: 준비된 레시피를 사용하여 어떤 데이터 세트에든 해당 작업을 적용합니다.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "Yb-7t7XcJaC8"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Prep and bake the recipe\r\n",
|
|
"preprocessed_df <- cuisines_recipe %>% \r\n",
|
|
" prep() %>% \r\n",
|
|
" bake(new_data = NULL) %>% \r\n",
|
|
" relocate(cuisine)\r\n",
|
|
"\r\n",
|
|
"# Display data\r\n",
|
|
"preprocessed_df %>% \r\n",
|
|
" slice_head(n = 5)\r\n",
|
|
"\r\n",
|
|
"# Quick summary stats\r\n",
|
|
"preprocessed_df %>% \r\n",
|
|
" introduce()"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "9QhSgdpxJl44"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"이제 우리의 요리 분포를 확인하고 불균형 데이터와 비교해 봅시다.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "dmidELh_LdV7"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Distribution of cuisines\r\n",
|
|
"new_label_count <- preprocessed_df %>% \r\n",
|
|
" count(cuisine) %>% \r\n",
|
|
" arrange(desc(n))\r\n",
|
|
"\r\n",
|
|
"list(new_label_count = new_label_count,\r\n",
|
|
" old_label_count = old_label_count)"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "aSh23klBLwDz"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"음! 데이터가 깔끔하고, 균형 잡혀 있으며, 정말 맛있네요 😋!\n",
|
|
"\n",
|
|
"> 일반적으로, 레시피는 모델링을 위한 전처리기로 사용되며, 데이터 세트를 모델링에 적합하게 준비하기 위해 어떤 단계를 적용해야 하는지를 정의합니다. 이 경우, 레시피를 수동으로 추정하는 대신 `workflow()`를 사용하는 것이 일반적입니다 (이전 수업에서 이미 본 것처럼요).\n",
|
|
">\n",
|
|
"> 따라서 tidymodels를 사용할 때는 보통 **`prep()`**과 **`bake()`**를 사용할 필요가 없지만, 레시피가 예상대로 작동하는지 확인하는 데 유용한 함수들입니다. 우리의 경우처럼 말이죠.\n",
|
|
">\n",
|
|
"> **`new_data = NULL`**로 준비된 레시피를 **`bake()`**하면, 레시피를 정의할 때 제공했던 데이터가 반환되지만, 전처리 단계를 거친 상태로 제공됩니다.\n",
|
|
"\n",
|
|
"이제 이 데이터를 저장하여 앞으로의 수업에서 사용할 수 있도록 해봅시다:\n"
|
|
],
|
|
"metadata": {
|
|
"id": "HEu80HZ8L7ae"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Save preprocessed data\r\n",
|
|
"write_csv(preprocessed_df, \"../../../data/cleaned_cuisines_R.csv\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "cBmCbIgrMOI6"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"이 새로운 CSV는 이제 루트 데이터 폴더에서 찾을 수 있습니다.\n",
|
|
"\n",
|
|
"**🚀도전 과제**\n",
|
|
"\n",
|
|
"이 커리큘럼에는 여러 흥미로운 데이터셋이 포함되어 있습니다. `data` 폴더를 탐색하여 이진 또는 다중 클래스 분류에 적합한 데이터셋이 있는지 확인해 보세요. 이 데이터셋에 대해 어떤 질문을 할 수 있을까요?\n",
|
|
"\n",
|
|
"## [**강의 후 퀴즈**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/20/)\n",
|
|
"\n",
|
|
"## **복습 및 자기 학습**\n",
|
|
"\n",
|
|
"- [themis 패키지](https://github.com/tidymodels/themis)를 확인해 보세요. 불균형 데이터 문제를 해결하기 위해 어떤 다른 기술을 사용할 수 있을까요?\n",
|
|
"\n",
|
|
"- Tidy models [참고 웹사이트](https://www.tidymodels.org/start/).\n",
|
|
"\n",
|
|
"- H. Wickham과 G. Grolemund, [*R for Data Science: Visualize, Model, Transform, Tidy, and Import Data*](https://r4ds.had.co.nz/).\n",
|
|
"\n",
|
|
"#### 감사의 인사:\n",
|
|
"\n",
|
|
"[`Allison Horst`](https://twitter.com/allison_horst/)에게 R을 더 친근하고 매력적으로 만들어주는 놀라운 삽화를 만들어 주셔서 감사합니다. 그녀의 [갤러리](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM)에서 더 많은 삽화를 확인하세요.\n",
|
|
"\n",
|
|
"[Cassie Breviu](https://www.twitter.com/cassieview)와 [Jen Looper](https://www.twitter.com/jenlooper)에게 이 모듈의 원래 Python 버전을 만들어 주셔서 감사합니다 ♥️\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/r_learners_sm.jpeg\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>@allison_horst의 작품</figcaption>\n"
|
|
],
|
|
"metadata": {
|
|
"id": "WQs5621pMGwf"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**면책 조항**: \n이 문서는 AI 번역 서비스 [Co-op Translator](https://github.com/Azure/co-op-translator)를 사용하여 번역되었습니다. 정확성을 위해 최선을 다하고 있으나, 자동 번역에는 오류나 부정확성이 포함될 수 있습니다. 원본 문서를 해당 언어로 작성된 상태에서 권위 있는 자료로 간주해야 합니다. 중요한 정보의 경우, 전문적인 인간 번역을 권장합니다. 이 번역 사용으로 인해 발생하는 오해나 잘못된 해석에 대해 당사는 책임을 지지 않습니다. \n"
|
|
]
|
|
}
|
|
]
|
|
} |