Tag: tidymodels

  • Machine Learning in R: รวบรวม 13 บทความสอนสร้าง Machine Learning ในภาษา R

    Machine Learning in R: รวบรวม 13 บทความสอนสร้าง Machine Learning ในภาษา R

    ภาษา R มี packages จำนวนมาก สำหรับสร้าง machine learning models

    ในบทความนี้ ผมรวบรวม 13 บทความสอนทำ machine learning ซึ่งแบ่งได้เป็น 4 กลุ่ม ดังนี้:

    1. Supervised learning models หรือการ train models แบบมีเฉลย
    2. Tree-based models หรือการสร้าง model ที่ใช้ decision trees
    3. Unsupervised learning models หรือการ train models แบบไม่มีเฉลย
    4. All-in-one packages หรือ packages สำหรับทำ machine learning แบบครบครัน ตั้งแต่การเตรียมข้อมูลไปจนถึงการประเมินประสิทธิภาพ รวมทั้งใช้ model ได้ตามต้องการ

    กลุ่มที่ 1. Supervised learning models (4 บทความ):

    1. KNN
    2. Naïve Bayes
    3. Linear regression
    4. Logistic regression
    5. Generalised linear models

    กลุ่มที่ 2. Tree-based models (3 บทความ):

    1. ภาค 1: Single tree และ random forest 1
    2. ภาค 2: Random forest 2
    3. ภาค 3: Boosted trees

    กลุ่มที่ 3. Unsupervised learning models (3 บทความ):

    1. k-means
    2. Hierarchical clustering analysis (HCA)
    3. Principal component analysis (PCA)

    กลุ่มที่ 4. All-in-one packages (2 บทความ):

    1. caret (เป็น package ที่เก่ากว่า)
    2. tidymodels (เป็น package ที่ใหม่กว่า)
  • tidymodels: แนะนำวิธีใช้แพ็กเกจ machine learning ที่ทรงพลัง ครบจบ และทันสมัยในภาษา R เพื่อสร้าง ประเมิน และปรับทูน model — ตัวอย่างการทำนายราคาบ้านใน Boston dataset

    tidymodels: แนะนำวิธีใช้แพ็กเกจ machine learning ที่ทรงพลัง ครบจบ และทันสมัยในภาษา R เพื่อสร้าง ประเมิน และปรับทูน model — ตัวอย่างการทำนายราคาบ้านใน Boston dataset

    ในการทำ machine learning (ML) ในภาษา R เรามี packages และ functions ที่หลากหลายให้เลือกใช้งาน ซึ่งแต่ละ package และ function มีวิธีใช้งานที่แตกต่างกันไป

    ยกตัวอย่างเช่น:

    glm() จาก base R สำหรับสร้าง regression models ต้องการ input 3 อย่าง คือ formula, data, และ family:

    glm(formula, data, family)

    knn() จาก class package สำหรับสร้าง KNN model ต้องการ input 4 อย่าง คือ ตัวแปรต้นของ training set, ตัวแปรต้นของ test set, ตัวแปรตามของ training set, และค่า k:

    knn(train_x, test_x, train_y, k)

    rpart() จาก rpart package สำหรับสร้าง decision tree model ต้องการ input 2 อย่าง คือ formula และ data:

    rpart(formula, data)

    การใช้งาน function ที่แตกต่างกันทำให้การสร้าง ML models เกิดความซับซ้อนโดยไม่จำเป็น และทำให้เกิดความผิดพลาดในการทำงานได้ง่าย

    tidymodels เป็น package ที่ถูกออกแบบมาเพื่อแก้ปัญหานี้โดยเฉพาะ

    tidymodels เป็น meta-package หรือ package ที่รวบรวม packages อื่นเอาไว้ เมื่อเราโหลด tidymodels เราจะสามารถใช้งาน 8 packages ที่ออกแบบมาให้ทำงานร่วมกัน ช่วยให้เราทำงาน ML ได้ครบ loop

    ทั้ง 8 packages ใน tidymodels ได้แก่:

    No.PackageML PhaseFor
    1rsamplePre-processingData resampling
    2recipesPre-processingFeature engineering
    3parsnipModellingModel fitting
    4tunePost-processingHyperparameter tuning
    5dialsPost-processingHyperparameter tuning
    6yardstickPost-processingModel evaluation
    7broomPost-processingFormat ผลลัพธ์ให้ดูง่าย
    8workflowAllรวม pre-processing, modeling, and post-processing ให้เป็น pipeline เดียวกัน

    ในบทความนี้ เราจะมาดูวิธีใช้ tidymodels เพื่อสร้าง ML models กัน

    ถ้าพร้อมแล้ว ไปเริ่มกันเลย


    1. 🔢 Dataset
      1. 🏠 Boston
      2. ⬇️ Get Boston
      3. 🧹 Prepare Boston
    2. 🛩️ tidymodels
      1. 🏁 Getting Started
      2. 🌊 Flows
    3. 🥐 Method #1. Standard Flow
      1. 1️⃣ Split the Data
      2. 2️⃣ Create a Recipe
      3. 3️⃣ Prep & Bake
      4. 4️⃣ Instantiate a Model
      5. 5️⃣ Fit the Model
      6. 6️⃣ Make Predictions
      7. 7️⃣ Evaluate the Model
    4. 🍰 Method #2. Workflow
      1. 1️⃣ Split the Data
      2. 2️⃣ Create a Recipe
      3. 3️⃣ Instantiate the Model
      4. 4️⃣ Bundle the Recipe and the Model
      5. 5️⃣ Fit the Model
      6. 6️⃣ Evaluate the Model
    5. 🍩 Bonus: Hyperparametre Tuning
      1. 1️⃣ Prepare
      2. 2️⃣ Tune
      3. 3️⃣ Select
      4. 4️⃣ Fit
      5. 5️⃣ Evaluate
    6. 😎 Summary
    7. 📚 Further Reading
    8. 💪 Example Project
    9. 😺 GitHub
    10. 📃 References
    11. ✅ R Book for Psychologists: หนังสือภาษา R สำหรับนักจิตวิทยา

    🔢 Dataset

    .

    🏠 Boston

    ในบทความนี้ เราจะใช้ Boston dataset จาก MASS package เป็นตัวอย่างในการทำงานกับ tidymodels กัน

    Boston เป็นชุดข้อมูลบ้านในเมืองบอสตัน รัฐแมสซาชูเซส ประเทศอเมริกา และมีข้อมูลทั้งหมด 14 columns ดังนี้:

    No.ColumnDescription
    1crimระดับอาชญากรรมในแต่ละเขต
    2znสัดส่วนพื้นที่อาศัย
    3indusสัดส่วนธุรกิจที่เป็น non-retail ในแต่ละเขต
    4chasเป็นพื้นที่ติดกับ Charles River ไหม (1 = ติด, 0 = ไม่ติด)
    5noxระดับ nitrogen oxide
    6rmจำนวนห้องโดยเฉลี่ย
    7ageสัดส่วย unit ที่มีคนเข้าอยู่ ซึ่งถูกสร้างก่อนปี ค.ศ. 1940
    8disระยะทางจากพื้นที่ทำงานในเมืองบอสตัน
    9radระดับการเข้าถึง radial highways
    10taxภาษีโรงเรือน
    11ptratioสัดส่วนนักเรียนต่อครูในแต่ละเขต
    12blackสัดส่วนผู้อยู่อาศัยที่เป็นคนผิวดำ
    13lstatสัดส่วนของประชากรที่มีฐานะยากจน
    14medvราคากลางของบ้านที่มีผู้อยู่อาศัย

    Note: อ่านรายละเอียดเพิ่มเติมเกี่ยวกับ Boston dataset ได้ที่ A Complete Guide to the Boston Dataset in R

    จุดประสงค์ของเราในการทำงานกับ Boston dataset คือ ทำนายราคาบ้าน (medv)

    .

    ⬇️ Get Boston

    ในการใช้งาน Boston เราสามารถเรียกใช้งานได้ผ่าน MASS package ดังนี้:

    1. ติดตั้ง MASS package
    2. โหลด MASS package
    3. โหลด Boston
    # Install package
    install.packages("MASS")
    
    # Load package
    library(MASS)
    
    # Load dataset
    data(Boston)
    

    .

    🧹 Prepare Boston

    ก่อนเริ่มใช้งาน Boston เราจะต้องปรับประเภทข้อมูลของ chas จาก numeric เป็น factor ก่อน ดังนี้:

    # Create a new dataset
    bt <- Boston
    
    # Convert `chas` to factor
    bt$chas <- factor(bt$chas,
                      levels = c(1, 0),
                      labels = c("tract bounds river", "otherwise"))
    
    # Preview
    head(Boston)
    

    ผลลัพธ์:

         crim zn indus chas   nox    rm  age    dis rad tax ptratio  black lstat medv
    1 0.00632 18  2.31    0 0.538 6.575 65.2 4.0900   1 296    15.3 396.90  4.98 24.0
    2 0.02731  0  7.07    0 0.469 6.421 78.9 4.9671   2 242    17.8 396.90  9.14 21.6
    3 0.02729  0  7.07    0 0.469 7.185 61.1 4.9671   2 242    17.8 392.83  4.03 34.7
    4 0.03237  0  2.18    0 0.458 6.998 45.8 6.0622   3 222    18.7 394.63  2.94 33.4
    5 0.06905  0  2.18    0 0.458 7.147 54.2 6.0622   3 222    18.7 396.90  5.33 36.2
    6 0.02985  0  2.18    0 0.458 6.430 58.7 6.0622   3 222    18.7 394.12  5.21 28.7
    

    เราสามารถเช็กผลลัพธ์ได้ด้วย str():

    # Check results
    str(bt)
    

    ผลลัพธ์:

    'data.frame':	506 obs. of  14 variables:
     $ crim   : num  0.00632 0.02731 0.02729 0.03237 0.06905 ...
     $ zn     : num  18 0 0 0 0 0 12.5 12.5 12.5 12.5 ...
     $ indus  : num  2.31 7.07 7.07 2.18 2.18 2.18 7.87 7.87 7.87 7.87 ...
     $ chas   : Factor w/ 2 levels "tract bounds river",..: 2 2 2 2 2 2 2 2 2 2 ...
     $ nox    : num  0.538 0.469 0.469 0.458 0.458 0.458 0.524 0.524 0.524 0.524 ...
     $ rm     : num  6.58 6.42 7.18 7 7.15 ...
     $ age    : num  65.2 78.9 61.1 45.8 54.2 58.7 66.6 96.1 100 85.9 ...
     $ dis    : num  4.09 4.97 4.97 6.06 6.06 ...
     $ rad    : int  1 2 2 3 3 3 5 5 5 5 ...
     $ tax    : num  296 242 242 222 222 222 311 311 311 311 ...
     $ ptratio: num  15.3 17.8 17.8 18.7 18.7 18.7 15.2 15.2 15.2 15.2 ...
     $ black  : num  397 397 393 395 397 ...
     $ lstat  : num  4.98 9.14 4.03 2.94 5.33 ...
     $ medv   : num  24 21.6 34.7 33.4 36.2 28.7 22.9 27.1 16.5 18.9 ...
    

    ตอนนี้ ทุก column มีข้อมูลถูกประเภทแล้ว เราพร้อมที่จะใช้ Boston กับ tidymodels แล้ว


    🛩️ tidymodels

    .

    🏁 Getting Started

    ในการเริ่มใช้งาน tidymodels เราต้องติดตั้งและโหลด package ก่อน

    ติดตั้ง (ทำครั้งแรกครั้งเดียว):

    # Install
    install.packages("tidymodels")
    

    โหลด (ทำทุกครั้งที่เริ่ม session ใหม่):

    # Load
    library(tidymodels)
    

    .

    🌊 Flows

    การใช้งาน tidymodels แบ่งเป็น 2 แบบ:

    1. Standard flow: เขียน code ยาวกว่า เหมาะกับการทำงานที่เราต้องการควบคุมการทำงานแต่ละขั้นด้วยตัวเอง
    2. Workflow: เขียน code สั้นกว่า เหมาะกับการสร้าง ML model อย่างรวดเร็ว

    เราไปดูวิธีเขียนแต่ละแบบกัน


    🥐 Method #1. Standard Flow

    สำหรับการใช้งาน tidymodels แบบ standard flow มีทั้งหมด 7 ขั้นตอน ได้แก่:

    1. Split the data
    2. Create a recipe
    3. Prep and bake
    4. Instantiate a model
    5. Fit the model
    6. Make predictions
    7. Evaluate the model

    .

    1️⃣ Split the Data

    ในขั้นแรก เราจะแบ่ง dataset ออกเป็น 2 ชุด ได้แก่:

    1. Training set สำหรับสร้าง model
    2. Test set สำหรับทดสอบ model

    โดยเราจะใช้ 3 functions จาก tidymodels ช่วย ได้แก่:

    No.FunctionFor
    1initial_split()กำหนดการแบ่ง dataset
    2training()สร้าง training set
    3testing()สร้าง test set

    ซึ่งเราเรียกใช้งานได้ดังนี้:

    # Set seed for reproducibility
    set.seed(2025)
    
    # Define the training set index
    bt_split <- initial_split(data = bt,
                              prop = 0.8,
                              strata = medv)
    
    # Create the training set
    bt_train <- training(bt_split)
    
    # Create the test set
    bt_test <- testing(bt_split)
    

    .

    2️⃣ Create a Recipe

    ในขั้นที่สอง เราจะสร้าง recipe หรือสูตรในการเตรียมข้อมูลกัน

    ในขั้นนี้ tidymodels มี 2 functions หลักให้เราใช้งาน ได้แก่:

    No.FunctionFor
    1recipe()กำหนดความสัมพันธ์ระหว่างตัวแปรต้นและตัวแปรตาม
    2step_*()data cleaning และ feature engineering

    ซึ่งเราเรียกใช้งานได้ดังนี้:

    # Create a recipe
    rec <- recipe(medv ~ .,
                  data = bt_train) |>
      
      ## Remove near-zero variance predictors
      step_nzv(all_numeric_predictors()) |>
      
      ## Handle multicollinearity
      step_corr(all_numeric_predictors(),
                threshold = 0.8)
    

    ในตัวอย่าง เราใช้:

    • recipe() กำหนดตัวแปรตาม (medv) และตัวแปรต้น (ตัวแปรที่เหลือทั้งหมด)
    • step_nzv() ลบตัวแปรต้นที่มี variance เข้าใกล้ 0
    • step_corr() จัดการกับ multicollinearity

    ศึกษาการใช้งาน step_*() อื่น ๆ ในการเตรียมข้อมูลได้ที่ tidymodels.org – Search recipe steps

    .

    3️⃣ Prep & Bake

    ในขั้นที่ 3 เราจะจัดเตรียมข้อมูลตาม recipe ที่กำหนด โดยเราจะใช้งาน 2 functions ได้แก่:

    No.FunctionFor
    1prep()เตรียม recipe
    2bake()เตรียมข้อมูลตาม recipe

    โดยเราแบ่งการทำงานเป็น 3 ขั้นตอน คือ:

    1. เตรียม recipe ด้วย prep()
    2. เตรียม training data ด้วย bake()
    3. เตรียม test data ด้วย bake()
    # Prepare the recipe
    rec_prep <- prep(rec,
                     data = bt_train)
    
    # Bake the training set
    bt_train_baked <- bake(rec_prep,
                           new_data = NULL)
    
    # Bake the test set
    bt_test_baked <- bake(rec_prep,
                          new_data = bt_test)
    

    .

    4️⃣ Instantiate a Model

    ในขั้นที่ 4 เราจะเรียกใช้ algorithm สำหรับ model ของเรา โดยในตัวอย่าง เราจะลองสร้าง decision tree กัน

    ในขั้นนี้ เรามี 3 functions จะเรียกใช้งาน ได้แก่:

    No.FunctionFor
    1decision_tree()สร้าง decision tree *
    2set_engine()กำหนด engine หรือ package ที่ใช้สร้าง model
    3set_mode()กำหนดประเภท model (classification หรือ regression)
    • Function นี้จะเปลี่ยนตาม model ที่ต้องการ โดยเราสามารถค้นหา model ที่ต้องการได้ที่ tidymodels.org – Search parsnip models
    # Instantiate the model
    dt_mod <- decision_tree() |>
      
      # Set the engine
      set_engine("rpart") |>
      
      # Set the mode
      set_mode("regression")
    

    ในตัวอย่าง เราใช้:

    • set_engine() เลือก rpart เป็น engine ในการสร้าง decision tree
    • set_mode() กำหนด mode เป็น regression เพราะเราต้องการทำนายราคาบ้านซึ่งเป็น continuous variable

    .

    5️⃣ Fit the Model

    ในขั้นที่ 5 เราจะ train model ด้วย training set ผ่าน fit():

    dt_mod_fit <- fit(dt_mod,
                      medv ~ .,
                      data = bt_train_baked)
    

    ตอนนี้ เราก็จะได้ model ที่พร้อมใช้งานมาแล้ว

    .

    6️⃣ Make Predictions

    ในขั้นที่ 6 เราจะใช้ model ทำนายข้อมูลเพื่อนำไปทดสอบความสามารถในขั้นที่ 7 ต่อไป

    ในขั้นนี้ เราจะใช้ predict() ร่วมกับ bind_cols() เพื่อเก็บผลลัพธ์การทำนายเอาไว้:

    # Make predictions
    dt_results <- predict(dt_mod_fit,
                          new_data = bt_test_baked,
                          type = "numeric") |>
      bind_cols(actual = bt_test_baked$medv)
    
    # Print the results
    dt_results
    

    ผลลัพธ์:

    # A tibble: 103 × 2
       .pred actual
       <dbl>  <dbl>
     1  34.6   34.7
     2  34.6   33.4
     3  11.8   16.5
     4  17.2   15.6
     5  27.3   30.8
     6  21.7   25  
     7  34.6   35.4
     8  21.7   21.2
     9  27.3   23.9
    10  44.3   43.8
    # ℹ 93 more rows
    # ℹ Use `print(n = ...)` to see more rows
    

    .

    7️⃣ Evaluate the Model

    ในขั้นสุดท้าย เราจะวิเคราะห์ความสามารถของ model กัน

    tidymodels มี functions สำหรับคำนวณค่าตัวชี้วัดต่าง ๆ เช่น:

    FunctionFor
    accuracy()ความแม่นยำในการทำนาย
    roc_auc()ความสมดุลในการทำนาย

    Note: ศึกษา functions ทั้งหมดได้ที่ tidymodels.org – Metric types

    สำหรับบทความนี้ เราจะเลือกใช้ 2 functions ได้แก่:

    No.FunctionFor
    1mae()Mean absolute error
    2rmse()Root mean squared error

    โดยเราเรียกใช้งาน functions ได้ 2 แบบ ดังนี้:

    แบบที่ 1. เรียกใช้ด้วยตัวเอง:

    # Calculate MAE
    dt_mae <- mae(dt_results,
                  truth = actual,
                  estimate = .pred)
    
    # Calculate RMSE
    dt_rmse <- rmse(dt_results,
                    truth = actual,
                    estimate = .pred)
    
    # Print MAE and RMSE
    cat("MAE:", round(dt_mae$.estimate, 2), "\\n")
    cat("RMSE:", round(dt_rmse$.estimate, 2), "\\n")
    

    ผลลัพธ์:

    MAE:
    # A tibble: 1 × 3
      .metric .estimator .estimate
      <chr>   <chr>          <dbl>
    1 mae     standard        3.70
    ------------------------------------------ 
    RMSE:
    # A tibble: 1 × 3
      .metric .estimator .estimate
      <chr>   <chr>          <dbl>
    1 rmse    standard        5.13
    

    .

    แบบที่ 2. เรียกใช้ผ่าน metric_set() ที่จะรวม functions ไว้ด้วยกัน:

    # Define a custom metrics
    dt_metrics <- metric_set(mae,
                             rmse)
    
    # Evaluate the model
    dt_eva_results <- dt_metrics(dt_results,
                                 truth = actual,
                                 estimate = .pred)
    
    # Print the results
    dt_eva_results
    

    ผลลัพธ์:

    # A tibble: 2 × 3
      .metric .estimator .estimate
      <chr>   <chr>          <dbl>
    1 mae     standard        3.70
    2 rmse    standard        5.13
    

    จะเห็นได้ว่า แบบที่ 2 สะดวกกว่า เพราะเราสามารถคำนวณค่าตัวชี้วัดหลายตัวได้ในครั้งเดียวกัน


    🍰 Method #2. Workflow

    เราได้ดูวิธีใช้งานแบบ standard flow ไปแล้ว เรามาดูวิธีใช้ tidymodels แบบ workflow ซึ่งมี 6 ขั้นตอน ดังนี้กัน:

    1. Split the data
    2. Create a recipe
    3. Instantiate the model
    4. Bundle the recipe and the model
    5. Fit the model
    6. Evaluate the model

    .

    1️⃣ Split the Data

    ในขั้นแรก เราจะแบ่ง dataset ออกเป็น 2 ชุด (เหมือนกับ standard flow):

    # Set seed for reproducibility
    set.seed(2025)
    
    # Define the training set index
    bt_split <- initial_split(data = bt,
                              prop = 0.8,
                              strata = medv)
    
    # Create the training set
    bt_train <- training(bt_split)
    

    จะสังเกตว่า เราจะไม่ได้สร้าง test set ในครั้งนี้

    .

    2️⃣ Create a Recipe

    ในขั้นที่ 2 เราจะสร้าง recipe (เหมือนกับ standard flow):

    # Create a recipe
    rec <- recipe(medv ~ .,
                  data = bt_train) |>
      
      ## Remove near-zero variance predictors
      step_nzv(all_numeric_predictors()) |>
      
      ## Handle multicollinearity
      step_corr(all_numeric_predictors(),
                threshold = 0.8)
    

    .

    3️⃣ Instantiate the Model

    ในขั้นที่ 3 ของ standard flow เราจะเตรียม recipe และข้อมูลกัน

    แต่ใน workflow เราจะสร้าง model (ซึ่งเป็นขั้นที่ 4 ของ standard flow) แทน:

    # Instantiate the model
    dt_mod <- decision_tree() |>
      
      ## Set the engine
      set_engine("rpart") |>
      
      ## Set the mode
      set_mode("regression")
    

    .

    4️⃣ Bundle the Recipe and the Model

    ในขั้นที่ 4 เราจะรวม recipe และ model เข้าด้วยกัน เพื่อทำให้การทำงานต่อจากนี้ง่ายขึ้น ผ่านการใช้ 3 functions ดังนี้:

    No.FunctionFor
    1workflow()สร้าง workflow object
    2add_recipe()เพิ่ม recipe ใน workflow object
    3add_model()เพิ่ม model ใน workflow object

    Note: อ่านเพิ่มเติมเกี่ยวกับ workflow object ได้ที่ tidymodels.org – workflows และ Tidy Modeling with R – A Model Workflow

    # Bundle the recipe and the model
    dt_wfl <- workflow() |>
      
      ## Add recipe
      add_recipe(rec) |>
      
      ## Add model
      add_model(dt_mod)
    

    .

    5️⃣ Fit the Model

    ในขั้นที่ 5 เราจะ train model ด้วย training set โดยเราจะใช้ last_fit() แทน fit()

    ทั้งนี้ last_fit() ต้องการ input 3 อย่าง ได้แก่:

    No.InputDescription
    1objectworkflow object
    2splitobject ที่ได้จาก initial_split()
    3metricsตัวชี้วัดที่เก็บไว้ใน metric_set()
    # Fit the model
    dt_last_fit <- last_fit(dt_wfl,
                            split = bt_split,
                            metrics = metric_set(mae, rmse))
    

    .

    6️⃣ Evaluate the Model

    นอกจาก train model แล้ว last_fit() ยังทำหน้าที่อีก 2 อย่าง ได้แก่:

    1. ทำนายข้อมูลจาก model ที่ได้
    2. ประเมิน model ตามตัวชี้วัดที่กำหนดใน metric_set()

    นั่นหมายคงามว่า last_fit() ได้ให้ผลลัพธ์ในการประเมิน model มาแล้ว เราเพียงแค่ต้องเรียกผลลัพธ์ออกมาแสดงเท่านั้น ซึ่งเราสามารถทำได้ด้วย 2 functions นี้:

    No.FunctionFor
    1collect_predictions()ดึงข้อมูลที่ model ทำนาย
    2collect_metrics()ดึงค่าตัวชี้วัดความสามารถของ model

    ดึงผลลัพธ์ในการทำนายได้ด้วย collect_predictions():

    # Collect predictions
    dt_predictions <- collect_predictions(dt_last_fit)
    
    # Print predictions
    dt_predictions
    

    ผลลัพธ์:

    # A tibble: 103 × 5
       .pred id                .row  medv .config             
       <dbl> <chr>            <int> <dbl> <chr>               
     1  34.6 train/test split     3  34.7 Preprocessor1_Model1
     2  34.6 train/test split     4  33.4 Preprocessor1_Model1
     3  11.8 train/test split     9  16.5 Preprocessor1_Model1
     4  17.2 train/test split    25  15.6 Preprocessor1_Model1
     5  27.3 train/test split    40  30.8 Preprocessor1_Model1
     6  21.7 train/test split    53  25   Preprocessor1_Model1
     7  34.6 train/test split    56  35.4 Preprocessor1_Model1
     8  21.7 train/test split    79  21.2 Preprocessor1_Model1
     9  27.3 train/test split    82  23.9 Preprocessor1_Model1
    10  44.3 train/test split    99  43.8 Preprocessor1_Model1
    # ℹ 93 more rows
    # ℹ Use `print(n = ...)` to see more rows
    

    Note:

    • .pred คือ ราคาที่ทำนาย
    • medv คือ ราคาจริง

    .

    ดึงตัวบ่งชี้ที่ได้จาก last_fit() ด้วย collect_metrics():

    # Collect metrics
    dt_metrics <- collect_metrics(dt_last_fit)
    
    # Print metrics
    dt_metrics
    

    ผลลัพธ์:

    # A tibble: 2 × 4
      .metric .estimator .estimate .config             
      <chr>   <chr>          <dbl> <chr>               
    1 mae     standard        3.70 Preprocessor1_Model1
    2 rmse    standard        5.13 Preprocessor1_Model1
    

    จะเห็นได้ว่า แม้ workflow จะมีจำนวนขั้นตอนใกล้เคียงกับ standard flow แต่การทำงานแบบ workflow มีความสะดวกกว่ามาก


    🍩 Bonus: Hyperparametre Tuning

    ส่งท้าย เรามาดูวิธีใช้ tidymodels เพื่อทำ hyperparametre tuning ใน 5 ขั้นตอนกัน:

    1. Prepare
    2. Tune
    3. Select
    4. Fit
    5. Evaluate

    .

    1️⃣ Prepare

    ในการทำ hyperparametre tuning เราสามารถเขียนได้ทั้งแบบ standard flow และ workflow

    ในบทความนี้ เราจะดูวิธีทำแบบ workflow ซึ่งเป็นวิธีที่ง่ายกว่ากัน

    ในขั้นแรก เราต้องเตรียมของสำหรับ hyperparametre tuning 4 ข้อ ได้แก่:

    No.InputDescription
    1objectworkflow object ที่รวม recipe และ model เอาไว้
    2resamplesการแบ่ง training set เพื่อทดสอบ hyperparametres
    3gridการจับคู่ hyperparametres
    4metricsตัวชี้วัดที่ต้องการใช้ประเมิน hyperparametres

    ข้อที่ 1. เตรียม object

    เราเริ่มจากแบ่งข้อมูล:

    # Set seed for reproducibility
    set.seed(2025)
    
    # Define the training set index
    bt_split <- initial_split(data = bt,
                              prop = 0.8,
                              strata = medv)
    
    # Create the training set
    bt_train <- training(bt_split)
    

    สร้าง recipe:

    # Create a recipe
    rec <- recipe(medv ~ .,
                  data = bt_train) |>
      
      ## Remove near-zero variance predictors
      step_nzv(all_numeric_predictors()) |>
      
      ## Handle multicollinearity
      step_corr(all_numeric_predictors(),
                threshold = 0.8)
    

    จากนั้น เรียกใช้ model โดยเราจะต้องกำหนด hyperparametre ที่ต้องการปรับ ด้วย tune():

    # Define the tuning parameters
    dt_model_tune <- decision_tree(cost_complexity = tune(),
                                   tree_depth = tune(),
                                   min_n = tune()) |>
      
      ## Set engine
      set_engine("rpart") |>
      
      ## Set mode
      set_mode("regression")
    

    สุดท้าย เรารวม recipe และ model ไว้ใน workflow object:

    # Define the workflow with tuning
    bt_wfl_tune <- workflow() |>
      
      ## Add recipe
      add_recipe(rec) |>
      
      ## Add model
      add_model(dt_model_tune)
    

    ข้อที่ 2. Resamples ซึ่งในที่นี้ เราจะใช้ k-fold cross-validation ที่แบ่ง training set ออกเป็น 5 ส่วน (4 ส่วนเพื่อ train และ 1 ส่วนเพื่อ test) แบบนี้:

    # Set k-fold cross-validation for tuning
    hpt_cv <- vfold_cv(bt_train,
                       v = 5,
                       strata = medv)
    

    ข้อที่ 3. Grid ซึ่งเราจะใช้การจับคู่แบบสุ่มผ่าน grid_random():

    # Set seed for reproducibility
    set.seed(2025)
    
    # Define the grid for tuning
    hpt_grid <- grid_random(cost_complexity(range = c(-5, 0), trans = log10_trans()),
                            tree_depth(range = c(1, 20)),
                            min_n(range = c(2, 50)),
                            size = 20)
    

    ข้อที่ 4. Metrics ซึ่งเราต้องเก็บไว้ใน metric_set():

    # Define metrics
    hpt_metrics = metric_set(mae,
                             rmse)
    

    .

    2️⃣ Tune

    หลังจากเตรียม input ครบแล้ว เราสามารถ tune model ได้ด้วย tune_grid():

    # Tune the model
    dt_tune_results <- tune_grid(bt_wfl_tune,
                                 resamples = hpt_cv,
                                 grid = hpt_grid,
                                 metrics = hpt_metrics)
    

    .

    3️⃣ Select

    หลังจาก tune แล้ว เราสามารถดูค่า hyperparametres ที่ดีที่สุดตามตัวบ่งชี้ที่เราเลือกได้ด้วย show_best()

    โดยในตัวอย่าง เราจะลองเลือก hyperparametres ที่ดีที่สุด 5 ชุดแรก โดยดูจาก RMSE:

    # Show the best model
    show_best(dt_tune_results,
              metric = "rmse",
              n = 5)
    

    ผลลัพธ์:

    # A tibble: 5 × 9
      cost_complexity tree_depth min_n .metric .estimator  mean     n
                <dbl>      <int> <int> <chr>   <chr>      <dbl> <int>
    1       0.00311            3     5 rmse    standard    4.55     5
    2       0.0167            16    12 rmse    standard    4.70     5
    3       0.00150            5    28 rmse    standard    4.75     5
    4       0.0000436         18    14 rmse    standard    4.88     5
    5       0.0000345         11    39 rmse    standard    4.88     5
    # ℹ 2 more variables: std_err <dbl>, .config <chr>
    

    จากนั้น เราสามารถเลือกค่า hyperparametres ที่ดีที่สุดได้ด้วย select_best():

    # Select the best model
    dt_best_params <- select_best(dt_tune_results,
                                  metric = "rmse")
    

    .

    4️⃣ Fit

    ในขั้นที่ 4 เราจะใส่ค่า hyperparametres ที่เลือกมาเข้าไปใน workflow object ผ่าน finalize_workflow():

    # Finalise the best workflow
    dt_wkl_best <- finalize_workflow(bt_wfl_tune,
                                     dt_best_params)
    

    จากนั้น train model ด้วย last_fit():

    # Fit the best model
    dt_best_fit <- last_fit(dt_wkl_best,
                            split = bt_split,
                            metrics = metric_set(mae, rmse))
    

    .

    5️⃣ Evaluate

    สุดท้าย เราจะทดสอบ model ด้วย collect_predictions() และ collect_metrics():

    # Collect predictions
    predictions_best <- collect_predictions(dt_best_fit)
    
    # Print predictions
    predictions_best
    

    ผลลัพธ์:

    # A tibble: 103 × 5
       .pred id                .row  medv .config             
       <dbl> <chr>            <int> <dbl> <chr>               
     1  32.3 train/test split     3  34.7 Preprocessor1_Model1
     2  32.3 train/test split     4  33.4 Preprocessor1_Model1
     3  11.8 train/test split     9  16.5 Preprocessor1_Model1
     4  17.2 train/test split    25  15.6 Preprocessor1_Model1
     5  22.6 train/test split    40  30.8 Preprocessor1_Model1
     6  22.6 train/test split    53  25   Preprocessor1_Model1
     7  32.3 train/test split    56  35.4 Preprocessor1_Model1
     8  22.6 train/test split    79  21.2 Preprocessor1_Model1
     9  22.6 train/test split    82  23.9 Preprocessor1_Model1
    10  34.5 train/test split    99  43.8 Preprocessor1_Model1
    # ℹ 93 more rows
    # ℹ Use `print(n = ...)` to see more rows
    

    และ

    # Collect metrics
    metrics_best <- collect_metrics(dt_best_fit)
    
    # Print metrics
    metrics_best
    

    ผลลัพธ์:

    # A tibble: 2 × 4
      .metric .estimator .estimate .config             
      <chr>   <chr>          <dbl> <chr>               
    1 mae     standard        3.48 Preprocessor1_Model1
    2 rmse    standard        4.68 Preprocessor1_Model1
    

    จะเห็นว่า hyperparametre tuning ทำให้ model ของเรามีประสิทธิภาพมากขึ้น เพราะมี MAE (3.70 vs 3.48) และ RMSE (5.13 vs 4.68) ที่ลดลง


    😎 Summary

    ในบทความนี้ เราได้ดูวิธีสร้าง ประเมิน และปรับ ML model ด้วย tidymodels ซึ่ง functions ต่าง ๆ ที่เราได้เรียนรู้สรุปตาม ML phase ได้ดังนี้:

    Pre-processing:

    FunctionDescription
    initial_split()แบ่งข้อมูล
    training()สร้าง training set
    testing()สร้าง test set
    recipe()กำหนดตัวแปรต้น ตัวแปรตาม
    step_*()กำหนดขั้นการแปลงข้อมูล
    prep()เตรียม recipe
    bake()เตรียมข้อมูล

    Modelling:

    FunctionDescription
    decision_tree()สร้าง decision tree
    set_engine()เรียกใช้ ML engine
    set_mode()กำหนดประเภท model
    fit()train model
    last_fit()train, ทำนาย, และประเมิน model

    Post-processing:

    FunctionDescription
    mae()คำนวณ MAE
    rmse()คำนวณ RMSE
    metric_set()กำหนดชุดตัวชี้วัด
    collect_predictions()เรียกดูคำทำนาย
    collect_metrics()เรียกดูตัวชี้วัด
    tune()กำหนด hyperparametres ที่ต้องการ tune
    vfold_cv()สร้าง k-fold cross-validation
    grid_random()สุ่มสร้างค่า hyperparametres ที่ต้องการทดสอบ
    tune_grid()tune model

    All:

    FunctionDescription
    workflow()รวม recipe และ model ไว้ด้วยกัน

    📚 Further Reading

    สำหรับคนที่สนใจ สามารถศึกษาเกี่ยวกับ tidymodels เพิ่มเติมได้ที่:


    💪 Example Project

    ดูตัวอย่างการใช้งาน tidymodels เพื่อสำหรับ data analytics project ได้ที่ Exploring & Predicting Employee Attrition With Machine Learning in R


    😺 GitHub

    ดู code ทั้งหมดในบทความนี้ได้ที่ GitHub:


    📃 References


    ✅ R Book for Psychologists: หนังสือภาษา R สำหรับนักจิตวิทยา

    📕 ขอฝากหนังสือเล่มแรกในชีวิตด้วยนะครับ 😆

    🙋 ใครที่กำลังเรียนจิตวิทยาหรือทำงานสายจิตวิทยา และเบื่อที่ต้องใช้ software ราคาแพงอย่าง SPSS และ Excel เพื่อทำข้อมูล

    💪 ผมขอแนะนำ R Book for Psychologists หนังสือสอนใช้ภาษา R เพื่อการวิเคราะห์ข้อมูลทางจิตวิทยา ที่เขียนมาเพื่อนักจิตวิทยาที่ไม่เคยมีประสบการณ์เขียน code มาก่อน

    ในหนังสือ เราจะปูพื้นฐานภาษา R และพาไปดูวิธีวิเคราะห์สถิติที่ใช้บ่อยกัน เช่น:

    • Correlation
    • t-tests
    • ANOVA
    • Reliability
    • Factor analysis

    🚀 เมื่ออ่านและทำตามตัวอย่างใน R Book for Psychologists ทุกคนจะไม่ต้องพึง SPSS และ Excel ในการทำงานอีกต่อไป และสามารถวิเคราะห์ข้อมูลด้วยตัวเองได้ด้วยความมั่นใจ

    แล้วทุกคนจะแปลกใจว่า ทำไมภาษา R ง่ายขนาดนี้ 🙂‍↕️

    👉 สนใจดูรายละเอียดหนังสือได้ที่ meb: