Machine Learning Data Preparation

DP4ML - Data Transform - Phần 6 - How to Transform Numerical and Categorical Data

DP4ML - Data Transform - Phần 6 - How to Transform Numerical and Categorical Data

Bài thứ 19 trong chuỗi các bài viết về chủ đề Data Preparation cho các mô hình ML và là bài thứ 6 về về Data Transforms. Trong bài này, chúng ta sẽ tìm hiểu cách thức để thực hiện Data Transforms đôi với những bộ dữ liệu có cả 2 loại features là numerical và categorical. Chúng ta cũng sẽ thực hành trên bộ dữ liệu thực tế.

1. “Best Practice” khi cần thực hiện nhiều kỹ thuật DP4ML

Khi chuẩn bị dữ liệu cho các mô hình ML, chúng ta thường phải thực hiện qua nhiều công đoạn: Thay thế Missing Data, Scaling Numerical Values, … Cách làm tốt nhất là gom chúng lại với nhau trong 1 Pipeline để tiện cho việc xử lý.

...
# define pipeline
pipeline = Pipeline(steps=[('i', SimpleImputer(strategy='median' )), ('s', MinMaxScaler())])
# transform training data
train_X = scaler.fit_transform(train_X)

2. Khó khăn khi thực hiện Data Transforms cho các features khác loại

Các bài viết từ trước đến giờ chỉ đề cập đến bộ dữ liệu chỉ có 1 loại features là numerical hoặc categorical. Nhưng trong thực tế, dữ liệu thường sẽ có cả 2 loại này. Cách làm truyền thống là tách riêng các features theo từng loại để xử lý theo các kỹ thuật của chúng. Sau đó mới gộp lại thành 1 dữ liệu chung. Cách làm này nghe thì đơn giản nhưng lại khá mất thời gian và hiệu quả không cao.

Rất may là scikit-learn cung cấp cho chúng ta class ColumnTransformer() để dễ dàng thực hiện nhiệm vụ này.

3. Sử dụng ColumnTransformer

ColumnTransformer() cho phép chúng ta áp dụng một hoặc nhiều kỹ thuật DP4ML tới mội hoặc nhiều features riêng biệt. Như vậy, ta có thể thực hiện các phép biến đổi A, B, C lên các features dạng numerical, thực hiện các phép biến đổi D, E, F lên các features dạng categorical.

Để sử dụng ColumnTransformer(), bạn phải chỉ ra 3 thông tin:

  • Tên của phép biến đổi
  • Kỹ thuật biến đổi
  • Số thứ tự features cần áp dụng phép biến đổi

VD:

transformer = ColumnTransformer(transformers=[( ' cat ' , OneHotEncoder(), [0, 1])])

Một VD khác, áp dụng SimpleImputer với median tới các numerical features tại cột số 0, 1. Áp dụng SimpleImputer với most_frequent tới categorical features tại cột số 2, 3.

...
t = [('num', SimpleImputer(strategy='median'), [0, 1]), ('cat', SimpleImputer(strategy='most_frequent'), [2, 3])]
transformer = ColumnTransformer(transformers=t)

Mặc định, các features mà không được đề cập đến trong ColumnTransformer thì sẽ bị xóa bỏ khỏi dataset. Để thay đổi điều này, set giá trị cho tham sô remainder=‘passthrough’.

Một khi ColumnTransformer() đã được khai báo, ta có thể áp dụng nó vào bộ dữ liệu của mình:

data = transformer.fit_transform(data)

ColumnTransformer() cũng có thể được sử dụng trong một Pipeline. Đây là một Best Practice để đảm bảo rằng các kỹ thuật DP4ML được thực hiện đầy đủ khi huấn luyện model cũng như khi sử dụng model để dự đoán.

...
# define model
model = LogisticRegression()
# define transform
transformer = ColumnTransformer(transformers=[('cat', OneHotEncoder(), [0, 1])])
# define pipeline
pipeline = Pipeline(steps=[('t', transformer), ('m', model)])
# fit the model on the transformed data
model.fit(train_X, train_y)
# make predictions

4. Thực hành ColumnTransformer()

4.1 Abalone Regression dataset

Abalone Regression dataset là tập dữ liệu chứa thông tin về con bào ngư. Nó bao gồm 4177 mẫu, mỗi mẫu có 8 features và 1 target. Nhiệm vụ của các mô hình ML đối với tập dữ liệu này là dự đoán số tuổi của bào ngư. Download và tìm hiểu thông tin về Abalone Regression dataset tại đây và tại đây

Base model đang đạt được kết quả MAE=2.363(std=0.092) khi đánh giá trên 10-fold cross-validation.

VD một vài mẫu của bộ dữ liệu này:

M,0.455,0.365,0.095,0.514,0.2245,0.101,0.15,15
M,0.35,0.265,0.09,0.2255,0.0995,0.0485,0.07,7
F,0.53,0.42,0.135,0.677,0.2565,0.1415,0.21,9
M,0.44,0.365,0.125,0.516,0.2155,0.114,0.155,10
I,0.33,0.255,0.08,0.205,0.0895,0.0395,0.055,7
...

4.2 Thực hiện Data Transforms và mô hình hóa dữ liệu

Ta thấy rằng, feature đầu tiên có dạng categorical, trong khi các features còn lại ở dạng numerical. Do đó, mình dự dịnh sẽ thực hiện One-Hot Encoding đối với feature đầu tiên đó, các features còn lại sẽ được thực hiện normalization. Cuối cùng, model SVR sẽ được sử dụng để mô hình hóa dữ liệu.

# example of using the ColumnTransformer for the Abalone dataset
from numpy import mean
from numpy import std
from numpy import absolute
from pandas import read_csv
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import MinMaxScaler
from sklearn.svm import SVR
# load dataset
dataframe = read_csv('abalone.csv', header=None)
# split into inputs and outputs
last_ix = len(dataframe.columns) - 1
X, y = dataframe.drop(last_ix, axis=1), dataframe[last_ix]
print(X.shape, y.shape)
# determine categorical and numerical features
numerical_ix = X.select_dtypes(include=['int64', 'float64']).columns
categorical_ix = X.select_dtypes(include=['object', 'bool']).columns
# define the data preparation for the columns
t = [('cat', OneHotEncoder(), categorical_ix), ('num', MinMaxScaler(), numerical_ix)]
col_transform = ColumnTransformer(transformers=t)
# define the model
model = SVR(kernel='rbf',gamma='scale',C=100)
# define the data preparation and modeling pipeline
pipeline = Pipeline(steps=[('prep',col_transform), ('m', model)])
# define the model cross-validation configuration
cv = KFold(n_splits=10, shuffle=True, random_state=1)
# evaluate the pipeline using cross validation and calculate MAE
scores = cross_val_score(pipeline, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1)
# convert MAE scores to positive values
scores = absolute(scores)
# summarize the model performance
print('MAE: %.3f (%.3f)' % (mean(scores), std(scores)))

Kết quả thực hiện:

(4177, 8) (4177,)
MAE: 1.465 (0.047)

Code này có thể coi như template cho các dự án tương tự của bạn.

5. Kết luận

Bài thứ 6 về chủ đề Data Transforms, mình đã giới thiệu về kỹ thuật class ColumnTransformer() của thư viện scikit-learn giúp chúng ta thực hiện được các kỹ thuật Data Transforms cho từng feature riêng biệt. Toàn bộ code của bài này, các bạn có thể tham khảo tại đây.

Bài tiếp theo chúng ta sẽ tìm hiểu cách thức thực hiện Data Transforms target thay vì features như các bài trước đó. Mời các bạn đón đọc.

6. Tham khảo

[1] Jason Brownlee, “Data Preparation for Machine Learning”, Book: https://machinelearningmastery.com/data-preparation-for-machine-learning/.