Nama Aggota Kelompok 14:

1. Christine Aprilia Putri (24031554046)

2. Fridania Nisa Calita (24031554208)

Seleksi Fitur

Dipilih 10 fitur numerik utama (kolom 2 sampai 11) yang bersifat kontinu, yaitu dari Rented Bike Count hingga Snowfall. Pemilihan ini dilakukan karena metode clustering berbasis jarak seperti K-Means dan K-Medians bekerja lebih baik pada data dengan nilai yang bertahap, bukan data diskrit.

Fitur-fitur tersebut mewakili kondisi lingkungan seperti suhu, kelembapan, dan radiasi matahari, serta kondisi cuaca seperti hujan dan salju, yang dapat memengaruhi keputusan seseorang untuk menyewa sepeda.

Sementara itu, data kategorikal dan biner seperti Seasons, Holiday, dan Functioning Day tidak digunakan agar tidak memengaruhi perhitungan jarak. Sehingga, hasil pengelompokan lebih fokus pada pola aktivitas dan kondisi lingkungan yang dapat diukur.

df_selected <- df[, c("Rented Bike Count", "Hour", "Temperature(°C)", "Humidity(%)", 
                      "Wind speed (m/s)", "Visibility (10m)", "Dew point temperature(°C)", 
                      "Solar Radiation (MJ/m2)", "Rainfall(mm)", "Snowfall (cm)")]

Ambil Data Sampel

Diambil 2000 data di awal agar mengurangi beban komputasi

set.seed(123)
df_sample_raw <- df_selected[sample(1:nrow(df_selected), 2000), ]

Cek Data

str(df_sample_raw)
## tibble [2,000 × 10] (S3: tbl_df/tbl/data.frame)
##  $ Rented Bike Count        : num [1:2000] 705 289 126 378 236 ...
##  $ Hour                     : num [1:2000] 14 14 5 9 17 10 8 1 20 18 ...
##  $ Temperature(°C)          : num [1:2000] 18.3 12.1 1.8 10.4 2.4 18.2 21.1 18.9 10.7 22.2 ...
##  $ Humidity(%)              : num [1:2000] 43 97 34 81 17 36 70 55 70 96 ...
##  $ Wind speed (m/s)         : num [1:2000] 2.2 2 0.9 1.4 3.1 1 0.3 2.3 2.8 1.2 ...
##  $ Visibility (10m)         : num [1:2000] 1509 177 1990 2000 1990 ...
##  $ Dew point temperature(°C): num [1:2000] 5.4 11.6 -12.4 7.2 -20.2 2.8 15.4 9.6 5.4 21.5 ...
##  $ Solar Radiation (MJ/m2)  : num [1:2000] 2.43 0.2 0 0.36 0.78 1.99 0.9 0 0 0.09 ...
##  $ Rainfall(mm)             : num [1:2000] 0 0 0 0 0 0 0 0 0 3.5 ...
##  $ Snowfall (cm)            : num [1:2000] 0 0 0 0 0 0 0 0 0 0 ...

Statistik deskriptif

summary(df_sample_raw)
##  Rented Bike Count      Hour       Temperature(°C)   Humidity(%)   
##  Min.   :   0.0    Min.   : 0.00   Min.   :-17.50   Min.   : 0.00  
##  1st Qu.: 188.8    1st Qu.: 5.00   1st Qu.:  3.50   1st Qu.:43.00  
##  Median : 480.0    Median :11.00   Median : 13.90   Median :57.00  
##  Mean   : 691.4    Mean   :11.47   Mean   : 12.94   Mean   :58.34  
##  3rd Qu.:1052.0    3rd Qu.:17.00   3rd Qu.: 22.60   3rd Qu.:74.00  
##  Max.   :3556.0    Max.   :23.00   Max.   : 39.30   Max.   :98.00  
##  Wind speed (m/s) Visibility (10m) Dew point temperature(°C)
##  Min.   :0.000    Min.   :  27.0   Min.   :-30.600          
##  1st Qu.:1.000    1st Qu.: 977.8   1st Qu.: -4.325          
##  Median :1.500    Median :1705.0   Median :  5.400          
##  Mean   :1.727    Mean   :1446.5   Mean   :  4.193          
##  3rd Qu.:2.300    3rd Qu.:1999.2   3rd Qu.: 15.000          
##  Max.   :7.400    Max.   :2000.0   Max.   : 26.800          
##  Solar Radiation (MJ/m2)  Rainfall(mm)     Snowfall (cm)   
##  Min.   :0.0000          Min.   : 0.0000   Min.   :0.0000  
##  1st Qu.:0.0000          1st Qu.: 0.0000   1st Qu.:0.0000  
##  Median :0.0100          Median : 0.0000   Median :0.0000  
##  Mean   :0.5601          Mean   : 0.1212   Mean   :0.0676  
##  3rd Qu.:0.9200          3rd Qu.: 0.0000   3rd Qu.:0.0000  
##  Max.   :3.5200          Max.   :29.5000   Max.   :8.8000

Visualisasi korelasi

korelasi <- cor(df_sample_raw)
corrplot(korelasi, method = "color", type = "upper", 
         tl.col = "black", addCoef.col = "black", tl.cex = 0.7, number.cex =0.5)

- Hubungan Terkuat dengan Jumlah Penyewaan: Variabel Temperature (°C) memiliki korelasi positif paling kuat terhadap Rented Bike Count sebesar 0.55. Hal ini menunjukkan bahwa peningkatan suhu udara secara signifikan mendorong masyarakat Seoul untuk menggunakan layanan sepeda publik. Selain suhu, variabel Hour (0.42) dan Dew point temperature (0.39) juga menunjukkan pengaruh positif yang cukup berarti.

Cek missing value

sum(is.na(df_sample_raw))
## [1] 0

Prepare data (Scale to ensure distance metrics aren’t biased by units)

df_scaled <- as.data.frame(scale(df_sample_raw))

number of K

Elbow Method

set.seed(123)
wss <- sapply(1:10, function(k) {
  kmeans(df_scaled, centers = k, nstart = 20)$tot.withinss
})

par(mfrow = c(1, 1))
plot(1:10, wss, type = "b", pch = 19, frame = FALSE,
     xlab = "Number of clusters K",
     ylab = "Total within-clusters sum of squares",
     main = "Elbow Method (Sample 2000)")

##### Silhouette Analysis(dengan sample)

set.seed(123)
avg_sil_values <- sapply(2:10, function(k) {
  km_res <- kmeans(df_scaled, centers = k, nstart = 25)
  ss <- silhouette(km_res$cluster, dist(df_scaled))
  mean(ss[, 3])
})
## Warning: did not converge in 10 iterations
plot(2:10, avg_sil_values, type = "b", pch = 19, frame = FALSE,
     xlab = "Number of clusters K",
     ylab = "Average Silhouette Width",
     main = "Silhouette Analysis (Sample 2000)")

Terdapat perbedaan dalam penentuan jumlah klaster optimal antara Elbow Method (k=3) dan Silhouette Analysis (k=7). Hal ini wajar terjadi pada data yang memiliki banyak variabel dan sebaran yang cukup padat. Elbow Method menunjukkan penurunan nilai yang paling jelas sampai k=3, sedangkan Silhouette memberikan nilai terbaik pada k=7. Namun, untuk menjaga keseimbangan antara hasil yang baik dan kemudahan dalam memahami hasilnya, dipilih k=3 sebagai jumlah klaster akhir.

Pemilihan ini dilakukan karena tiga kelompok utama yaiturendah, sedang, dan tinggi sehinggalebih mudah dipahami dan lebih berguna untuk kebutuhan operasional. Jika menggunakan tujuh klaster, hasilnya akan terlalu detail dan sulit dibedakan secara jelas dalam praktik.

Metode

set.seed(123)
k_fix <- 3
1. Kmeans
km_res   <- kmeans(df_scaled, centers = k_fix, nstart = 25)

2. K-Median

kmed_res <- flexclust::kcca(df_scaled, k = k_fix, family = kccaFamily("kmedians"))
## Found more than one class "kcca" in cache; using the first, from namespace 'flexclust'
## Also defined by 'kernlab'
## Found more than one class "kcca" in cache; using the first, from namespace 'flexclust'
## Also defined by 'kernlab'

3. DBSCAN

db_res <- dbscan(df_scaled, eps = 1.1, MinPts = 9)

4. Mean Shift(Gunakan bandwidth agar stabil)

bw_vec   <- rep(1.2, ncol(df_scaled))
ms_res   <- meanShift(as.matrix(df_scaled), bandwidth = bw_vec)

5. Fuzzy C-means

fcm_res  <- cmeans(df_scaled, centers = k_fix, m = 2)

Visualization Comparison

par(mfrow = c(2, 3), mar = c(4, 4, 2, 1))
plot(df_scaled[,3], df_scaled[,1], col = km_res$cluster, main = "K-means", pch=19, cex=0.5)
plot(df_scaled[,3], df_scaled[,1], col = clusters(kmed_res), main = "K-medians", pch=19, cex=0.5)
plot(df_scaled[,3], df_scaled[,1], col = db_res$cluster + 1L, main = "DBSCAN", pch=19, cex=0.5)
plot(df_scaled[,3], df_scaled[,1], col = ms_res$assignment, main = "Mean Shift", pch=19, cex=0.5)
plot(df_scaled[,3], df_scaled[,1], col = fcm_res$cluster, main = "Fuzzy C-means", pch=19, cex=0.5)
plot(df_scaled[,3], df_scaled[,1], col = as.numeric(cut(df_scaled[,1], 3)), main = "Pseudo-Original", pch=19, cex=0.5)

  1. K-Means dan K-Medians Menghasilkan pembagian data yang jelas menjadi tiga kelompok (rendah, sedang, tinggi). K-Medians lebih tahan terhadap data pencilan karena menggunakan median.

  2. DBSCAN dan Mean Shift Lebih fokus pada kepadatan data, tidak membagi secara merata. DBSCAN cenderung membentuk satu klaster utama dan menganggap data lain sebagai noise, sedangkan Mean Shift menghasilkan klaster yang menyebar tanpa batas jelas.

  3. Fuzzy C-Means Menunjukkan klaster yang saling tumpang tindih karena satu data bisa masuk ke lebih dari satu kelompok, sehingga batas klaster lebih fleksibel.

  4. Pseudo-Original Data awal bersifat kontinu tanpa batas yang jelas, sehingga beberapa metode menghasilkan klaster yang tidak tegas.

Berdasarkan hasil pengujian:

DBSCAN dan Mean Shift kurang optimal karena menghasilkan klaster yang kurang jelas atau terlalu menyatu, sehingga kurang efektif untuk kebutuhan operasional.

Metrics

Karena tidak tersedia label asli (ground truth), maka evaluasi tidak dapat menggunakan Adjusted Rand Index (ARI). Oleh karena itu, penilaian dilakukan menggunakan metrik internal, yaitu Silhouette dan Dunn Index.

# Hitung Jarak (Distance Matrix)
d_mat <- dist(df_scaled)

1. Silhouette Score (K-Means)

# Mengukur seberapa baik sebuah objek cocok dengan klasternya (Range -1 ke 1)
sil_val <- mean(silhouette(km_res$cluster, d_mat)[,3])
print(paste("Average Silhouette Score:", round(sil_val, 4)))
## [1] "Average Silhouette Score: 0.2313"

Nilai ini berada di sekitar 0,2 yang menunjukkan bahwa struktur klaster berada pada tingkat sedang. Pada data nyata seperti penyewaan sepeda, nilai yang tidak mendekati 1 merupakan hal yang wajar karena masih terdapat beberapa data antar klaster yang saling berdekatan atau sedikit tumpang tindih. Meskipun demikian, nilai sebesar 0,23 sudah menunjukkan bahwa hasil pengelompokan memiliki pola yang jelas dan tidak terbentuk secara acak.

2. Dunn Index & Within-cluster SS

Menggunakan stats yang sudah dihitung dari cluster.stats

stats <- fpc::cluster.stats(d_mat, km_res$cluster)
print(paste("Dunn Index:", round(stats$dunn, 6)))
## [1] "Dunn Index: 0.011662"
print(paste("Within-cluster SS:", round(km_res$tot.withinss, 2)))
## [1] "Within-cluster SS: 13392.79"

Dunn Index: 0.011662 Nilai ini menunjukkan perbandingan antara jarak antar klaster dan kepadatan dalam klaster. Meskipun nilainya kecil (sekitar 0,01), hal ini wajar pada dataset dengan banyak fitur dan jumlah data yang besar. Yang penting, nilainya positif, yang berarti tetap terdapat pemisahan antar klaster.

Within-cluster SS: 13392.79 Nilai ini menunjukkan total jarak kuadrat antara data dengan pusat klasternya masing-masing. Semakin kecil nilainya, semakin padat klaster yang terbentuk. Nilai 13.392 untuk 2.000 data menunjukkan bahwa klaster yang dihasilkan sudah cukup baik dan cukup rapat.

3. ARI Score (Adjusted Rand Index)

Karena tidak tersedia ground truth (label asli), evaluasi dilakukan dengan membandingkan hasil K-Means dan K-Medians untuk melihat tingkat konsistensi antar algoritma.

ari_score <- mclust::adjustedRandIndex(km_res$cluster, clusters(kmed_res))
print(paste("Adjusted Rand Index (KM vs KMed):", round(ari_score, 4)))
## [1] "Adjusted Rand Index (KM vs KMed): 0.8232"

Nilai ini tergolong sangat tinggi (sekitar 82%), yang menunjukkan bahwa hasil pengelompokan dari kedua metode sangat mirip. Meskipun K-Means menggunakan rata-rata dan K-Medians menggunakan nilai tengah, keduanya menghasilkan kelompok yang hampir sama. Hal ini menunjukkan bahwa hasil clustering cukup stabil dan dapat dipercaya.

Eksplorasi

1. Profiling Karakteristik Klaster

Pada tahap ini dilakukan perhitungan rata-rata setiap variabel pada masing-masing klaster untuk melihat perbedaan pola penyewaan berdasarkan kondisi lingkungan.

df_cek <- as.data.frame(df_scaled)
df_cek$cluster <- as.factor(km_res$cluster)
profil_klaster <- df_cek %>%
  group_by(cluster) %>%
  summarise(across(everything(), mean))

print(profil_klaster)
## # A tibble: 3 × 11
##   cluster `Rented Bike Count`    Hour `Temperature(°C)` `Humidity(%)`
##   <fct>                 <dbl>   <dbl>             <dbl>         <dbl>
## 1 1                    -0.580  0.0838           -1.16          -0.852
## 2 2                    -0.510 -0.605             0.0154         0.881
## 3 3                     0.982  0.604             0.825         -0.349
## # ℹ 6 more variables: `Wind speed (m/s)` <dbl>, `Visibility (10m)` <dbl>,
## #   `Dew point temperature(°C)` <dbl>, `Solar Radiation (MJ/m2)` <dbl>,
## #   `Rainfall(mm)` <dbl>, `Snowfall (cm)` <dbl>
  • Klaster 1 (Kondisi Cuaca Dingin dan Kering (Penyewaan Rendah)): Klaster ini mencerminkan kondisi lingkungan dengan suhu udara yang sangat rendah (ekstrem dingin). Meskipun tingkat kelembapan udara berada di bawah rata-rata (kondisi kering/cerah), suhu yang terlalu rendah menjadi faktor penghambat utama yang menurunkan minat masyarakat untuk bersepeda. Kondisi ini umumnya merepresentasikan periode musim dingin atau waktu dini hari di mana mobilitas sangat terbatas.

  • Klaster 2 (Kondisi Lembap dan Pasif (Penyewaan Rendah)): Klaster ini didominasi oleh tingkat kelembapan udara yang tinggi, yang secara signifikan berhubungan dengan kondisi cuaca kurang nyaman seperti mendung, berkabut, atau pasca hujan. Terjadi umumnya di luar jam sibuk, kelompok ini menunjukkan penurunan aktivitas bersepeda karena faktor kenyamanan lingkungan yang rendah, meskipun suhu udara berada pada level normal.

  • Klaster 3 (Kondisi Ideal dan Jam Sibuk (Penyewaan Tinggi)): Klaster ini merupakan kelompok dengan tingkat penggunaan layanan paling maksimal. Karakteristik utamanya adalah suhu udara yang hangat, cuaca cerah (radiasi matahari tinggi), dan terjadi pada jam-jam sibuk (peak hours). Kombinasi antara kenyamanan termal dan kebutuhan mobilitas yang tinggi mendorong peningkatan jumlah penyewaan sepeda secara signifikan di atas rata-rata.

2. Analisis Pusat Massa/Centroid

Analisis pusat massa atau centroid dilakukan untuk mengetahui titik tengah yang mewakili setiap klaster dalam skala standar (scaled). Nilai centroid menunjukkan perbedaan karakteristik tiap klaster dibandingkan dengan rata-rata keseluruhan data (nilai 0). Nilai positif berarti berada di atas rata-rata, sedangkan nilai negatif berarti berada dibawah rata-rata

centroids <- km_res$centers
print(centroids)
##   Rented Bike Count        Hour Temperature(°C) Humidity(%) Wind speed (m/s)
## 1        -0.5804902  0.08376289     -1.16030782  -0.8519040        0.3938794
## 2        -0.5103838 -0.60488776      0.01537817   0.8808072       -0.4905899
## 3         0.9822748  0.60388213      0.82547176  -0.3494200        0.2531425
##   Visibility (10m) Dew point temperature(°C) Solar Radiation (MJ/m2)
## 1        0.5324904                -1.3012897              -0.1957037
## 2       -0.6726482                 0.3460486              -0.5245874
## 3        0.3525709                 0.5644592               0.7185320
##   Rainfall(mm) Snowfall (cm)
## 1   -0.1163938    0.07753084
## 2    0.1781552    0.09169443
## 3   -0.1112689   -0.15704678
  • Klaster 1: Memiliki nilai suhu udara paling rendah (-1.16) dan titik embun terendah (-1.30). Hal ini menunjukkan bahwa pusat kelompok ini berada pada kondisi suhu yang sangat dingin, sehingga jumlah penyewaan juga berada di bawah rata-rata (- 0.58).

  • Klaster 2: Ditandai dengan nilai kelembapan paling tinggi (0.88) dan radiasi matahari paling rendah (-0.52). Hal ini menunjukkan bahwa klaster ini berada pada kondisi cuaca yang kurang mendukung seperti mendung atau hujan, sehingga jumlah penyewaan berada di bawah rata-rata (-0.51).

  • Klaster 3: Memiliki nilai tertinggi pada jumlah penyewaan (0.98), suhu udara (0.82), dan jam sibuk (0.60). Hal ini menunjukkan bahwa klaster ini berada pada kondisi yang paling mendukung, yaitu cuaca hangat dan waktu sibuk, sehingga jumlah penyewaan berada di atas rata-rata.

3. Evaluasi Distribusi dan Ukuran Klaster

Analisis ini bertujuan untuk melihat sebaran 2.000 data ke dalam tiga klaster untuk memahami pola penggunaan sepeda di Seoul

jumlah_anggota <- table(km_res$cluster)
persentase_anggota <- prop.table(jumlah_anggota) * 100
distribusi_klaster <- rbind(Jumlah = jumlah_anggota, Persentase = round(persentase_anggota, 2))
print(distribusi_klaster)
##                1     2     3
## Jumlah     514.0 778.0 708.0
## Persentase  25.7  38.9  35.4
  • Dominasi Klaster 2 (Kondisi Lembap): Klaster 2 merupakan kelompok terbesar dengan 778 data (38,9%). Hal ini menunjukkan bahwa sebagian besar waktu penyewaan terjadi pada kondisi lembap atau di luar jam sibuk, dengan tingkat penggunaan yang cenderung rendah hingga sedang.

  • Potensi Klaster 3 (Kondisi Ideal): Klaster 3 memiliki 708 data (35,4%) dan menunjukkan tingkat penyewaan tertinggi. Hal ini menandakan adanya aktivitas penggunaan yang tinggi pada kondisi cuaca hangat dan jam sibuk.

  • Klaster 1 (Cuaca Dingin): Klaster ini merupakan yang paling kecil dengan 514 data (25,7%), yang menggambarkan kondisi cuaca dingin atau waktu dini hari dengan tingkat penggunaan rendah.

Dapat disimpulkan secara umum, pembagian data cukup merata antar klaster. Hal ini menunjukkan bahwa K-Means mampu mengelompokkan data dengan baik berdasarkan kondisi lingkungan, bukan hanya memisahkan data ekstrem.

4. Deteksi Outlier/Anomali (DBSCAN)

noise_idx <- which(db_res$cluster == 0)
length(noise_idx)
## [1] 416
length(noise_idx) / nrow(df_scaled)
## [1] 0.208

Berdasarkan hasil DBSCAN diperoleh jumlah data noise 416 dan proporsi noise 0,208, artinya sekitar 20,8% (416 data) tidak termasuk kedalam cluster manapun karena berada pada pola dengan kepadatan rendah, sehingga di kategorikan sebagai noise/anomali.

df_sample_raw$db_cluster <- db_res$cluster
aggregate(. ~ db_cluster, data = df_sample_raw, mean)
##   db_cluster Rented Bike Count     Hour Temperature(°C) Humidity(%)
## 1          0          705.8197 12.75000        12.50072    61.33413
## 2          1          686.8794 11.12000        13.02083    57.61206
## 3          2          825.1111 12.55556        18.97778    48.22222
##   Wind speed (m/s) Visibility (10m) Dew point temperature(°C)
## 1         2.347837        1178.5505                  4.323317
## 2         1.560825        1522.0216                  4.139175
## 3         2.022222         607.7778                  7.555556
##   Solar Radiation (MJ/m2) Rainfall(mm) Snowfall (cm)
## 1               0.7461058  0.546153846   0.314182692
## 2               0.5015492  0.009650794   0.002857143
## 3               2.1977778  0.000000000   0.000000000
pca <- prcomp(df_scaled)

plot(pca$x[,1:2],
     col = ifelse(db_res$cluster == 0, "red", "black"),
     pch = 16,
     main = "Noise Detection(DBSCAN)")

Titik merah : noise Titik Hitam : cluster utama

Grafik menujukkan bahwa noise tersebar di area pinggir dan luar kepadatan utama, dan beberapa titik berada jauh dari pusat distribusi. Noise ini merepresentasikan kondisi penyewaan sepeda yang yang terjadi pada kondisi tidak normal. Kondisi tersebut berkaitan dengan cuaca ekstrem, visibilitas rendah, waktu tidak umum.

membership <- fcm_res$membership
head(membership)
##              1         2         3
## [1,] 0.1993205 0.5301231 0.2705565
## [2,] 0.5307653 0.2417271 0.2275076
## [3,] 0.2477291 0.1735400 0.5787308
## [4,] 0.5239964 0.2184852 0.2575184
## [5,] 0.1848194 0.2440939 0.5710867
## [6,] 0.3121784 0.3914054 0.2964162

Tabel ini menunjukkan hubungan setiap data dengan klaster. Jika sebuah data memiliki nilai yang hampir sama atau sama besar di dua/lebih klaster, maka data tersebut sangat ambigu.

max_membership <- apply(membership, 1, max)

summary(max_membership)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.3356  0.4573  0.5240  0.5233  0.5803  0.8125

max_membership untuk mengetahui seberapa yakin model mengelompokkan data. Jika rata-rata (mean) mendekati 1.0, berarti sebagian besar data terklasifikasi dengan sangat jelas.

ambiguous_idx <- which(max_membership < 0.6)
length(ambiguous_idx)
## [1] 1623
length(ambiguous_idx) / nrow(df_scaled)
## [1] 0.8115

Jumlah data ambigu diperoleh sebanyak 1.623 data atau sekitar 81,15% dari total data termasuk dalam kategori ambigu (memiliki nilai maximum membership < 0,6). Proporsi ini menunjukkan bahwa mayoritas data berada pada kondisi yang tidak dapat diklasifikasikan secara tegas ke dalam satu klaster.

ambiguous_data <- df_sample_raw[ambiguous_idx, ]
head(ambiguous_data)
## # A tibble: 6 × 11
##   `Rented Bike Count`  Hour `Temperature(°C)` `Humidity(%)` `Wind speed (m/s)`
##                 <dbl> <dbl>             <dbl>         <dbl>              <dbl>
## 1                 705    14              18.3            43                2.2
## 2                 289    14              12.1            97                2  
## 3                 126     5               1.8            34                0.9
## 4                 378     9              10.4            81                1.4
## 5                 236    17               2.4            17                3.1
## 6                 708    10              18.2            36                1  
## # ℹ 6 more variables: `Visibility (10m)` <dbl>,
## #   `Dew point temperature(°C)` <dbl>, `Solar Radiation (MJ/m2)` <dbl>,
## #   `Rainfall(mm)` <dbl>, `Snowfall (cm)` <dbl>, db_cluster <dbl>
pca <- prcomp(df_scaled)

plot(pca$x[,1:2],
     col = ifelse(max_membership < 0.6, "orange", "blue"),
     pch = 16,
     main = "Ambiguity in Fuzzy C-Means")

Titik bitu : data ambigu Ttitik Oranye : data jelas

Visualisasi menunjukkan bahwa data dengan tingkat ambiguitas tinggi cenderung berada di area tengah distribusi, yaitu pada wilayah perpotongan antar klaster. Hal ini berbeda dengan hasil DBSCAN, di mana data anomali (noise) berada di area pinggir distribusi.

Ambiguitas ini mencerminkan kondisi transisi dalam pola penyewaan sepeda. Kondisi tersebut umumnya terjadi pada: 1. Peralihan waktu, seperti dari jam sibuk ke jam sepi atau sebaliknya 2. Kondisi cuaca moderat, seperti suhu sedang dan kelembapan yang tidak ekstrem 3. Situasi lingkungan yang tidak sepenuhnya mendukung maupun menghambat aktivitas bersepeda

Temuan ini menunjukkan bahwa pola penyewaan sepeda di Seoul tidak sepenuhnya terbagi secara diskrit ke dalam kelompok rendah, sedang, dan tinggi, melainkan bersifat kontinu. Dengan demikian, metode Fuzzy C-Means memberikan representasi yang lebih fleksibel dalam menangkap dinamika data, khususnya dalam kondisi transisi yang tidak dapat dijelaskan secara tegas oleh metode clustering konvensional.

fuzzy_cluster <- apply(membership, 1, which.max)
table(fuzzy_cluster)
## fuzzy_cluster
##   1   2   3 
## 731 691 578

Hasil penentuan cluster dominan pada metode Fuzzy C-Means menunjukkan bahwa sebanyak 731 data termasuk dalam cluster 1, 691 data pada cluster 2, dan 578 data pada cluster 3. Distribusi ini relatif seimbang, yang menunjukkan bahwa pola penyewaan sepeda tersebar cukup merata pada ketiga kelompok. Namun, jika dikaitkan dengan nilai membership sebelumnya, sebagian besar data memiliki tingkat ambiguitas yang tinggi, sehingga meskipun dapat diklasifikasikan ke dalam cluster dominan, batas antar klaster tidak bersifat tegas.