Trong bài viết này tôi muốn giới thiệu đến thuật toán nâng cấp từ thuật toán K-Means đó là K-Prototypes. Trong bài viết trước khi đề cập đến phân nhóm khách hàng, chúng ta cần xem xét đến biến “Gender” đây chính là biến phân loại, trong trường hợp này K-Means chỉ đảm nhiệm vai trò đối với các thuộc tính số, để triển khai bài toán phân nhóm khách hàng có hiệu quả hơn chúng ta cần dùng đến K-Prototypes để làm việc với tập dữ liệu hỗn hợp giữa thuộc tính số và thuộc tính phân loại (categorical). Thuật toán K-Prototypes sử dụng các đối tượng mẫu (prototype) để biểu diễn cho các cụm thay vì sử dụng các đối tượng trung tâm như thuật toán K-Means. Các đối tượng dữ liệu lần lượt được phân phối cho các cụm dữ liệu sao cho chúng tương tự nhất với đối tượng mẫu tương ứng với cụm dữ liệu mà chúng được phân phối.

Ban đầu, chọn k đối tượng mẫu theo ngẫu nhiên hoặc có thể theo kinh nghiệm chuyên môn. Giai đoạn tiếp theo chúng ta phân phối lần lượt từng đối tượng dữ liệu cho các cụm ứng với đối tượng mẫu mà chúng tương tự nhất, sau mỗi lần phân phối đối tượng dữ liệu cho các cụm, chúng ta cập nhật giá trị cho các đối tượng mẫu. Sau khi tất cả các đối tượng đã được phân về cho các cụm dữ liệu, chúng ta lần lượt kiểm tra lại từng đối tượng dữ liệu cho các cụm, nếu đối tượng dữ liệu nào phân phối chưa phù hợp thì ta tiến hành di chuyển đối tượng đó sang cụm thích hợp và tiến hành cập nhật lại các đối tượng mẫu đại diện cho hai cụm này. Quá trình kiểm tra này được lặp cho đến khi chúng ta chuyển đến trạng thái tất cả các đối tượng đã được phân về đúng cụm của mình.

Các đối tượng mẫu có mô hình giống như mô hình của các đối tượng dữ liệu, nghĩa là chúng được biểu diễn bằng vector và được xác định như sau:

Ví dụ như sau: xét một cụm dữ liệu có các đối tượng dữ liệu là thông tin về khách hàng có giá trị thuộc tính lần lượt là: age (year), spending score(1…100), gender (Male or Female):

Lúc này, đối tượng mẫu được xác định như sau: Prototypes = (133/4, 297/4, Male)

Thuật toán K-Prototypes là thuật toán phân cụm phân hoạch sử dụng hàm tiêu chuẩn E và các thức biểu diễn cụm bằng đối tượng mẫu

Các bước thực hiện:

library(clustMixType)
library(tidyverse)
library(broom)
library(dplyr)


df <- read.csv('https://raw.githubusercontent.com/SteffiPeTaffy/machineLearningAZ/master/Machine%20Learning%20A-Z%20Template%20Folder/Part%204%20-%20Clustering/Section%2025%20-%20Hierarchical%20Clustering/Mall_Customers.csv')

head(df)
##   CustomerID  Genre Age Annual.Income..k.. Spending.Score..1.100.
## 1          1   Male  19                 15                     39
## 2          2   Male  21                 15                     81
## 3          3 Female  20                 16                      6
## 4          4 Female  23                 16                     77
## 5          5 Female  31                 17                     40
## 6          6 Female  22                 17                     76

Thực hiện đổi tên các biến giúp các mã code trở nên gọn gàng hơn

df <- rename(df, 
             Id = CustomerID, 
             Age = Age,
             Gender = Genre, 
             Income = Annual.Income..k.., 
             SpendingScore = Spending.Score..1.100.)
head(df)
##   Id Gender Age Income SpendingScore
## 1  1   Male  19     15            39
## 2  2   Male  21     15            81
## 3  3 Female  20     16             6
## 4  4 Female  23     16            77
## 5  5 Female  31     17            40
## 6  6 Female  22     17            76
df$Gender <- as.factor(df$Gender)
str(df)
## 'data.frame':    200 obs. of  5 variables:
##  $ Id           : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ Gender       : Factor w/ 2 levels "Female","Male": 2 2 1 1 1 1 1 1 2 1 ...
##  $ Age          : int  19 21 20 23 31 22 35 23 64 30 ...
##  $ Income       : int  15 15 16 16 17 17 18 18 19 19 ...
##  $ SpendingScore: int  39 81 6 77 40 76 6 94 3 72 ...
#count plot of some categorical variables 
ggplot(df, aes(x = df$Age, 
               y = df$SpendingScore)) + 
  geom_point(color="blue") + 
  geom_smooth()+
  labs(title = "Age ~ SpendingScore", 
       x = "Age", 
       y = "Spending Score") + 
  facet_grid(~Gender) 
## Warning in check_font_path(italic, "italic"): 'italic' should be a length-one
## vector, using the first element
## Warning: Use of `df$Age` is discouraged. Use `Age` instead.
## Warning: Use of `df$SpendingScore` is discouraged. Use `SpendingScore` instead.
## Warning: Use of `df$Age` is discouraged. Use `Age` instead.
## Warning: Use of `df$SpendingScore` is discouraged. Use `SpendingScore` instead.
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

df_kproto <- kproto(df, 
                    k = 3, 
                    iter.max=100, 
                    nstart = 25)
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## Estimated lambda: 2486.72 
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
## 0 observation(s) with NAs.
df_kproto$centers
##          Id Gender      Age   Income SpendingScore
## 1  37.07246 Female 37.97101 33.14493      49.81159
## 2 167.30645 Female 36.50000 89.70968      49.95161
## 3 103.89855   Male 41.84058 61.78261      50.81159
df_kproto$size
## clusters
##  1  2  3 
## 69 62 69
fit <- factor(df_kproto$cluster, 
                 order = TRUE, 
                 levels = c(1:6))

fit_df <- data.frame(df, fit)

result <- data.frame(df_kproto$size, df_kproto$centers)

result
##   clusters Freq        Id Gender      Age   Income SpendingScore
## 1        1   69  37.07246 Female 37.97101 33.14493      49.81159
## 2        2   62 167.30645 Female 36.50000 89.70968      49.95161
## 3        3   69 103.89855   Male 41.84058 61.78261      50.81159
ggplot(fit_df, 
       aes(SpendingScore, 
           Income, color = fit)) + 
  geom_point() + 
  labs(title = "Income ~ SpendingScore",
       x = "SpendingScore", 
       y = "Income") + 
  facet_grid(~Gender) +
  guides(color = guide_legend(title = "Cluster"))
## Warning in check_font_path(italic, "italic"): 'italic' should be a length-one
## vector, using the first element

library(plotly)
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
fig <- plot_ly(fit_df,
               x= ~Income, 
               y= ~Age, 
               z= ~SpendingScore, 
               color = ~fit, 
               colors = c('#BF382A', '#0C4B8E', "#BBBBBB", "#00FF00")) %>%
  add_markers() %>% 
  layout(scene = list(
    xaxis = list(title="Annual Income"), 
      yaxis = list(title="Age"), 
      zaxis = list(title="Spending Score")))
fig
summary(df_kproto)
## Id 
##   Min. 1st Qu. Median      Mean 3rd Qu. Max.
## 1    1   18.00   35.0  37.07246   52.00   85
## 2  122  154.25  169.5 167.30645  184.75  200
## 3   54   87.00  104.0 103.89855  121.00  152
## 
## -----------------------------------------------------------------
## Gender 
##        
## cluster Female  Male
##       1  0.725 0.275
##       2  0.661 0.339
##       3  0.304 0.696
## 
## -----------------------------------------------------------------
## Age 
##   Min. 1st Qu. Median     Mean 3rd Qu. Max.
## 1   18   24.00   35.0 37.97101   49.00   68
## 2   19   30.25   34.5 36.50000   40.75   59
## 3   18   26.00   40.0 41.84058   54.00   70
## 
## -----------------------------------------------------------------
## Income 
##   Min. 1st Qu. Median     Mean 3rd Qu. Max.
## 1   15      21     33 33.14493   42.00   54
## 2   67      78     87 89.70968   98.75  137
## 3   43      57     62 61.78261   67.00   78
## 
## -----------------------------------------------------------------
## SpendingScore 
##   Min. 1st Qu. Median     Mean 3rd Qu. Max.
## 1    3    35.0     50 49.81159   73.00   99
## 2    1    18.5     49 49.95161   78.75   97
## 3    5    43.0     50 50.81159   56.00   97
## 
## -----------------------------------------------------------------
val <- validation_kproto(method = "silhouette", data = fit_df, k = 3:4, nstart = 5)
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
##           fit 
##             0 
## 0 observation(s) with NAs.
## 
## Estimated lambda: 2115.317 
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
##           fit 
##             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
##           fit 
##             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
##           fit 
##             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
##           fit 
##             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
##           fit 
##             0 
## 0 observation(s) with NAs.
## 
## Estimated lambda: 2115.317 
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
##           fit 
##             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
##           fit 
##             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
##           fit 
##             0 
## 0 observation(s) with NAs.
## 
## # NAs in variables:
##            Id        Gender           Age        Income SpendingScore 
##             0             0             0             0             0 
##           fit 
##             0 
## 0 observation(s) with NAs.
val
## $k_opt
## [1] 3
## 
## $index_opt
##         3 
## 0.5745268 
## 
## $indices
##         3         4 
## 0.5745268 0.5559994 
## 
## $kp_obj
## Numeric predictors: 4 
## Categorical predictors: 2 
## Lambda: 2115.317 
## 
## Number of Clusters: 3 
## Cluster sizes: 69 69 62 
## Within cluster error: 146208.7 139785.5 157706 
## 
## Cluster prototypes:
##          Id Gender      Age   Income SpendingScore fit
## 1  37.07246 Female 37.97101 33.14493      49.81159   1
## 2 103.89855   Male 41.84058 61.78261      50.81159   3
## 3 167.30645 Female 36.50000 89.70968      49.95161   2