Machine Learning Data Preparation

DP4ML - Data Transform - Phần 4 - How to Transform Numerical to Categorical Data

DP4ML - Data Transform - Phần 4 - How to Transform Numerical to Categorical Data

Bài thứ 17 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ứ 4 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 Transforms để chuyển đổi dữ liệu từ dạng numerical sang dạng categorical. Chúng ta cũng sẽ thực hành trên bộ dữ liệu thực tế.

1. Discretization Transforms

Các features dạng numerical thường có phân phối ngẫu nhiên bất kỳ. Ngoài cách đưa chúng về gần với phân phối Gaussian như bài trước thì chúng ta có thể áp dụng phép biến đổi Discretization để chuyển phân phối của chúng sang một dạng khác mà có thể giúp các mô hình học dễ hơn.

Discretization Transforms hay Categorization Transforms là một cách gom các giá trị của feature thành một số hữu hạn các nhóm, hay bin.

Ví dụ: Feature Age có giá trị nằm trong khoảng từ 1-100, ta chia thành 3 bins: 1-30, 31-60, 61-100.

Có 3 kỹ thuật thực hiện Discretization Transforms:

  • Uniform: Chiều rộng của mỗi bin trên trục X là bằng nhau.
  • Quantile: Số lượng phần tử trong mỗi bin là bằng nhau.
  • Clustered: Mỗi bin có một điểm trung tâm.

Trong scikit-learn, Discretization Transforms được implemented bởi lớp KBinsDiscretizer(). 3 tham số:

  • strategy: chỉ ra tên kỹ thuật thực hiện (uniform, quantile, clustered),
  • n_bins: chỉ ra số lượng bin được tạo ra,
  • encode: quy định cách thức chuyển đổi (ordinal, one-hot).

Ví dụ về việc sử dụng KBinsDiscretizer():

# demonstration of the discretization transform
from numpy.random import randn
from sklearn.preprocessing import KBinsDiscretizer
from matplotlib import pyplot
# generate gaussian data sample
data = randn(1000)
# histogram of the raw data
pyplot.hist(data, bins=25)
pyplot.show()
# reshape data to have rows and columns
data = data.reshape((len(data),1))
# discretization transform the raw data
kbins = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')
data_trans = kbins.fit_transform(data)
# summarize first few rows
print(data_trans[:10, :])
# histogram of the transformed data
pyplot.hist(data_trans, bins=10)
pyplot.show()

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

  • Dữ liệu ban đầu:
  • Dữ liệu sau khi thực hiện Discretization:
[[5.]
 [6.]
 [4.]
 [6.]
 [5.]
 [5.]
 [4.]
 [4.]
 [5.]
 [5.]]

2. Thực hành Discretization trên tập dữ liệu Sonar

2.1 Uniform Discretization Transform

a, Áp dụng Uniform Discretization Transform trên tập dữ liệu Sonar
# visualize a uniform ordinal discretization transform of the sonar dataset
from pandas import read_csv
from pandas import DataFrame
from sklearn.preprocessing import KBinsDiscretizer
from matplotlib import pyplot
# load dataset
dataset = read_csv('sonar.csv', header=None)
# retrieve just the numeric input values
data = dataset.values[:, :-1]
# perform a uniform discretization transform of the dataset
trans = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')
data = trans.fit_transform(data)
# convert the array back to a dataframe
dataset = DataFrame(data)
# histograms of the variables
fig = dataset.hist(xlabelsize=4, ylabelsize=4)
[x.title.set_size(4) for x in fig.ravel()]
# show the plot
pyplot.show()

Ta thấy hình dạng histogram của các features sau khi biến đổi gần giống như của dữ liệu ban đầu.

b, Mô hình hóa thuật toán kNN trên dữ liệu đã biến đổi
# evaluate knn on the sonar dataset with uniform ordinal discretization transform
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.pipeline import Pipeline
# load dataset
dataset = read_csv('sonar.csv', header=None)
data = dataset.values
# separate into input and output columns
X, y = data[:, :-1], data[:, -1]
# ensure inputs are floats and output is an integer label
X = X.astype('float32')
y = LabelEncoder().fit_transform(y.astype('str'))
# define the pipeline
trans = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')
model = KNeighborsClassifier()
pipeline = Pipeline(steps=[('t', trans), ('m', model)])
# evaluate the pipeline
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# report pipeline performance
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

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

Accuracy: 0.829 (0.079)

Hãy nhớ lại bài trước, độ chính xác khi mô hình hóa tập Sonar khi chưa áp dụng bất kỳ phép biến đổi nào là 79.7%. Với việc áp dụng Uniform Discretization Transform, độ chính xác đã tăng lên 82.9%.

2.2 Clustered Discretization Transform

a, Áp dụng Clustered Discretization Transform trên tập dữ liệu Sonar
# visualize a k-means ordinal discretization transform of the sonar dataset
from pandas import read_csv
from pandas import DataFrame
from sklearn.preprocessing import KBinsDiscretizer
from matplotlib import pyplot
# load dataset
dataset = read_csv('sonar.csv', header=None)
# retrieve just the numeric input values
data = dataset.values[:, :-1]
# perform a k-means discretization transform of the dataset
trans = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='kmeans')
data = trans.fit_transform(data)
# convert the array back to a dataframe
dataset = DataFrame(data)
# histograms of the variables
fig = dataset.hist(xlabelsize=4, ylabelsize=4)
[x.title.set_size(4) for x in fig.ravel()]
# show the plot
pyplot.show()

Chúng ta có thể thấy rằng các các features được tổ chức thành ba nhóm, một số nhóm trong số đó có vẻ khá đồng đều về mặt quan sát, và một số khác thì ít hơn.

b, Mô hình hóa thuật toán kNN trên dữ liệu đã biến đổi
# evaluate knn on the sonar dataset with k-means ordinal discretization transform
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.pipeline import Pipeline
# load dataset
dataset = read_csv('sonar.csv', header=None)
data = dataset.values
# separate into input and output columns
X, y = data[:, :-1], data[:, -1]
# ensure inputs are floats and output is an integer label
X = X.astype('float32')
y = LabelEncoder().fit_transform(y.astype('str'))
# define the pipeline
trans = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='kmeans')
model = KNeighborsClassifier()
pipeline = Pipeline(steps=[('t', trans), ('m', model)])
# evaluate the pipeline
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# report pipeline performance
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

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

Accuracy: 0.814 (0.084)

Ta thấy độ chính xác giảm đi một chút so với khi áp dụng Uniform Discretization Transform, chỉ còn 81.4%.

2.3 Quantile Discretization Transform

a, Áp dụng Quantile Discretization Transform trên tập dữ liệu Sonar
# visualize a quantile ordinal discretization transform of the sonar dataset
from pandas import read_csv
from pandas import DataFrame
from sklearn.preprocessing import KBinsDiscretizer
from matplotlib import pyplot
# load dataset
dataset = read_csv('sonar.csv', header=None)
# retrieve just the numeric input values
data = dataset.values[:, :-1]
# perform a quantile discretization transform of the dataset
trans = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='quantile')
data = trans.fit_transform(data)
# convert the array back to a dataframe
dataset = DataFrame(data)
# histograms of the variables
fig = dataset.hist(xlabelsize=4, ylabelsize=4)
[x.title.set_size(4) for x in fig.ravel()]
# show the plot
pyplot.show()

Ta thấy tất các features sau khi biến đổi đều có cùng kiểu phân phối và chúng được sắp xếp vào 10 bins khác nhau, số lượng giá trị của mỗi bin là như nhau.

b, Mô hình hóa thuật toán kNN trên dữ liệu đã biến đổi
# evaluate knn on the sonar dataset with quantile ordinal discretization transform
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.pipeline import Pipeline
# load dataset
dataset = read_csv('sonar.csv', header=None)
data = dataset.values
# separate into input and output columns
X, y = data[:, :-1], data[:, -1]
# ensure inputs are floats and output is an integer label
X = X.astype('float32')
y = LabelEncoder().fit_transform(y.astype('str'))
# define the pipeline
trans = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='quantile')
model = KNeighborsClassifier()
pipeline = Pipeline(steps=[('t', trans), ('m', model)])
# evaluate the pipeline
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# report pipeline performance
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

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

Accuracy: 0.840 (0.072)

Độ chính xác trong trường hợp này là cao nhất so với 2 trường hợp kia.

c, Tune số lượng bins

n_bins là tham số có ảnh hưởng lớn đến khả năng học hỏi của model. Ta thử đi tuning chúng xem sao.

# explore number of discrete bins on classification accuracy
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.preprocessing import LabelEncoder
from sklearn.pipeline import Pipeline
from matplotlib import pyplot

# get the dataset
def get_dataset():
	# load dataset
	dataset = read_csv('sonar.csv', header=None)
	data = dataset.values
	# separate into input and output columns
	X, y = data[:, :-1], data[:, -1]
	# ensure inputs are floats and output is an integer label
	X = X.astype('float32')
	y = LabelEncoder().fit_transform(y.astype('str'))
	return X, y

# get a list of models to evaluate
def get_models():
	models = dict()
	for i in range(2,11):
		# define the pipeline
		trans = KBinsDiscretizer(n_bins=i, encode='ordinal', strategy='quantile')
		model = KNeighborsClassifier()
		models[str(i)] = Pipeline(steps=[('t', trans), ('m', model)])
	return models

# evaluate a given model using cross-validation
def evaluate_model(model, X, y):
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# get the dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# evaluate the models and store results
results, names = list(), list()
for name, model in models.items():
	scores = evaluate_model(model, X, y)
	results.append(scores)
	names.append(name)
	print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()

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

>2 0.822 (0.066)
>3 0.869 (0.073)
>4 0.838 (0.078)
>5 0.838 (0.070)
>6 0.836 (0.071)
>7 0.852 (0.072)
>8 0.837 (0.077)
>9 0.841 (0.069)
>10 0.840 (0.072)

Khá ngạc nhiên là khi n_bins=3 ta thu được độ chính xác cao nhất 86.9%. Tuy nhiên khi nhìn vào biểu đồ Box thì phân phối của nó đang hơi lệch về bên phải.

3. Kết luận

Bài thứ 4 về chủ đề Data Transforms, mình đã giới thiệu 3 kỹ thuật thực hiện Data Transforms để chuyển features dạng numerical sang dạng categorical, đó là Uniform Discretization, Clustered Discretization, và Quantile Discretization. Việc chuyển đổi này nhằm mục đích thay đổi phân phối của các features mà trong 1 số trường hợp nó sẽ mang lại hiệu quả cho model. 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 sinh thêm features mới sử dụng kỹ thuật Polynominal/Interaction. Mời các bạn đón đọc.

4. Tham khảo

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