scikit-learn ColumnTransformer 2026: จัดการฟีเจอร์ตัวเลขและ Categorical ในไปป์ไลน์เดียว

คู่มือใช้ ColumnTransformer ของ scikit-learn 2026 จัดการฟีเจอร์ตัวเลขและ categorical ในไปป์ไลน์เดียว พร้อมตัวอย่าง Pipeline, GridSearchCV, custom transformer และวิธีแก้ error ที่พบบ่อย

ColumnTransformer sklearn คู่มือ (2026)

อัปเดตล่าสุด: 5 สิงหาคม 2026

ColumnTransformer ของ scikit-learn คือคลาสสำหรับ apply ตัวแปลง (transformer) ที่ต่างกัน ไปยัง คอลัมน์ที่ต่างกัน ของ DataFrame ในขั้นตอนเดียว เช่น scale คอลัมน์ตัวเลขด้วย StandardScaler พร้อมกับ one-hot encode คอลัมน์ categorical ด้วย OneHotEncoder ผลลัพธ์ถูกเชื่อมกลับเป็น matrix เดียวที่พร้อมส่งเข้า estimator ได้ทันที บทความนี้เราจะพาไปดูวิธีใช้ตั้งแต่พื้นฐาน จนถึงเทคนิคขั้นสูงอย่าง make_column_selector, custom transformer และการดึงชื่อฟีเจอร์หลัง transform ด้วย get_feature_names_out() โดยยึด scikit-learn เวอร์ชัน 1.9 (ปี 2026) เป็นหลัก

บอกก่อนเลยว่า ผมเจอบั๊กจาก data leakage ตอนทำ Kaggle competition ครั้งหนึ่ง เพราะ preprocess ข้อมูลรวมกันก่อนแบ่ง train/test พอ ColumnTransformer เข้ามาช่วย ปัญหานี้หายไปเลย

  • ColumnTransformer แยก apply preprocessing แต่ละแบบไปยังคอลัมน์แต่ละกลุ่ม แล้วเชื่อมผลลัพธ์กลับเป็น array เดียว โดยไม่มี data leakage เพราะเรียก fit_transform เฉพาะบน training set
  • ตั้งแต่ scikit-learn 1.2 เป็นต้นมา ทุก transformer รองรับ get_feature_names_out() ทำให้ตามชื่อฟีเจอร์หลัง transform ได้แล้ว ไม่ต้อง hack เอง
  • ใช้ make_column_selector(dtype_include=np.number) เพื่อเลือกคอลัมน์ตามชนิดข้อมูลอัตโนมัติ ประหยัดโค้ดกว่าการระบุชื่อคอลัมน์ทีละตัว
  • ใส่ ColumnTransformer ไว้ใน Pipeline ร่วมกับ estimator เพื่อใช้กับ GridSearchCV ได้ทันที และ tune hyperparameter ของทั้ง preprocessor และ model พร้อมกัน
  • พารามิเตอร์ remainder='passthrough' ให้คอลัมน์ที่ไม่ได้ระบุถูกส่งต่อโดยไม่แก้ไข ส่วน 'drop' (ค่าเริ่มต้น) จะทิ้งไป
  • ต่างจาก Pipeline ที่ทำงานแบบลำดับขั้น (sequential), ColumnTransformer ทำงานแบบขนาน (parallel) ต่อคอลัมน์ ทั้งสองมักถูกใช้ร่วมกัน

ColumnTransformer คืออะไร และใช้ทำอะไร

ColumnTransformer คือ meta-estimator ในโมดูล sklearn.compose ที่ออกแบบมาสำหรับข้อมูลที่มี ชนิด (dtype) หลากหลาย ในตารางเดียว ปัญหาคลาสสิกที่มันช่วยแก้คือ ใน DataFrame ทั่วไปคุณมักมีคอลัมน์ตัวเลข (อายุ, ราคา, จำนวนคลิก) ปะปนกับคอลัมน์ categorical (เพศ, ประเทศ, ประเภทสินค้า) และอาจมีคอลัมน์ข้อความหรือวันที่อีก transformer แต่ละตัว เช่น StandardScaler ต้องการเฉพาะตัวเลข ส่วน OneHotEncoder ต้องการเฉพาะ categorical ถ้าคุณ apply แบบสุ่มบนทั้ง DataFrame จะได้ error ทันที

วิธีเก่าที่ต้องแยก DataFrame ออกเป็น df_num, df_cat, transform แยก แล้วค่อย np.hstack กลับ ก็เขียนยาว แถมยังเสี่ยงต่อ data leakage ถ้าคุณเผลอ fit_transform บนข้อมูล validation หรือ test ColumnTransformer จัดการปัญหาเหล่านี้ด้วย API เดียว โดยคุณกำหนดว่าคอลัมน์ไหนควรผ่าน transformer ตัวไหน แล้วคลาสจัดการเรื่อง fit, transform และเชื่อมผลลัพธ์ให้ทั้งหมด

ยิ่งไปกว่านั้น เมื่อคุณห่อ ColumnTransformer ไว้ใน Pipeline เดียวกับ estimator (เช่น LogisticRegression) คุณจะได้ object เดียวที่พร้อม fit, predict, score รวมทั้ง cross-validate ได้อย่างปลอดภัย เพราะทุก fold จะ fit preprocessor ใหม่บนเฉพาะ training portion ของ fold นั้น ตัวอย่าง Column Transformer with Mixed Types จาก scikit-learn เป็นเทมเพลตที่ผมมักคัดลอกมาใช้เป็นจุดเริ่มต้นเสมอ

การใช้งานพื้นฐานพร้อมตัวอย่างครบวงจร

เริ่มด้วย workflow ที่พบบ่อยที่สุด คือ dataset ที่มีทั้งคอลัมน์ตัวเลขและ categorical เราจะใช้ Titanic dataset ที่โหลดมาจาก OpenML ซึ่งมีทั้งคอลัมน์ที่ต้อง impute, scale, และ encode ในเวลาเดียวกัน

import pandas as pd
import numpy as np
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_openml

# 1) โหลดข้อมูล Titanic (มี dtype ผสม)
X, y = fetch_openml("titanic", version=1, as_frame=True, return_X_y=True)
X = X[["age", "fare", "pclass", "sex", "embarked"]]
y = (y == "1").astype(int)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 2) กำหนดคอลัมน์แต่ละกลุ่ม
num_cols = ["age", "fare"]
cat_cols = ["pclass", "sex", "embarked"]

# 3) สร้าง sub-pipeline สำหรับแต่ละกลุ่ม
num_pipe = Pipeline([
    ("imputer", SimpleImputer(strategy="median")),
    ("scaler", StandardScaler()),
])
cat_pipe = Pipeline([
    ("imputer", SimpleImputer(strategy="most_frequent")),
    ("encoder", OneHotEncoder(handle_unknown="ignore", sparse_output=False)),
])

# 4) รวมด้วย ColumnTransformer
preprocessor = ColumnTransformer(
    transformers=[
        ("num", num_pipe, num_cols),
        ("cat", cat_pipe, cat_cols),
    ],
    remainder="drop",
    verbose_feature_names_out=False,
)

# 5) ต่อเข้ากับ estimator
model = Pipeline([
    ("prep", preprocessor),
    ("clf", LogisticRegression(max_iter=1000)),
])

model.fit(X_train, y_train)
print("Test accuracy:", model.score(X_test, y_test))

สังเกตว่าเราไม่ได้แตะข้อมูล X_train เลย นอกจากส่งเข้า fit ColumnTransformer จัดการทุกอย่าง ตั้งแต่การเลือกคอลัมน์, impute, scale, encode แล้วเชื่อมกลับก่อนส่งต่อไปยัง LogisticRegression ถ้าอยากดู array หลัง preprocess ก็เรียก preprocessor.fit_transform(X_train) ได้โดยตรงเพื่อ debug (ผมทำแบบนี้ทุกครั้งก่อน deploy เพื่อให้แน่ใจว่าไม่มีคอลัมน์แปลกๆ หลุดออกมา)

เลือกคอลัมน์อัตโนมัติด้วย make_column_selector

การระบุชื่อคอลัมน์ทีละตัวใช้ได้ดีเมื่อ dataset เล็ก แต่ถ้ามี 200+ คอลัมน์คุณจะไม่อยากพิมพ์มือแน่ๆ make_column_selector ให้คุณเลือกคอลัมน์ตาม dtype หรือ regular expression บนชื่อคอลัมน์ได้อัตโนมัติ ทำให้ pipeline generalize ได้กับ dataset ใหม่โดยไม่ต้องแก้โค้ด

from sklearn.compose import make_column_selector, make_column_transformer

# เลือกทุกคอลัมน์ตัวเลข (int, float) ให้ scale
# เลือกทุกคอลัมน์ object/category ให้ encode
preprocessor = make_column_transformer(
    (num_pipe, make_column_selector(dtype_include=np.number)),
    (cat_pipe, make_column_selector(dtype_include=["object", "category"])),
    remainder="drop",
    verbose_feature_names_out=False,
)

# ใช้ regex เพื่อเลือกคอลัมน์ที่ขึ้นต้นด้วย 'log_'
log_selector = make_column_selector(pattern="^log_")

make_column_transformer เป็น shorthand ที่ตั้งชื่อ transformer อัตโนมัติ (เช่น pipeline-1) จึงไม่ต้องเขียน tuple ยาวๆ แต่ข้อเสียคือชื่ออัตโนมัติอาจไม่สื่อความหมาย ถ้าคุณอยากอ้างถึงชื่อใน GridSearchCV ให้ใช้ ColumnTransformer ตรงๆ พร้อมชื่อที่คุณกำหนดเองจะเข้าใจง่ายกว่ามาก

จัดการค่าที่หายไปใน ColumnTransformer

คำถามที่พบบ่อยคือ "impute ควรอยู่ก่อนหรือหลัง ColumnTransformer?" คำตอบคือ อยู่ข้างในเป็น sub-pipeline ต่อคอลัมน์แต่ละกลุ่ม เพราะกลยุทธ์ impute ต่างกันไปตามชนิดข้อมูล ตัวเลขมักใช้ค่ากลาง (median) ส่วน categorical ใช้ค่าที่พบบ่อย (most_frequent) หรือ constant "Unknown"

from sklearn.impute import KNNImputer, SimpleImputer
from sklearn.preprocessing import RobustScaler

# ตัวเลข: impute ด้วย KNN แล้ว RobustScaler สำหรับ outlier
num_pipe_v2 = Pipeline([
    ("imputer", KNNImputer(n_neighbors=5)),
    ("scaler", RobustScaler()),
])

# Categorical: impute เป็น 'missing' แล้ว one-hot
cat_pipe_v2 = Pipeline([
    ("imputer", SimpleImputer(strategy="constant", fill_value="missing")),
    ("encoder", OneHotEncoder(handle_unknown="ignore", sparse_output=False,
                              min_frequency=10)),
])

preprocessor_v2 = ColumnTransformer([
    ("num", num_pipe_v2, num_cols),
    ("cat", cat_pipe_v2, cat_cols),
])

min_frequency=10 ใน OneHotEncoder เป็นฟีเจอร์ตั้งแต่ scikit-learn 1.1 ที่รวม category หายากเข้าเป็น infrequent_sklearn อัตโนมัติ ช่วยลดจำนวนคอลัมน์และป้องกัน overfitting บน category ที่มีตัวอย่างน้อย ถ้าอยากจัดการปัญหา imbalanced target class ควบคู่กันด้วย ดูวิธีในคู่มือจัดการข้อมูลไม่สมดุลด้วย SMOTEที่เราเขียนไว้

รวม ColumnTransformer เข้ากับ Pipeline และ GridSearchCV

จุดแข็งที่แท้จริงของ ColumnTransformer ปรากฏชัดเมื่อรวมกับ Pipeline และ GridSearchCV คุณสามารถ tune hyperparameter ของ ทั้ง preprocessor และ estimator พร้อมกันได้ โดยระบบจะ fit preprocessor ใหม่ในทุก fold ป้องกัน data leakage อัตโนมัติ

from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier

full = Pipeline([
    ("prep", preprocessor_v2),
    ("clf", RandomForestClassifier(random_state=42)),
])

param_grid = {
    # tune imputer ภายใน ColumnTransformer
    "prep__num__imputer__n_neighbors": [3, 5, 10],
    # tune encoder threshold
    "prep__cat__encoder__min_frequency": [5, 10, 20],
    # tune estimator
    "clf__n_estimators": [100, 300],
    "clf__max_depth": [None, 10, 20],
}

search = GridSearchCV(full, param_grid, cv=5, scoring="roc_auc", n_jobs=-1)
search.fit(X_train, y_train)

print("Best params:", search.best_params_)
print("Best CV AUC:", search.best_score_)

รูปแบบชื่อ parameter จะเป็น {step_name}__{sub_step}__{param} ใช้ double underscore เท่านั้น สังเกตว่าเราสามารถเข้าถึง imputer.n_neighbors ที่ฝังอยู่ 3 ชั้นได้ นี่คือเหตุผลว่าทำไมการตั้งชื่อ transformer ที่มีความหมายจึงสำคัญ ถ้าใช้ make_column_transformer คุณต้องอ้างถึง pipeline-1__imputer__n_neighbors ซึ่งอ่านยากกว่ามาก สำหรับผู้ที่ต้องการเทคนิค tuning ขั้นสูงเพิ่มเติม ลองอ่านคู่มือปรับ Hyperparameter ด้วย GridSearchCV, RandomizedSearchCV และ Optunaของเรา

ดึงชื่อฟีเจอร์หลัง transform ด้วย get_feature_names_out

ปัญหาคลาสสิกที่เคยทำให้ผู้ใช้ปวดหัวคือ หลัง ColumnTransformer.transform() คุณได้ NumPy array ที่ไม่มีชื่อคอลัมน์ ทำให้ตีความ feature importance หรือ SHAP value ยากมาก ตั้งแต่ scikit-learn 1.2 เป็นต้นมา ทุก transformer มาตรฐานรองรับ get_feature_names_out() เต็มรูปแบบแล้ว (ตาม SLEP007 proposal ซึ่งเป็น API ที่ผมรอมานาน)

preprocessor.fit(X_train)

# ดึงชื่อฟีเจอร์ทุกตัวหลัง transform
feature_names = preprocessor.get_feature_names_out()
print(feature_names)
# ['age' 'fare' 'pclass_1' 'pclass_2' 'pclass_3'
#  'sex_female' 'sex_male' 'embarked_C' 'embarked_Q' 'embarked_S']

# แปลง array เป็น DataFrame ที่มีชื่อคอลัมน์เพื่ออ่านง่าย
import pandas as pd
X_train_prep = preprocessor.transform(X_train)
df_prep = pd.DataFrame(X_train_prep, columns=feature_names, index=X_train.index)
print(df_prep.head())

# ถ้าใช้ Pipeline ที่มี ColumnTransformer อยู่ข้างใน
full.fit(X_train, y_train)
names_after_prep = full.named_steps["prep"].get_feature_names_out()

ถ้าตั้ง verbose_feature_names_out=True (ค่าเริ่มต้น) ชื่อจะมี prefix เป็นชื่อ transformer เช่น num__age, cat__sex_female ซึ่งกันชนกันได้ระหว่างกลุ่ม ถ้าตั้งเป็น False จะไม่มี prefix แต่คุณต้องรับผิดชอบเองว่าชื่อไม่ซ้ำ วิธีนี้ทำให้การผูกกับ SHAP หรือ feature importance ตรงไปตรงมามาก อยากรู้เพิ่มเติมเรื่อง API ทั้งหมด อ่านคู่มือ Column Transformer อย่างเป็นทางการของ scikit-learn ประกอบด้วย

ColumnTransformer vs Pipeline ต่างกันอย่างไร

คำถามยอดฮิตของผู้เริ่มต้นคือ "ควรใช้ Pipeline หรือ ColumnTransformer?" คำตอบคือ ใช้ทั้งคู่ เพราะทั้งสองไม่ได้แข่งกัน แต่ทำงานคนละหน้าที่ ตารางเปรียบเทียบด้านล่างสรุปความต่างสำคัญ

ประเด็นPipelineColumnTransformer
รูปแบบการทำงานSequential (แต่ละ step ทำต่อจาก step ก่อน)Parallel (apply transformer แต่ละตัวไปยังคอลัมน์คนละกลุ่ม)
Input/Outputผลลัพธ์ของ step ก่อนคือ input ของ step ถัดไปทุก transformer รับ input เดิม แล้วเชื่อมผลลัพธ์แบบ concat
ใช้เมื่อไรเมื่อต้องทำ preprocess ต่อเนื่อง เช่น impute → scale → PCAเมื่อคอลัมน์ต่างชนิดต้อง preprocess ต่างกัน
Step สุดท้ายเป็น estimator ได้ไหมได้ จึงเรียก predict ได้ไม่ได้ เป็น transformer เท่านั้น
Prefix ในชื่อฟีเจอร์ไม่มี ส่งชื่อจาก step สุดท้ายมี prefix ของชื่อ transformer (ปิดได้)
ตัวอย่างการใช้ร่วมกันPipeline([('prep', ColumnTransformer([...])), ('clf', LogisticRegression())])

สรุปสั้นๆ: Pipeline คือ "ทำต่อกันเป็นสายพาน" ส่วน ColumnTransformer คือ "แยกช่องแล้วทำขนาน" การผูกทั้งสองเข้าด้วยกันเป็นแพทเทิร์นมาตรฐานของ ML pipeline สมัยใหม่ ถ้าอยากเข้าใจ Pipeline ให้ลึกขึ้น อ่านคู่มือ scikit-learn Pipeline ฉบับสมบูรณ์ของเราต่อได้เลย

สร้าง custom transformer สำหรับคอลัมน์เฉพาะ

บ่อยครั้งที่ transformer สำเร็จรูปไม่พอ เช่น คุณอยาก log-transform เฉพาะคอลัมน์ราคา หรือแยกวัน/เดือน/ปีออกจากคอลัมน์ datetime สองวิธีหลักคือใช้ FunctionTransformer (ง่าย, ใช้สำหรับฟังก์ชัน stateless) หรือสร้าง class ที่ extend BaseEstimator และ TransformerMixin (ยืดหยุ่น, ใช้สำหรับ transformer ที่ต้องเก็บ state จาก training set)

from sklearn.preprocessing import FunctionTransformer
from sklearn.base import BaseEstimator, TransformerMixin
import numpy as np

# แบบง่าย: log1p สำหรับคอลัมน์ที่ skew (fare)
log_transformer = FunctionTransformer(
    func=np.log1p,
    inverse_func=np.expm1,
    feature_names_out="one-to-one",
    validate=True,
)

# แบบ class: skewed→log ถ้า skewness > threshold
class AutoLogTransformer(BaseEstimator, TransformerMixin):
    def __init__(self, threshold=1.0):
        self.threshold = threshold

    def fit(self, X, y=None):
        import pandas as pd
        df = pd.DataFrame(X)
        self.skewed_ = (df.skew().abs() > self.threshold).values
        return self

    def transform(self, X):
        X = np.asarray(X, dtype=float)
        X[:, self.skewed_] = np.log1p(X[:, self.skewed_])
        return X

    def get_feature_names_out(self, input_features=None):
        return np.asarray(input_features)

preprocessor_custom = ColumnTransformer([
    ("log_fare", log_transformer, ["fare"]),
    ("num_others", StandardScaler(), ["age"]),
    ("cat", cat_pipe, cat_cols),
])

อย่าลืม implement get_feature_names_out ใน custom class ของคุณเพื่อให้ integrate กับ ColumnTransformer ได้อย่างสมบูรณ์ ไม่เช่นนั้น get_feature_names_out() บน parent จะโยน error ตามที่กล่าวใน callout ก่อนหน้า (ผมเจอบั๊กนี้ตอนใช้กับ SHAP แล้วค้นหาสาเหตุอยู่พักใหญ่)

ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข

รวบรวมปัญหาที่ผู้ใช้ ColumnTransformer เจอบ่อยที่สุดในโปรเจกต์จริง พร้อมวิธีแก้ไข

1. Found unknown categories ตอน predict

เกิดเมื่อ test set มีค่าที่ไม่เคยเจอใน training set แก้ด้วยการตั้ง OneHotEncoder(handle_unknown="ignore") ซึ่งจะสร้าง row เป็นศูนย์ทั้งหมดสำหรับค่าใหม่ ทางเลือกอื่นคือ OneHotEncoder(handle_unknown="infrequent_if_exist", min_frequency=1) ที่จะส่งไปยัง infrequent bucket

2. Shape mismatch หลัง transform

เกิดจากลืม sparse_output=False เมื่อผสมกับ transformer ที่คืน dense array ทำให้ scikit-learn ผสมได้แต่ downstream model บางตัวไม่รองรับ sparse ตั้ง sparse_output=False ใน OneHotEncoder ให้ทุกอย่างเป็น dense เหมือนกัน

3. คอลัมน์หายไปโดยไม่ตั้งใจ

ค่าเริ่มต้นของ remainder คือ 'drop' ทำให้คอลัมน์ที่คุณไม่ได้ระบุถูกทิ้งไปเงียบๆ แก้ด้วย remainder='passthrough' เพื่อส่งต่อโดยไม่แก้ไข หรือระบุคอลัมน์ทุกตัวให้ครบเพื่อความชัดเจน แนะนำให้ใช้ preprocessor.get_feature_names_out() เพื่อ verify ทันที

4. Data leakage ตอน cross-validation

ถ้าคุณเรียก preprocessor.fit_transform(X) บน dataset ทั้งหมดก่อน CV คุณจะรั่วสถิติของ test fold ให้ training fold เสมอ วิธีที่ถูกคือใส่ ColumnTransformer ไว้ใน Pipeline เดียวกับ estimator แล้วให้ cross_val_score หรือ GridSearchCV จัดการ fit/transform ในแต่ละ fold เอง

5. Sparse matrix กินหน่วยความจำเยอะเกิน

เมื่อคุณมี high-cardinality categorical (เช่น 50,000 zip codes) การ one-hot จะสร้าง sparse matrix ขนาดใหญ่ ทางเลือกคือใช้ min_frequency/max_categories ใน OneHotEncoder, เปลี่ยนเป็น TargetEncoder (มีตั้งแต่ scikit-learn 1.3) หรือ OrdinalEncoder เมื่อ downstream model รองรับ categorical โดยตรง

คำถามที่พบบ่อย

ColumnTransformer รับ NumPy array หรือแค่ pandas DataFrame?

รับทั้งสอง แต่การใช้ pandas DataFrame มีข้อได้เปรียบสำคัญคือคุณระบุคอลัมน์ด้วยชื่อได้ (เช่น ["age", "fare"]) และ make_column_selector จะทำงานได้เต็มประสิทธิภาพ ถ้าใช้ NumPy array คุณต้องระบุคอลัมน์ด้วย index ([0, 1, 5]) และเสีย metadata ประเภทข้อมูลไป

ต่างจาก FeatureUnion อย่างไร?

FeatureUnion apply transformer ทุกตัวไปยัง ทุกคอลัมน์ แล้ว concat ผลลัพธ์ (เช่น รวม PCA กับ PolynomialFeatures บน dataset เดียวกัน) ส่วน ColumnTransformer apply transformer ไปยัง คอลัมน์ต่างกลุ่มกัน ในทางปฏิบัติ ColumnTransformer ครอบคลุมกรณีของ FeatureUnion ได้เกือบทั้งหมด และมีความยืดหยุ่นสูงกว่า

ทำไมชื่อคอลัมน์ผลลัพธ์มี prefix "num__" หรือ "cat__"?

เพราะ verbose_feature_names_out=True ถูกตั้งเป็นค่าเริ่มต้นตั้งแต่ scikit-learn 1.0 เพื่อกันชื่อคอลัมน์ชนกันระหว่าง transformer ถ้าคุณมั่นใจว่าชื่อคอลัมน์ไม่ซ้ำระหว่างกลุ่ม ตั้ง verbose_feature_names_out=False เพื่อเอา prefix ออก

ColumnTransformer ทำงานร่วมกับ XGBoost หรือ LightGBM ได้ไหม?

ได้ ทั้ง XGBoost และ LightGBM มี scikit-learn compatible API (XGBClassifier, LGBMClassifier) ที่ใส่เป็น step สุดท้ายใน Pipeline ได้ตรงๆ อย่างไรก็ตาม LightGBM รองรับ categorical features แบบ native ผ่านพารามิเตอร์ categorical_feature อยู่แล้ว จึงอาจไม่จำเป็นต้อง one-hot encode ทุกครั้ง

Save และ load ColumnTransformer ที่ fit แล้วอย่างไร?

ใช้ joblib.dump(model, "model.joblib") และ joblib.load() ได้เหมือน estimator ทั่วไป แต่ต้องระวังว่าเวอร์ชัน scikit-learn ตอน save และ load ควรตรงกัน (แนะนำ pin ใน requirements.txt) มิฉะนั้นอาจได้ InconsistentVersionWarning หรือพฤติกรรมเพี้ยน

Editorial Team
เกี่ยวกับผู้เขียน Editorial Team

Our team of expert writers and editors.