1 Introduction

Breast cancer is a disease in which cells in the breast grow out of control. There are different kinds of breast cancer. The kind of breast cancer depends on which cells in the breast turn into cancer. Breast cancer is a formidable health challenge affecting millions of women globally. Characterized by abnormal cell growth in breast tissue, early detection is paramount for effective treatment and improved outcomes. Breast cancer can spread outside the breast through blood vessels and lymph vessels. When breast cancer spreads to other parts of the body, it is said to have metastasized.

In this LBB we will make an unsupervised learning model to find the patterns in our data to generate information.

2 Data Preparation

2.1 Import Library

library(dplyr)
library(FactoMineR)
## Warning: package 'FactoMineR' was built under R version 4.3.3
library(factoextra)
## Warning: package 'factoextra' was built under R version 4.3.3
## Warning: package 'ggplot2' was built under R version 4.3.3
options(scipen = 999)

2.2 Import Data

cancer <- read.csv("data_input/data.csv")
glimpse(cancer)
## Rows: 569
## Columns: 33
## $ id                      <int> 842302, 842517, 84300903, 84348301, 84358402, …
## $ diagnosis               <chr> "M", "M", "M", "M", "M", "M", "M", "M", "M", "…
## $ radius_mean             <dbl> 17.990, 20.570, 19.690, 11.420, 20.290, 12.450…
## $ texture_mean            <dbl> 10.38, 17.77, 21.25, 20.38, 14.34, 15.70, 19.9…
## $ perimeter_mean          <dbl> 122.80, 132.90, 130.00, 77.58, 135.10, 82.57, …
## $ area_mean               <dbl> 1001.0, 1326.0, 1203.0, 386.1, 1297.0, 477.1, …
## $ smoothness_mean         <dbl> 0.11840, 0.08474, 0.10960, 0.14250, 0.10030, 0…
## $ compactness_mean        <dbl> 0.27760, 0.07864, 0.15990, 0.28390, 0.13280, 0…
## $ concavity_mean          <dbl> 0.30010, 0.08690, 0.19740, 0.24140, 0.19800, 0…
## $ concave.points_mean     <dbl> 0.14710, 0.07017, 0.12790, 0.10520, 0.10430, 0…
## $ symmetry_mean           <dbl> 0.2419, 0.1812, 0.2069, 0.2597, 0.1809, 0.2087…
## $ fractal_dimension_mean  <dbl> 0.07871, 0.05667, 0.05999, 0.09744, 0.05883, 0…
## $ radius_se               <dbl> 1.0950, 0.5435, 0.7456, 0.4956, 0.7572, 0.3345…
## $ texture_se              <dbl> 0.9053, 0.7339, 0.7869, 1.1560, 0.7813, 0.8902…
## $ perimeter_se            <dbl> 8.589, 3.398, 4.585, 3.445, 5.438, 2.217, 3.18…
## $ area_se                 <dbl> 153.40, 74.08, 94.03, 27.23, 94.44, 27.19, 53.…
## $ smoothness_se           <dbl> 0.006399, 0.005225, 0.006150, 0.009110, 0.0114…
## $ compactness_se          <dbl> 0.049040, 0.013080, 0.040060, 0.074580, 0.0246…
## $ concavity_se            <dbl> 0.05373, 0.01860, 0.03832, 0.05661, 0.05688, 0…
## $ concave.points_se       <dbl> 0.015870, 0.013400, 0.020580, 0.018670, 0.0188…
## $ symmetry_se             <dbl> 0.03003, 0.01389, 0.02250, 0.05963, 0.01756, 0…
## $ fractal_dimension_se    <dbl> 0.006193, 0.003532, 0.004571, 0.009208, 0.0051…
## $ radius_worst            <dbl> 25.38, 24.99, 23.57, 14.91, 22.54, 15.47, 22.8…
## $ texture_worst           <dbl> 17.33, 23.41, 25.53, 26.50, 16.67, 23.75, 27.6…
## $ perimeter_worst         <dbl> 184.60, 158.80, 152.50, 98.87, 152.20, 103.40,…
## $ area_worst              <dbl> 2019.0, 1956.0, 1709.0, 567.7, 1575.0, 741.6, …
## $ smoothness_worst        <dbl> 0.1622, 0.1238, 0.1444, 0.2098, 0.1374, 0.1791…
## $ compactness_worst       <dbl> 0.6656, 0.1866, 0.4245, 0.8663, 0.2050, 0.5249…
## $ concavity_worst         <dbl> 0.71190, 0.24160, 0.45040, 0.68690, 0.40000, 0…
## $ concave.points_worst    <dbl> 0.26540, 0.18600, 0.24300, 0.25750, 0.16250, 0…
## $ symmetry_worst          <dbl> 0.4601, 0.2750, 0.3613, 0.6638, 0.2364, 0.3985…
## $ fractal_dimension_worst <dbl> 0.11890, 0.08902, 0.08758, 0.17300, 0.07678, 0…
## $ X                       <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…

2.3 Data Cleansing

In this case we will use only the mean data. Therefore we will remove SE and Worst data. Also we want to change diagnosis type into factor.

cancer_clean <- cancer %>%
                select(-c(1, 13:33)) %>%
                mutate(diagnosis = as.factor(diagnosis))
glimpse(cancer_clean)
## Rows: 569
## Columns: 11
## $ diagnosis              <fct> M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M,…
## $ radius_mean            <dbl> 17.990, 20.570, 19.690, 11.420, 20.290, 12.450,…
## $ texture_mean           <dbl> 10.38, 17.77, 21.25, 20.38, 14.34, 15.70, 19.98…
## $ perimeter_mean         <dbl> 122.80, 132.90, 130.00, 77.58, 135.10, 82.57, 1…
## $ area_mean              <dbl> 1001.0, 1326.0, 1203.0, 386.1, 1297.0, 477.1, 1…
## $ smoothness_mean        <dbl> 0.11840, 0.08474, 0.10960, 0.14250, 0.10030, 0.…
## $ compactness_mean       <dbl> 0.27760, 0.07864, 0.15990, 0.28390, 0.13280, 0.…
## $ concavity_mean         <dbl> 0.30010, 0.08690, 0.19740, 0.24140, 0.19800, 0.…
## $ concave.points_mean    <dbl> 0.14710, 0.07017, 0.12790, 0.10520, 0.10430, 0.…
## $ symmetry_mean          <dbl> 0.2419, 0.1812, 0.2069, 0.2597, 0.1809, 0.2087,…
## $ fractal_dimension_mean <dbl> 0.07871, 0.05667, 0.05999, 0.09744, 0.05883, 0.…

Data is cleaned. From glimpse function above we can see there are 569 rows with 11 columns.

All the columns are:

  • diagnosis : The diagnosis of breast tissue samples, where ‘M’ indicates malignant (cancerous) and ‘B’ indicates benign (non-cancerous)
  • radius_mean : Radius of the nucleus of the cells
  • texture_mean : Texture of the cells
  • perimeter_mean : perimeter of the cells
  • area_mean : area of the cells
  • smoothness_mean : Smoothness (local variation in radius lengths) of the cells
  • compactness_mean : Compactness
  • concavity_mean : Severity of concave portions of the contour
  • concave.points_mean : Number of concave portions of the contour
  • symmetry_mean : Symmetry of the cells
  • fractal_dimension_mean : Fractal dimension

Next we will check is there any missing value in the data before we start modeling.

colSums(is.na(cancer_clean))
##              diagnosis            radius_mean           texture_mean 
##                      0                      0                      0 
##         perimeter_mean              area_mean        smoothness_mean 
##                      0                      0                      0 
##       compactness_mean         concavity_mean    concave.points_mean 
##                      0                      0                      0 
##          symmetry_mean fractal_dimension_mean 
##                      0                      0

There is no missing value in the data.

3 Modeling

3.1 PCA using FactoMineR

Before creating the Unsupervised Learning model, we need create an index to identify which column is categorical and which one is numeric

qualivar <- c(1)
quantivar <- c(2:11)

Next we will create the model.

cancer_pca <- PCA(X = cancer_clean,
                  scale.unit = T,
                  quali.sup = qualivar,
                  graph = F,
                  ncp = 10)

scale.unit = T means that our data is automatically scaled. Scaling is used before PCA because we want the data to be at the same scale.
quali.sup = qualivar means we give our model information which column index are categorical so that our model will ignore and only use numerical variables only.
ncp = 10 means that we will use all 10 of our numeric variables as our PC.

3.2 Dimentionality Reduction

We will check our eigen value of our model that we just created.

cancer_pca$eig
##           eigenvalue percentage of variance cumulative percentage of variance
## comp 1  5.4785879917           54.785879917                          54.78588
## comp 2  2.5187135854           25.187135854                          79.97302
## comp 3  0.8806151792            8.806151792                          88.77917
## comp 4  0.4990094357            4.990094357                          93.76926
## comp 5  0.3725391897            3.725391897                          97.49465
## comp 6  0.1241417485            1.241417485                          98.73607
## comp 7  0.0800853104            0.800853104                          99.53692
## comp 8  0.0348897928            0.348897928                          99.88582
## comp 9  0.0111354606            0.111354606                          99.99718
## comp 10 0.0002823059            0.002823059                         100.00000

We want to use as few PC as possible while retaining as much data as we can. In this case, we want to retain at least 90% of our data, which in our model, we will choose PC1 - PC4 from 10 PC. By doing so, we could reduce our dimension by 60% while also retaining 93.77% of our data.

pca_keep <- as.data.frame(cancer_pca$ind$coord[, 1:4])

pca_keep_1 <- cbind(pca_keep,
                    Type = cancer_clean$diagnosis)
pca_keep_1

3.3 Plotting

3.3.1 Individual Factor Map

plot.PCA(x= cancer_pca,
         choix = "ind",
         habillage = "area_mean",
         select = "contrib 10",
         invinsible = "quali")

Based on our Individual Factor Map above, there are some data which are an outlier. The top 10 of the data are data number 505, 4, 79, 109, 123, 83, 353, 181, 462, 213.

3.3.2 Variable Factor Map

plot.PCA(x = cancer_pca,
         choix = "var")

fviz_contrib(X = cancer_pca,
             choice = "var",
             axes = 1)

fviz_contrib(X = cancer_pca,
             choice = "var",
             axes = 2)

Insights that we get from our plots are:

  1. Variables that contribute to PC 1 are concave.points, concavity, perimeter, compacness, area, and radius
  2. Variables that contribute to PC2 are fractal_dimension, smoothness, and symmetry
  3. Variable that doesn’t contribute to either PC1 or PC2 is texture

3.4 Clustering

Clustering is a method of grouping the data based on their characteristics. First we will check our data’s summary

summary(cancer_clean)
##  diagnosis  radius_mean      texture_mean   perimeter_mean     area_mean     
##  B:357     Min.   : 6.981   Min.   : 9.71   Min.   : 43.79   Min.   : 143.5  
##  M:212     1st Qu.:11.700   1st Qu.:16.17   1st Qu.: 75.17   1st Qu.: 420.3  
##            Median :13.370   Median :18.84   Median : 86.24   Median : 551.1  
##            Mean   :14.127   Mean   :19.29   Mean   : 91.97   Mean   : 654.9  
##            3rd Qu.:15.780   3rd Qu.:21.80   3rd Qu.:104.10   3rd Qu.: 782.7  
##            Max.   :28.110   Max.   :39.28   Max.   :188.50   Max.   :2501.0  
##  smoothness_mean   compactness_mean  concavity_mean    concave.points_mean
##  Min.   :0.05263   Min.   :0.01938   Min.   :0.00000   Min.   :0.00000    
##  1st Qu.:0.08637   1st Qu.:0.06492   1st Qu.:0.02956   1st Qu.:0.02031    
##  Median :0.09587   Median :0.09263   Median :0.06154   Median :0.03350    
##  Mean   :0.09636   Mean   :0.10434   Mean   :0.08880   Mean   :0.04892    
##  3rd Qu.:0.10530   3rd Qu.:0.13040   3rd Qu.:0.13070   3rd Qu.:0.07400    
##  Max.   :0.16340   Max.   :0.34540   Max.   :0.42680   Max.   :0.20120    
##  symmetry_mean    fractal_dimension_mean
##  Min.   :0.1060   Min.   :0.04996       
##  1st Qu.:0.1619   1st Qu.:0.05770       
##  Median :0.1792   Median :0.06154       
##  Mean   :0.1812   Mean   :0.06280       
##  3rd Qu.:0.1957   3rd Qu.:0.06612       
##  Max.   :0.3040   Max.   :0.09744

Based on the summary above, the data scale is pretty wide. In order to do clustering, we need a equally balanced data. So we will scale our data and remove factor column because we cannot determine our optimum k if there’s still a factor column.

cancer_scale <- scale(cancer_clean[, -1])

Then we will check our k optimum

fviz_nbclust(
  x = cancer_scale,
  FUNcluster = kmeans,
  method = "wss"
)

From plot above, our k optimum is 2.

Next we will create our cluster model with our k optimum.

cancer_cluster <- kmeans(cancer_scale,
                         centers = 2)
cancer_cluster
## K-means clustering with 2 clusters of sizes 396, 173
## 
## Cluster means:
##   radius_mean texture_mean perimeter_mean  area_mean smoothness_mean
## 1  -0.4926965   -0.2197678     -0.5050319 -0.4868855      -0.2641564
## 2   1.1277909    0.5030524      1.1560268  1.1144893       0.6046586
##   compactness_mean concavity_mean concave.points_mean symmetry_mean
## 1       -0.4524743     -0.5124564           -0.549105    -0.2600021
## 2        1.0357214      1.1730216            1.256911     0.5951494
##   fractal_dimension_mean
## 1             -0.0527427
## 2              0.1207289
## 
## Clustering vector:
##   [1] 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 1 2 2 1 1 1 2 2 2 2 2 2 2 2 2 1 2 2 2 2 1
##  [38] 1 1 1 1 1 2 1 1 2 1 1 1 1 1 1 1 2 1 1 2 2 1 1 1 1 2 1 1 2 1 1 1 1 2 1 2 1
##  [75] 1 1 1 2 2 1 1 1 2 2 1 2 1 2 1 2 1 1 1 1 2 2 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1
## [112] 1 2 1 1 1 1 2 2 2 1 2 2 1 1 1 1 2 2 2 1 2 2 1 2 1 1 1 2 1 1 1 1 1 1 1 2 1
## [149] 1 1 1 1 2 1 1 1 2 1 1 1 1 2 2 1 2 1 1 1 2 1 1 1 2 1 1 1 1 2 1 1 2 2 1 1 1
## [186] 1 2 1 1 1 2 1 1 1 2 1 2 2 2 1 1 2 2 2 1 1 1 1 1 1 2 1 2 2 2 1 1 1 2 2 1 1
## [223] 1 2 1 1 1 1 1 2 2 1 1 2 1 1 2 2 1 2 1 1 1 1 2 1 1 1 1 1 2 1 2 2 2 1 2 2 2
## [260] 2 2 1 2 1 2 2 1 1 1 1 1 1 2 1 1 1 1 2 1 1 2 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1
## [297] 1 1 1 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 2 1 2 1 1 1 1 2 2 2 1 1
## [334] 1 1 2 1 2 1 2 1 1 1 2 1 1 1 1 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 2 2
## [371] 2 1 2 2 1 2 1 1 1 2 1 1 1 1 1 1 1 1 1 2 1 1 2 2 1 1 1 1 1 1 2 1 1 1 1 1 1
## [408] 1 2 1 1 1 1 1 1 1 1 2 1 1 1 2 1 1 1 1 1 1 1 1 2 1 2 2 1 1 1 1 1 1 1 2 1 1
## [445] 2 1 2 1 1 2 1 2 1 1 1 1 1 1 1 1 2 2 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 2 1
## [482] 1 1 1 1 1 1 2 1 1 1 1 2 1 1 1 1 1 2 2 1 2 1 2 1 1 1 1 1 2 1 1 2 1 1 1 2 2
## [519] 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [556] 1 1 1 1 1 1 1 2 2 2 2 1 2 1
## 
## Within cluster sum of squares by cluster:
## [1] 1918.436 1557.576
##  (between_SS / total_SS =  38.8 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"

Next we will evaluate our new cluster model

cancer_cluster$withinss
## [1] 1918.436 1557.576
cancer_cluster$betweenss/cancer_cluster$totss
## [1] 0.388026

Based on the result above, our cluster model isn’t that good in classifying our data because our within sum of square (wss) is pretty high with 1918.436 for our first cluster and 1557.576 for our second cluster. Our between sum of square (bss) and total sum of square (tss) is also pretty low with 0.388 point. This could happen because we only create 2 cluster. Therefor it’s the best to use classification method in our case