Industri sepak bola modern semakin bergantung pada analisis data untuk mengevaluasi performa pemain secara objektif. Setiap pemain sepak bola memiliki profil atribut yang kompleks, mencakup kemampuan teknis, fisik, dan mental yang dinilai melalui puluhan indikator. Dalam konteks analisis statistik, keberadaan banyak variabel secara simultan menimbulkan tantangan tersendiri, terutama karena atribut-atribut tersebut cenderung saling berkorelasi satu sama lain.
Sebagai contoh, pemain dengan kemampuan short passing yang tinggi pada umumnya juga memiliki nilai ball control dan vision yang tinggi. Demikian pula, atribut dribbling sering kali berkorelasi erat dengan agility dan acceleration. Kondisi ini menunjukkan bahwa terdapat redundansi informasi di antara variabel-variabel tersebut, sehingga analisis langsung menggunakan seluruh variabel secara serentak dapat menghasilkan model yang tidak efisien dan sulit diinterpretasikan.
Untuk mengatasi permasalahan tersebut, diperlukan metode reduksi dimensi yang mampu meringkas informasi dari banyak variabel yang berkorelasi menjadi sejumlah kecil komponen yang tidak saling berkorelasi namun tetap merepresentasikan sebagian besar variasi data. Metode yang umum digunakan untuk tujuan ini adalah Principal Component Analysis (PCA). PCA merupakan teknik statistik multivariat yang mentransformasi variabel-variabel asli menjadi komponen-komponen utama (principal components) yang ortogonal satu sama lain, sehingga redundansi informasi dapat dieliminasi secara efektif (Johnson & Wichern, 2007).
Laporan ini merupakan tahap awal dari analisis multivariat menggunakan dataset FC 26, yang mencakup pembersihan data dan eksplorasi data (Exploratory Data Analysis/EDA) sebagai dasar penerapan PCA pada tahap analisis berikutnya.
Dataset yang digunakan dalam analisis ini adalah FC 26 Player Dataset, yang bersumber dari platform Kaggle. Dataset ini memuat data atribut pemain dari video game simulasi sepak bola FC 26 (FIFA 26), yang secara luas digunakan sebagai proksi penilaian kemampuan pemain sepak bola nyata.
library(tidyverse)
library(psych)
library(corrplot)
library(knitr)
# Membaca dataset
# Catatan: letakkan file CSV dalam folder yang sama dengan file Rmd ini.
data_path <- "FC26_20250921.csv"
if (!file.exists(data_path)) {
stop("File FC26_20250921.csv tidak ditemukan. Pastikan file CSV berada dalam folder kerja yang sama dengan file Rmd.")
}
df_raw <- read.csv(data_path, stringsAsFactors = FALSE)
# Menampilkan dimensi dataset
cat("Jumlah observasi (baris):", nrow(df_raw), "\n")
## Jumlah observasi (baris): 18405
cat("Jumlah variabel (kolom) :", ncol(df_raw), "\n")
## Jumlah variabel (kolom) : 110
Dataset ini memuat informasi mengenai pemain dari berbagai liga di seluruh dunia, mencakup:
Tujuan dari analisis ini adalah sebagai berikut:
# Memeriksa struktur data
glimpse(df_raw)
## Rows: 18,405
## Columns: 110
## $ player_id <int> 252371, 239053, 212622, 235212, 224232,…
## $ player_url <chr> "/player/252371/jude-bellingham/260004/…
## $ fifa_version <int> 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,…
## $ fifa_update <int> 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, …
## $ fifa_update_date <chr> "2025-09-19", "2025-09-19", "2025-09-19…
## $ short_name <chr> "J. Bellingham", "F. Valverde", "J. Kim…
## $ long_name <chr> "Jude Victor William Bellingham", "Fede…
## $ player_positions <chr> "CAM, CM", "CM, CDM, RB", "CDM, RB, CM"…
## $ overall <int> 90, 89, 89, 89, 87, 86, 85, 87, 90, 85,…
## $ potential <int> 94, 90, 89, 90, 87, 86, 85, 88, 90, 85,…
## $ value_eur <int> 174500000, 120500000, 86000000, 1110000…
## $ wage_eur <int> 320000, 340000, 140000, 170000, 69000, …
## $ age <int> 22, 26, 30, 26, 28, 31, 27, 26, 29, 34,…
## $ dob <chr> "2003-06-29", "1998-07-22", "1995-02-08…
## $ height_cm <int> 186, 182, 177, 181, 175, 178, 175, 176,…
## $ weight_kg <int> 75, 74, 75, 73, 68, 69, 76, 72, 82, 67,…
## $ league_id <int> 53, 53, 19, 16, 31, 31, 31, 13, 13, 53,…
## $ league_name <chr> "La Liga", "La Liga", "Bundesliga", "Li…
## $ league_level <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ club_team_id <int> 243, 243, 21, 73, 44, 44, 44, 9, 10, 24…
## $ club_name <chr> "Real Madrid", "Real Madrid", "FC Bayer…
## $ club_position <chr> "CAM", "RDM", "RDM", "RB", "RCM", "CDM"…
## $ club_jersey_number <int> 5, 8, 6, 2, 23, 20, 32, 10, 16, 7, 19, …
## $ club_loaned_from <chr> "", "", "", "", "", "", "", "", "", "",…
## $ club_joined_date <chr> "2023-07-01", "2016-07-22", "2015-07-01…
## $ club_contract_valid_until_year <int> 2029, 2029, 2029, 2029, 2029, 2027, 202…
## $ nationality_id <int> 14, 60, 21, 129, 27, 48, 27, 52, 45, 18…
## $ nationality_name <chr> "England", "Uruguay", "Germany", "Moroc…
## $ nation_team_id <int> 1318, NA, 1337, 111111, 1343, NA, 1343,…
## $ nation_position <chr> "CAM", "", "RCM", "RB", "RCM", "", "LB"…
## $ nation_jersey_number <int> 10, NA, 6, 2, 18, NA, 3, 20, 16, NA, 22…
## $ preferred_foot <chr> "Right", "Right", "Right", "Right", "Ri…
## $ weak_foot <int> 4, 4, 4, 4, 4, 5, 4, 3, 4, 3, 3, 4, 4, …
## $ skill_moves <int> 4, 3, 3, 4, 3, 4, 3, 3, 3, 4, 4, 4, 4, …
## $ international_reputation <int> 5, 4, 4, 4, 4, 4, 3, 4, 5, 4, 3, 4, 4, …
## $ work_rate <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ body_type <chr> "Normal (170-185)", "Unique", "Normal (…
## $ real_face <chr> "Yes", "Yes", "Yes", "Yes", "Yes", "Yes…
## $ release_clause_eur <int> 370800000, 256100000, 141900000, 213700…
## $ player_tags <chr> "#Dribbler, #Playmaker , #Clinical fini…
## $ player_traits <chr> "Relentless +, Low Driven Shot, Gamecha…
## $ pace <int> 80, 88, 72, 92, 80, 71, 80, 66, 65, 77,…
## $ shooting <int> 86, 84, 74, 79, 78, 81, 78, 82, 80, 86,…
## $ passing <int> 83, 84, 89, 82, 84, 87, 84, 85, 86, 85,…
## $ dribbling <int> 90, 84, 84, 83, 86, 82, 82, 85, 84, 88,…
## $ defending <int> 78, 83, 83, 82, 81, 81, 79, 78, 86, 59,…
## $ physic <int> 85, 85, 79, 79, 76, 73, 77, 76, 85, 73,…
## $ attacking_crossing <int> 66, 78, 92, 85, 79, 78, 87, 79, 76, 82,…
## $ attacking_finishing <int> 88, 80, 68, 80, 77, 75, 74, 79, 74, 86,…
## $ attacking_heading_accuracy <int> 75, 63, 72, 71, 60, 65, 69, 65, 81, 79,…
## $ attacking_short_passing <int> 90, 88, 89, 86, 89, 90, 84, 88, 93, 86,…
## $ attacking_volleys <int> 77, 78, 69, 74, 80, 78, 82, 77, 71, 86,…
## $ skill_dribbling <int> 91, 84, 82, 82, 84, 78, 79, 84, 84, 86,…
## $ skill_curve <int> 73, 76, 85, 78, 79, 88, 88, 83, 86, 89,…
## $ skill_fk_accuracy <int> 68, 69, 79, 80, 67, 85, 83, 82, 64, 85,…
## $ skill_long_passing <int> 89, 88, 92, 73, 87, 89, 83, 87, 91, 83,…
## $ skill_ball_control <int> 91, 88, 86, 85, 87, 87, 86, 86, 90, 90,…
## $ movement_acceleration <int> 81, 84, 75, 89, 82, 74, 83, 68, 65, 80,…
## $ movement_sprint_speed <int> 80, 92, 70, 95, 78, 68, 78, 64, 65, 75,…
## $ movement_agility <int> 83, 77, 83, 81, 91, 83, 84, 82, 66, 88,…
## $ movement_reactions <int> 91, 89, 89, 90, 91, 87, 83, 89, 93, 87,…
## $ movement_balance <int> 83, 68, 84, 78, 88, 77, 81, 86, 67, 85,…
## $ power_shot_power <int> 86, 91, 78, 82, 80, 87, 81, 88, 92, 85,…
## $ power_jumping <int> 85, 82, 77, 84, 75, 73, 81, 72, 83, 84,…
## $ power_stamina <int> 94, 93, 92, 95, 89, 81, 84, 87, 91, 77,…
## $ power_strength <int> 80, 82, 69, 72, 66, 65, 72, 69, 83, 70,…
## $ power_long_shots <int> 87, 91, 83, 77, 79, 87, 84, 85, 89, 86,…
## $ mentality_aggression <int> 85, 81, 89, 77, 87, 83, 81, 83, 85, 74,…
## $ mentality_interceptions <int> 82, 86, 85, 85, 85, 82, 80, 80, 84, 59,…
## $ mentality_positioning <int> 91, 86, 78, 84, 84, 73, 83, 78, 76, 87,…
## $ mentality_vision <int> 90, 86, 86, 78, 85, 89, 80, 86, 84, 86,…
## $ mentality_penalties <int> 74, 59, 71, 68, 73, 92, 71, 86, 62, 79,…
## $ mentality_composure <int> 90, 84, 86, 84, 88, 85, 78, 86, 93, 88,…
## $ defending_marking_awareness <int> 77, 82, 82, 82, 80, 81, 81, 78, 88, 45,…
## $ defending_standing_tackle <int> 79, 87, 86, 85, 85, 85, 81, 83, 87, 63,…
## $ defending_sliding_tackle <int> 77, 86, 85, 79, 80, 80, 79, 74, 82, 64,…
## $ goalkeeping_diving <int> 14, 6, 8, 10, 11, 9, 9, 7, 10, 14, 12, …
## $ goalkeeping_handling <int> 11, 10, 15, 8, 5, 14, 8, 10, 10, 8, 10,…
## $ goalkeeping_kicking <int> 10, 6, 7, 14, 13, 11, 12, 14, 7, 14, 7,…
## $ goalkeeping_positioning <int> 5, 15, 15, 6, 14, 6, 7, 15, 14, 13, 7, …
## $ goalkeeping_reflexes <int> 8, 8, 15, 8, 11, 10, 7, 10, 8, 14, 7, 1…
## $ goalkeeping_speed <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ ls <chr> "86+3", "84+3", "77+3", "82+3", "80+3",…
## $ st <chr> "86+3", "84+3", "77+3", "82+3", "80+3",…
## $ rs <chr> "86+3", "84+3", "77+3", "82+3", "80+3",…
## $ lw <chr> "87+0", "85+0", "82+0", "84+0", "84+0",…
## $ lf <chr> "89+0", "86+0", "81+0", "84+0", "84+0",…
## $ cf <chr> "89+0", "86+0", "81+0", "84+0", "84+0",…
## $ rf <chr> "89+0", "86+0", "81+0", "84+0", "84+0",…
## $ rw <chr> "87+0", "85+0", "82+0", "84+0", "84+0",…
## $ lam <chr> "89+3", "86+3", "83+3", "83+3", "85+2",…
## $ cam <chr> "89+3", "86+3", "83+3", "83+3", "85+2",…
## $ ram <chr> "89+3", "86+3", "83+3", "83+3", "85+2",…
## $ lm <chr> "87+3", "86+3", "84+3", "85+3", "84+3",…
## $ lcm <chr> "89+3", "88+2", "87+2", "83+3", "86+1",…
## $ cm <chr> "89+3", "88+2", "87+2", "83+3", "86+1",…
## $ rcm <chr> "89+3", "88+2", "87+2", "83+3", "86+1",…
## $ rm <chr> "87+3", "86+3", "84+3", "85+3", "84+3",…
## $ lwb <chr> "83+3", "86+3", "86+3", "86+3", "84+3",…
## $ ldm <chr> "85+3", "87+3", "87+2", "83+3", "85+2",…
## $ cdm <chr> "85+3", "87+3", "87+2", "83+3", "85+2",…
## $ rdm <chr> "85+3", "87+3", "87+2", "83+3", "85+2",…
## $ rwb <chr> "83+3", "86+3", "86+3", "86+3", "84+3",…
## $ lb <chr> "82+3", "86+3", "85+3", "86+3", "83+3",…
## $ lcb <chr> "81+3", "83+3", "82+3", "81+3", "80+3",…
## $ cb <chr> "81+3", "83+3", "82+3", "81+3", "80+3",…
## $ rcb <chr> "81+3", "83+3", "82+3", "81+3", "80+3",…
## $ rb <chr> "82+3", "86+3", "85+3", "86+3", "83+3",…
## $ gk <chr> "18+3", "18+3", "21+3", "17+3", "19+3",…
## $ player_face_url <chr> "https://cdn.sofifa.net/players/252/371…
cat("Dimensi data sebelum pembersihan:", nrow(df_raw), "baris x", ncol(df_raw), "kolom\n")
## Dimensi data sebelum pembersihan: 18405 baris x 110 kolom
Pada dataset FC 26, pemain dengan posisi Goalkeeper (GK) memiliki profil atribut yang secara fundamental berbeda dari pemain lapangan. Atribut utama kiper—seperti goalkeeping_diving, goalkeeping_handling, goalkeeping_reflexes, dan goalkeeping_positioning—tidak relevan bagi pemain lapangan. Sebaliknya, atribut teknis seperti dribbling, passing, dan shooting pada kiper memiliki nilai yang sangat rendah dan tidak representatif. Keberadaan data kiper dapat mengakibatkan distorsi pada struktur korelasi antar variabel skill serta memengaruhi validitas komponen utama yang dihasilkan oleh PCA. Oleh karena itu, seluruh pemain dengan posisi GK dihapus dari dataset agar analisis lebih homogen dan representatif untuk pemain lapangan.
# Menghapus pemain kiper (GK)
df_field <- df_raw %>%
filter(!grepl("GK", player_positions))
cat("Jumlah pemain setelah penghapusan GK:", nrow(df_field), "\n")
## Jumlah pemain setelah penghapusan GK: 16343
Untuk keperluan analisis multivariat, dipilih variabel-variabel atribut skill teknis dan fisik pemain lapangan yang relevan. Variabel identitas, administratif, dan atribut kiper dikeluarkan dari analisis.
# Memilih variabel skill yang relevan untuk analisis multivariat
variabel_skill <- c(
"pace", "shooting", "passing", "dribbling", "defending", "physic",
"attacking_crossing", "attacking_finishing", "attacking_heading_accuracy",
"attacking_short_passing", "attacking_volleys",
"skill_dribbling", "skill_curve", "skill_fk_accuracy",
"skill_long_passing", "skill_ball_control",
"movement_acceleration", "movement_sprint_speed", "movement_agility",
"movement_reactions", "movement_balance",
"power_shot_power", "power_jumping", "power_stamina",
"power_strength", "power_long_shots",
"mentality_aggression", "mentality_interceptions",
"mentality_positioning", "mentality_vision",
"mentality_penalties", "mentality_composure",
"defending_marking_awareness", "defending_standing_tackle",
"defending_sliding_tackle"
)
df_skill <- df_field %>%
select(short_name, player_positions, overall, all_of(variabel_skill))
cat("Dimensi data setelah pemilihan variabel:\n")
## Dimensi data setelah pemilihan variabel:
cat(" Baris :", nrow(df_skill), "\n")
## Baris : 16343
cat(" Kolom :", ncol(df_skill), "\n")
## Kolom : 38
Ringkasan dimensi data sebelum dan sesudah pembersihan:
tabel_dim <- data.frame(
Tahap = c("Sebelum Pembersihan", "Setelah Hapus GK", "Setelah Pilih Variabel"),
Baris = c(nrow(df_raw), nrow(df_field), nrow(df_skill)),
Kolom = c(ncol(df_raw), ncol(df_field), ncol(df_skill))
)
kable(tabel_dim, caption = "Ringkasan Dimensi Data pada Setiap Tahap Pembersihan")
| Tahap | Baris | Kolom |
|---|---|---|
| Sebelum Pembersihan | 18405 | 110 |
| Setelah Hapus GK | 16343 | 110 |
| Setelah Pilih Variabel | 16343 | 38 |
# Menghitung missing value per variabel skill
df_num <- df_skill %>% select(all_of(variabel_skill))
mv_per_var <- df_num %>%
summarise(across(everything(), ~sum(is.na(.)))) %>%
pivot_longer(everything(), names_to = "Variabel", values_to = "Jumlah_NA") %>%
arrange(desc(Jumlah_NA))
# Total missing value
total_mv <- sum(is.na(df_num))
cat("Total missing value pada variabel skill:", total_mv, "\n")
## Total missing value pada variabel skill: 0
# Menampilkan variabel dengan missing value > 0
mv_ada <- mv_per_var %>% filter(Jumlah_NA > 0)
if (nrow(mv_ada) > 0) {
kable(mv_ada, caption = "Variabel dengan Missing Value")
} else {
cat("Tidak terdapat missing value pada seluruh variabel skill yang dipilih.\n")
}
## Tidak terdapat missing value pada seluruh variabel skill yang dipilih.
Interpretasi: Apabila terdapat missing value, perlu dilakukan penanganan lebih lanjut seperti imputasi atau penghapusan baris sebelum analisis multivariat dilanjutkan. Apabila tidak terdapat missing value, maka data siap untuk tahap analisis berikutnya tanpa perlakuan tambahan.
# Menghapus baris dengan missing value (jika ada)
df_clean <- df_skill %>%
drop_na(all_of(variabel_skill))
cat("Dimensi data setelah penghapusan missing value:",
nrow(df_clean), "baris x", ncol(df_clean), "kolom\n")
## Dimensi data setelah penghapusan missing value: 16343 baris x 38 kolom
# Menghitung statistik deskriptif
df_num_clean <- df_clean %>% select(all_of(variabel_skill))
stat_desk <- df_num_clean %>%
summarise(across(everything(), list(
Mean = ~round(mean(., na.rm = TRUE), 2),
Median = ~round(median(., na.rm = TRUE), 2),
SD = ~round(sd(., na.rm = TRUE), 2),
Min = ~min(., na.rm = TRUE),
Maks = ~max(., na.rm = TRUE)
))) %>%
pivot_longer(everything(),
names_to = c("Variabel", ".value"),
names_sep = "_(?=[^_]+$)") %>%
rename(`Std. Deviasi` = SD, Minimum = Min, Maksimum = Maks)
kable(stat_desk,
caption = "Statistik Deskriptif Variabel Skill Pemain Lapangan FC 26",
align = "lrrrrr")
| Variabel | Mean | Median | Std. Deviasi | Minimum | Maksimum |
|---|---|---|---|---|---|
| pace | 68.37 | 69 | 10.52 | 30 | 97 |
| shooting | 52.81 | 55 | 13.94 | 21 | 92 |
| passing | 57.61 | 58 | 9.91 | 25 | 92 |
| dribbling | 62.88 | 64 | 9.38 | 22 | 93 |
| defending | 51.95 | 57 | 16.20 | 15 | 90 |
| physic | 64.76 | 66 | 9.75 | 32 | 91 |
| attacking_crossing | 53.64 | 55 | 13.43 | 20 | 93 |
| attacking_finishing | 51.33 | 55 | 15.97 | 15 | 94 |
| attacking_heading_accuracy | 56.64 | 57 | 11.37 | 20 | 93 |
| attacking_short_passing | 63.16 | 64 | 9.11 | 25 | 93 |
| attacking_volleys | 46.45 | 46 | 14.20 | 15 | 92 |
| skill_dribbling | 61.41 | 63 | 11.40 | 17 | 94 |
| skill_curve | 51.91 | 52 | 14.23 | 15 | 93 |
| skill_fk_accuracy | 45.93 | 44 | 13.89 | 15 | 94 |
| skill_long_passing | 57.21 | 58 | 11.43 | 20 | 93 |
| skill_ball_control | 63.77 | 64 | 9.21 | 20 | 94 |
| movement_acceleration | 68.27 | 69 | 11.07 | 27 | 97 |
| movement_sprint_speed | 68.43 | 69 | 10.86 | 30 | 97 |
| movement_agility | 66.29 | 67 | 12.03 | 25 | 94 |
| movement_reactions | 62.38 | 62 | 8.49 | 31 | 94 |
| movement_balance | 66.74 | 68 | 11.85 | 29 | 95 |
| power_shot_power | 58.84 | 60 | 12.87 | 20 | 94 |
| power_jumping | 66.94 | 68 | 11.63 | 27 | 95 |
| power_stamina | 66.97 | 67 | 11.21 | 27 | 95 |
| power_strength | 65.43 | 66 | 12.33 | 24 | 95 |
| power_long_shots | 51.22 | 54 | 15.47 | 15 | 91 |
| mentality_aggression | 59.67 | 61 | 13.02 | 24 | 94 |
| mentality_interceptions | 50.88 | 57 | 18.34 | 10 | 91 |
| mentality_positioning | 55.94 | 59 | 14.23 | 15 | 95 |
| mentality_vision | 56.42 | 58 | 12.46 | 22 | 92 |
| mentality_penalties | 51.04 | 50 | 12.06 | 20 | 93 |
| mentality_composure | 60.13 | 60 | 10.02 | 30 | 93 |
| defending_marking_awareness | 50.57 | 56 | 17.70 | 10 | 91 |
| defending_standing_tackle | 52.85 | 59 | 17.98 | 10 | 91 |
| defending_sliding_tackle | 50.40 | 56 | 17.95 | 10 | 89 |
Interpretasi: Berdasarkan tabel di atas, dapat diamati bahwa terdapat variasi yang cukup besar antar variabel skill. Nilai rata-rata dan median yang berdekatan pada sebagian besar variabel mengindikasikan distribusi yang relatif simetris. Namun, nilai standar deviasi yang relatif besar pada beberapa atribut menunjukkan adanya heterogenitas kemampuan pemain yang signifikan dalam dataset. Perbedaan skala antar variabel yang tidak terlalu ekstrem mengindikasikan bahwa normalisasi data perlu dipertimbangkan sebelum penerapan PCA.
Deteksi outlier dilakukan secara visual menggunakan boxplot untuk beberapa atribut skill utama yang merepresentasikan dimensi teknis, fisik, dan mental pemain.
# Memilih atribut utama untuk visualisasi outlier
atribut_utama <- c(
"skill_ball_control", "attacking_short_passing", "skill_long_passing",
"mentality_vision", "skill_dribbling", "movement_acceleration",
"power_stamina", "power_strength", "defending_standing_tackle",
"mentality_composure"
)
df_plot <- df_clean %>%
select(all_of(atribut_utama)) %>%
pivot_longer(everything(), names_to = "Atribut", values_to = "Nilai")
ggplot(df_plot, aes(x = Atribut, y = Nilai)) +
geom_boxplot(fill = "steelblue", alpha = 0.6, outlier.colour = "red",
outlier.size = 1) +
labs(
title = "Boxplot Atribut Skill Utama Pemain Lapangan FC 26",
subtitle = "Titik merah menunjukkan nilai yang teridentifikasi sebagai outlier",
x = "Atribut Skill",
y = "Nilai"
) +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 9))
Interpretasi: Visualisasi boxplot di atas menunjukkan adanya sejumlah nilai ekstrem (outlier) pada beberapa atribut skill. Outlier yang muncul umumnya berasal dari pemain-pemain elit dengan kemampuan jauh di atas rata-rata, maupun dari pemain muda atau pemain dengan spesialisasi posisi tertentu yang memiliki profil atribut tidak seimbang. Keberadaan outlier perlu diperhatikan karena dapat memengaruhi struktur kovarians data dan pada akhirnya memengaruhi arah serta interpretasi komponen utama yang dihasilkan oleh PCA. Oleh karena itu, evaluasi lebih lanjut terhadap outlier diperlukan sebelum penerapan analisis multivariat lanjutan.
# Menghitung matriks korelasi
mat_kor <- cor(df_num_clean, use = "complete.obs", method = "pearson")
# Menampilkan sebagian tabel korelasi (10 variabel pertama) agar mudah dibaca
kable(
round(mat_kor[1:10, 1:10], 3),
caption = "Matriks Korelasi Pearson (10 Variabel Pertama)"
)
| pace | shooting | passing | dribbling | defending | physic | attacking_crossing | attacking_finishing | attacking_heading_accuracy | attacking_short_passing | |
|---|---|---|---|---|---|---|---|---|---|---|
| pace | 1.000 | 0.355 | 0.294 | 0.505 | -0.255 | -0.122 | 0.424 | 0.370 | -0.218 | 0.150 |
| shooting | 0.355 | 1.000 | 0.667 | 0.773 | -0.384 | 0.018 | 0.540 | 0.974 | 0.045 | 0.502 |
| passing | 0.294 | 0.667 | 1.000 | 0.862 | 0.218 | 0.191 | 0.834 | 0.584 | 0.070 | 0.897 |
| dribbling | 0.505 | 0.773 | 0.862 | 1.000 | -0.061 | 0.064 | 0.752 | 0.727 | -0.001 | 0.737 |
| defending | -0.255 | -0.384 | 0.218 | -0.061 | 1.000 | 0.525 | 0.116 | -0.467 | 0.340 | 0.366 |
| physic | -0.122 | 0.018 | 0.191 | 0.064 | 0.525 | 1.000 | 0.023 | -0.056 | 0.683 | 0.350 |
| attacking_crossing | 0.424 | 0.540 | 0.834 | 0.752 | 0.116 | 0.023 | 1.000 | 0.479 | -0.106 | 0.590 |
| attacking_finishing | 0.370 | 0.974 | 0.584 | 0.727 | -0.467 | -0.056 | 0.479 | 1.000 | -0.006 | 0.419 |
| attacking_heading_accuracy | -0.218 | 0.045 | 0.070 | -0.001 | 0.340 | 0.683 | -0.106 | -0.006 | 1.000 | 0.270 |
| attacking_short_passing | 0.150 | 0.502 | 0.897 | 0.737 | 0.366 | 0.350 | 0.590 | 0.419 | 0.270 | 1.000 |
corrplot(
mat_kor,
method = "color",
type = "upper",
order = "hclust",
tl.cex = 0.65,
tl.col = "black",
addCoef.col = NULL,
col = colorRampPalette(c("blue", "white", "red"))(200),
title = "Heatmap Korelasi Antar Variabel Skill Pemain FC 26",
mar = c(0, 0, 1.5, 0)
)
Berdasarkan hasil analisis korelasi pada Sub-bab 2.5, teridentifikasi adanya korelasi yang sangat tinggi di antara banyak variabel skill pemain lapangan. Sebagai contoh, atribut short passing (attacking_short_passing) menunjukkan korelasi yang sangat kuat dengan ball control (skill_ball_control), vision (mentality_vision), long passing (skill_long_passing), dan dribbling (skill_dribbling). Kondisi serupa juga dijumpai pada kelompok atribut teknis lainnya, di mana pasangan variabel seperti skill_dribbling dengan movement_agility, serta power_shot_power dengan attacking_finishing, memiliki nilai korelasi yang tinggi.
# Mengidentifikasi pasangan variabel dengan korelasi sangat tinggi (|r| > 0.80)
mat_kor_df <- as.data.frame(as.table(mat_kor)) %>%
rename(Var1 = Var1, Var2 = Var2, Korelasi = Freq) %>%
filter(as.character(Var1) < as.character(Var2)) %>%
filter(abs(Korelasi) > 0.80) %>%
arrange(desc(abs(Korelasi)))
kable(
mat_kor_df %>% mutate(Korelasi = round(Korelasi, 3)),
caption = "Pasangan Variabel Skill dengan Korelasi Sangat Tinggi (|r| > 0.80)"
)
| Var1 | Var2 | Korelasi |
|---|---|---|
| defending | defending_standing_tackle | 0.981 |
| defending | defending_marking_awareness | 0.978 |
| attacking_finishing | shooting | 0.974 |
| defending | mentality_interceptions | 0.974 |
| dribbling | skill_dribbling | 0.972 |
| defending_sliding_tackle | defending_standing_tackle | 0.972 |
| defending | defending_sliding_tackle | 0.970 |
| movement_sprint_speed | pace | 0.967 |
| movement_acceleration | pace | 0.952 |
| defending_standing_tackle | mentality_interceptions | 0.949 |
| power_long_shots | shooting | 0.944 |
| defending_marking_awareness | mentality_interceptions | 0.940 |
| defending_marking_awareness | defending_standing_tackle | 0.939 |
| defending_sliding_tackle | mentality_interceptions | 0.936 |
| defending_marking_awareness | defending_sliding_tackle | 0.934 |
| dribbling | skill_ball_control | 0.925 |
| physic | power_strength | 0.904 |
| attacking_short_passing | passing | 0.897 |
| mentality_vision | passing | 0.894 |
| attacking_volleys | shooting | 0.886 |
| power_shot_power | shooting | 0.883 |
| mentality_positioning | shooting | 0.878 |
| attacking_short_passing | skill_long_passing | 0.875 |
| attacking_finishing | power_long_shots | 0.873 |
| dribbling | passing | 0.862 |
| passing | skill_ball_control | 0.860 |
| attacking_finishing | mentality_positioning | 0.859 |
| passing | skill_long_passing | 0.854 |
| skill_ball_control | skill_dribbling | 0.852 |
| power_long_shots | power_shot_power | 0.851 |
| attacking_finishing | attacking_volleys | 0.846 |
| movement_acceleration | movement_sprint_speed | 0.844 |
| dribbling | mentality_vision | 0.838 |
| physic | power_jumping | 0.836 |
| attacking_crossing | passing | 0.834 |
| attacking_short_passing | skill_ball_control | 0.828 |
| passing | skill_curve | 0.825 |
| mentality_positioning | power_long_shots | 0.823 |
| power_jumping | power_strength | 0.820 |
| attacking_volleys | power_long_shots | 0.818 |
| attacking_heading_accuracy | power_jumping | 0.817 |
| mentality_penalties | shooting | 0.814 |
| mentality_positioning | skill_dribbling | 0.813 |
| dribbling | mentality_positioning | 0.809 |
| mentality_vision | skill_dribbling | 0.808 |
| passing | skill_dribbling | 0.806 |
Keberadaan korelasi yang sangat tinggi antar variabel ini secara statistik mengindikasikan adanya multikolinearitas yang kuat dalam dataset. Multikolinearitas menyebabkan informasi yang dikandung oleh suatu variabel sebagian besar sudah tercakup dalam variabel lainnya, sehingga terjadi redundansi informasi yang signifikan. Dalam konteks analisis regresi, multikolinearitas dapat menyebabkan estimasi koefisien menjadi tidak stabil. Dalam konteks analisis eksplorasi seperti yang dilakukan pada laporan ini, multikolinearitas menjadi justifikasi utama penerapan metode reduksi dimensi.
Principal Component Analysis (PCA) merupakan metode yang secara khusus dirancang untuk menangani kondisi multikolinearitas dengan cara mentransformasi variabel-variabel asli yang saling berkorelasi menjadi komponen-komponen utama yang saling ortogonal (tidak berkorelasi). Dengan demikian, redundansi informasi dapat dieliminasi, dimensi data dapat dikurangi secara signifikan, dan struktur laten dalam data dapat diungkap dengan lebih jelas.
Tahap feature engineering dilakukan untuk membentuk variabel
turunan yang memiliki makna substantif dalam konteks evaluasi performa
pemain sepak bola. Variabel baru tidak hanya dibuat berdasarkan operasi
matematis, tetapi juga berdasarkan logika permainan, kebutuhan scouting,
dan karakteristik atribut pemain dalam dataset FC 26. Pada bagian ini,
tiga variabel baru dibentuk, yaitu Is_Wonderkid,
Goal_Contribution_Potential, dan
Physical_Dominance.
# Membentuk kembali dataset untuk feature engineering
# karena variabel age dan potential tidak termasuk dalam df_clean pada tahap EDA.
df_fe <- df_field %>%
select(
short_name, player_positions, age, potential, overall,
all_of(variabel_skill)
) %>%
drop_na(age, potential, overall, all_of(variabel_skill)) %>%
mutate(
# 1. Pemain muda dengan potensi tinggi
Is_Wonderkid = ifelse(age <= 21 & potential >= 80, 1, 0),
# 2. Potensi kontribusi gol dari atribut menyerang
Goal_Contribution_Potential = rowMeans(
select(
., shooting, attacking_finishing, attacking_volleys,
power_shot_power, power_long_shots,
mentality_positioning, mentality_penalties
),
na.rm = TRUE
),
# 3. Dominasi fisik dari atribut kekuatan, stamina, kecepatan, dan kelincahan
Physical_Dominance = rowMeans(
select(
., physic, power_strength, power_stamina, power_jumping,
movement_acceleration, movement_sprint_speed,
movement_agility, movement_balance
),
na.rm = TRUE
)
)
# Menampilkan contoh hasil feature engineering
kable(
head(
df_fe %>%
select(
short_name, player_positions, age, potential, overall,
Is_Wonderkid, Goal_Contribution_Potential, Physical_Dominance
),
10
),
digits = 2,
caption = "Contoh Hasil Pembentukan Variabel Baru"
)
| short_name | player_positions | age | potential | overall | Is_Wonderkid | Goal_Contribution_Potential | Physical_Dominance |
|---|---|---|---|---|---|---|---|
| J. Bellingham | CAM, CM | 22 | 94 | 90 | 0 | 84.14 | 83.88 |
| F. Valverde | CM, CDM, RB | 26 | 90 | 89 | 0 | 81.29 | 82.88 |
| J. Kimmich | CDM, RB, CM | 30 | 89 | 89 | 0 | 74.43 | 78.62 |
| A. Hakimi | RB, RM | 26 | 90 | 89 | 0 | 77.71 | 84.12 |
| N. Barella | CM | 28 | 87 | 87 | 0 | 78.71 | 80.62 |
| H. Çalhanoğlu | CDM, CM | 31 | 86 | 86 | 0 | 81.86 | 74.25 |
| F. Dimarco | LB, LM | 27 | 85 | 85 | 0 | 79.00 | 80.00 |
| A. Mac Allister | CM, CDM | 26 | 88 | 87 | 0 | 82.14 | 75.50 |
| Rodri | CDM, CM | 29 | 90 | 90 | 0 | 77.71 | 75.62 |
| A. Griezmann | ST, LM, CAM | 34 | 85 | 85 | 0 | 85.00 | 79.00 |
Pertama, variabel Is_Wonderkid dibuat menggunakan teknik
binning dengan ketentuan pemain berusia maksimal 21 tahun dan
memiliki nilai potential minimal 80 diberi nilai 1,
sedangkan pemain lain diberi nilai 0. Secara substantif, variabel ini
berguna untuk mengidentifikasi pemain muda yang memiliki prospek
perkembangan tinggi. Dalam konteks sepak bola modern, pemain seperti ini
sering menjadi fokus scouting karena dapat memiliki nilai
strategis jangka panjang bagi klub.
Kedua, variabel Goal_Contribution_Potential dibentuk
dari rata-rata beberapa atribut menyerang, yaitu shooting,
attacking_finishing, attacking_volleys,
power_shot_power, power_long_shots,
mentality_positioning, dan
mentality_penalties. Variabel ini dibuat karena kontribusi
gol seorang pemain tidak hanya ditentukan oleh satu atribut, tetapi
merupakan kombinasi dari kemampuan menyelesaikan peluang, kekuatan
tembakan, kemampuan melakukan tembakan jarak jauh, serta kecerdasan
posisi di area menyerang.
Ketiga, variabel Physical_Dominance dibentuk dari
rata-rata atribut fisik seperti physic,
power_strength, power_stamina,
power_jumping, movement_acceleration,
movement_sprint_speed, movement_agility, dan
movement_balance. Variabel ini merepresentasikan dominasi
fisik pemain secara lebih menyeluruh. Pemain dengan nilai fisik tinggi
umumnya lebih mampu memenangkan duel, menjaga intensitas permainan,
bergerak cepat, dan mempertahankan keseimbangan dalam situasi tekanan
lawan.
fitur_baru <- c("Is_Wonderkid", "Goal_Contribution_Potential", "Physical_Dominance")
stat_fitur_baru <- df_fe %>%
select(all_of(fitur_baru)) %>%
summarise(across(everything(), list(
Mean = ~round(mean(., na.rm = TRUE), 2),
Median = ~round(median(., na.rm = TRUE), 2),
SD = ~round(sd(., na.rm = TRUE), 2),
Min = ~round(min(., na.rm = TRUE), 2),
Maks = ~round(max(., na.rm = TRUE), 2)
))) %>%
pivot_longer(
everything(),
names_to = c("Variabel", ".value"),
names_sep = "_(?=[^_]+$)"
) %>%
rename(`Std. Deviasi` = SD, Minimum = Min, Maksimum = Maks)
kable(
stat_fitur_baru,
caption = "Statistik Deskriptif Variabel Hasil Feature Engineering",
align = "lrrrrr"
)
| Variabel | Mean | Median | Std. Deviasi | Minimum | Maksimum |
|---|---|---|---|---|---|
| Is_Wonderkid | 0.04 | 0.00 | 0.20 | 0.00 | 1.00 |
| Goal_Contribution_Potential | 52.52 | 54.14 | 13.00 | 21.71 | 91.57 |
| Physical_Dominance | 66.73 | 67.00 | 6.47 | 39.50 | 89.50 |
df_fe %>%
select(Goal_Contribution_Potential, Physical_Dominance) %>%
pivot_longer(everything(), names_to = "Variabel", values_to = "Nilai") %>%
ggplot(aes(x = Nilai)) +
geom_histogram(bins = 30, fill = "steelblue", color = "white", alpha = 0.8) +
facet_wrap(~ Variabel, scales = "free") +
labs(
title = "Distribusi Variabel Baru Hasil Feature Engineering",
x = "Nilai",
y = "Frekuensi"
) +
theme_bw()
Interpretasi: Variabel hasil feature
engineering memberikan ringkasan informasi yang lebih mudah dibaca
dibandingkan atribut tunggal. Goal_Contribution_Potential
merangkum aspek kemampuan menyerang, sedangkan
Physical_Dominance merangkum kekuatan fisik dan mobilitas
pemain. Sementara itu, Is_Wonderkid memberikan penanda
kategorikal bagi pemain muda dengan potensi tinggi. Ketiga variabel ini
dapat digunakan sebagai kandidat prediktor tambahan dalam proses seleksi
fitur terhadap nilai overall.
Tahap feature selection dilakukan untuk mengidentifikasi
atribut yang paling relevan terhadap nilai overall. Seleksi
fitur penting dilakukan karena dataset memiliki banyak atribut yang
saling berkorelasi. Jika seluruh variabel digunakan secara langsung,
model dapat menjadi kurang efisien dan interpretasi menjadi sulit karena
adanya redundansi informasi. Pada bagian ini digunakan dua pendekatan,
yaitu filter method berbasis korelasi dan embedded
method berbasis Random Forest Feature Importance.
# Menggabungkan variabel skill asli dan variabel hasil feature engineering
predictor_vars <- c(variabel_skill, fitur_baru)
feature_selection_data <- df_fe %>%
select(overall, all_of(predictor_vars)) %>%
drop_na()
cat("Jumlah observasi untuk feature selection:", nrow(feature_selection_data), "\n")
## Jumlah observasi untuk feature selection: 16343
cat("Jumlah kandidat prediktor:", length(predictor_vars), "\n")
## Jumlah kandidat prediktor: 38
Filter method dilakukan dengan memeriksa korelasi
antarvariabel prediktor. Variabel yang memiliki korelasi absolut sangat
tinggi dapat dianggap redundan karena membawa informasi yang hampir
sama. Dalam analisis ini, batas korelasi tinggi ditetapkan pada
|r| > 0,80. Untuk setiap pasangan variabel yang
redundan, variabel yang korelasinya lebih rendah terhadap
overall disarankan untuk dibuang.
# Matriks korelasi antar prediktor
cor_predictor <- cor(
feature_selection_data %>% select(all_of(predictor_vars)),
use = "complete.obs",
method = "pearson"
)
# Korelasi setiap prediktor dengan target overall
cor_target <- cor(
feature_selection_data %>% select(all_of(predictor_vars)),
feature_selection_data$overall,
use = "complete.obs",
method = "pearson"
)[, 1]
# Visualisasi korelasi antar prediktor
corrplot(
cor_predictor,
method = "color",
type = "upper",
order = "hclust",
tl.cex = 0.55,
tl.col = "black",
addCoef.col = NULL,
col = colorRampPalette(c("blue", "white", "red"))(200),
title = "Heatmap Korelasi Kandidat Prediktor",
mar = c(0, 0, 1.5, 0)
)
# Mengubah matriks korelasi menjadi tabel pasangan variabel
high_corr_pairs <- as.data.frame(as.table(cor_predictor)) %>%
rename(Var1 = Var1, Var2 = Var2, Korelasi = Freq) %>%
filter(as.character(Var1) < as.character(Var2)) %>%
filter(abs(Korelasi) > 0.80) %>%
mutate(
Korelasi = round(Korelasi, 3),
Kor_Overall_Var1 = round(cor_target[as.character(Var1)], 3),
Kor_Overall_Var2 = round(cor_target[as.character(Var2)], 3),
Rekomendasi_Dibuang = ifelse(
abs(cor_target[as.character(Var1)]) < abs(cor_target[as.character(Var2)]),
as.character(Var1),
as.character(Var2)
)
) %>%
arrange(desc(abs(Korelasi)))
if (nrow(high_corr_pairs) > 0) {
kable(
high_corr_pairs,
caption = "Pasangan Variabel dengan Korelasi Tinggi dan Rekomendasi Penghapusan"
)
} else {
cat("Tidak terdapat pasangan variabel dengan korelasi absolut di atas 0,80.\n")
}
| Var1 | Var2 | Korelasi | Kor_Overall_Var1 | Kor_Overall_Var2 | Rekomendasi_Dibuang |
|---|---|---|---|---|---|
| Goal_Contribution_Potential | shooting | 0.993 | 0.496 | 0.478 | shooting |
| defending | defending_standing_tackle | 0.981 | 0.366 | 0.318 | defending_standing_tackle |
| defending | defending_marking_awareness | 0.978 | 0.366 | 0.354 | defending_marking_awareness |
| attacking_finishing | shooting | 0.974 | 0.399 | 0.478 | attacking_finishing |
| defending | mentality_interceptions | 0.974 | 0.366 | 0.343 | mentality_interceptions |
| dribbling | skill_dribbling | 0.972 | 0.693 | 0.600 | skill_dribbling |
| defending_sliding_tackle | defending_standing_tackle | 0.972 | 0.283 | 0.318 | defending_sliding_tackle |
| defending | defending_sliding_tackle | 0.970 | 0.366 | 0.283 | defending_sliding_tackle |
| movement_sprint_speed | pace | 0.967 | 0.231 | 0.236 | movement_sprint_speed |
| attacking_finishing | Goal_Contribution_Potential | 0.954 | 0.399 | 0.496 | attacking_finishing |
| movement_acceleration | pace | 0.952 | 0.220 | 0.236 | movement_acceleration |
| defending_standing_tackle | mentality_interceptions | 0.949 | 0.318 | 0.343 | defending_standing_tackle |
| power_long_shots | shooting | 0.944 | 0.476 | 0.478 | power_long_shots |
| Goal_Contribution_Potential | power_long_shots | 0.941 | 0.496 | 0.476 | power_long_shots |
| defending_marking_awareness | mentality_interceptions | 0.940 | 0.354 | 0.343 | mentality_interceptions |
| defending_marking_awareness | defending_standing_tackle | 0.939 | 0.354 | 0.318 | defending_standing_tackle |
| defending_sliding_tackle | mentality_interceptions | 0.936 | 0.283 | 0.343 | defending_sliding_tackle |
| defending_marking_awareness | defending_sliding_tackle | 0.934 | 0.354 | 0.283 | defending_sliding_tackle |
| dribbling | skill_ball_control | 0.925 | 0.693 | 0.793 | dribbling |
| attacking_volleys | Goal_Contribution_Potential | 0.914 | 0.434 | 0.496 | attacking_volleys |
| physic | power_strength | 0.904 | 0.555 | 0.363 | power_strength |
| attacking_short_passing | passing | 0.897 | 0.812 | 0.735 | passing |
| mentality_vision | passing | 0.894 | 0.576 | 0.735 | mentality_vision |
| Goal_Contribution_Potential | mentality_positioning | 0.894 | 0.496 | 0.470 | mentality_positioning |
| Goal_Contribution_Potential | power_shot_power | 0.887 | 0.496 | 0.562 | Goal_Contribution_Potential |
| attacking_volleys | shooting | 0.886 | 0.434 | 0.478 | attacking_volleys |
| power_shot_power | shooting | 0.883 | 0.562 | 0.478 | shooting |
| mentality_positioning | shooting | 0.878 | 0.470 | 0.478 | mentality_positioning |
| attacking_short_passing | skill_long_passing | 0.875 | 0.812 | 0.665 | skill_long_passing |
| attacking_finishing | power_long_shots | 0.873 | 0.399 | 0.476 | attacking_finishing |
| dribbling | passing | 0.862 | 0.693 | 0.735 | dribbling |
| passing | skill_ball_control | 0.860 | 0.735 | 0.793 | passing |
| attacking_finishing | mentality_positioning | 0.859 | 0.399 | 0.470 | attacking_finishing |
| passing | skill_long_passing | 0.854 | 0.735 | 0.665 | skill_long_passing |
| skill_ball_control | skill_dribbling | 0.852 | 0.793 | 0.600 | skill_dribbling |
| power_long_shots | power_shot_power | 0.851 | 0.476 | 0.562 | power_long_shots |
| Goal_Contribution_Potential | mentality_penalties | 0.847 | 0.496 | 0.389 | mentality_penalties |
| attacking_finishing | attacking_volleys | 0.846 | 0.399 | 0.434 | attacking_finishing |
| movement_acceleration | movement_sprint_speed | 0.844 | 0.220 | 0.231 | movement_acceleration |
| dribbling | mentality_vision | 0.838 | 0.693 | 0.576 | mentality_vision |
| physic | power_jumping | 0.836 | 0.555 | 0.589 | physic |
| attacking_crossing | passing | 0.834 | 0.529 | 0.735 | attacking_crossing |
| attacking_short_passing | skill_ball_control | 0.828 | 0.812 | 0.793 | skill_ball_control |
| passing | skill_curve | 0.825 | 0.735 | 0.541 | skill_curve |
| mentality_positioning | power_long_shots | 0.823 | 0.470 | 0.476 | mentality_positioning |
| power_jumping | power_strength | 0.820 | 0.589 | 0.363 | power_strength |
| attacking_volleys | power_long_shots | 0.818 | 0.434 | 0.476 | attacking_volleys |
| attacking_heading_accuracy | power_jumping | 0.817 | 0.494 | 0.589 | attacking_heading_accuracy |
| mentality_penalties | shooting | 0.814 | 0.389 | 0.478 | mentality_penalties |
| mentality_positioning | skill_dribbling | 0.813 | 0.470 | 0.600 | mentality_positioning |
| dribbling | mentality_positioning | 0.809 | 0.693 | 0.470 | mentality_positioning |
| mentality_vision | skill_dribbling | 0.808 | 0.576 | 0.600 | mentality_vision |
| passing | skill_dribbling | 0.806 | 0.735 | 0.600 | skill_dribbling |
# Daftar variabel redundan yang direkomendasikan untuk dibuang
redundant_vars <- unique(high_corr_pairs$Rekomendasi_Dibuang)
selected_filter_vars <- setdiff(predictor_vars, redundant_vars)
cat("Jumlah variabel yang direkomendasikan dibuang:", length(redundant_vars), "\n")
## Jumlah variabel yang direkomendasikan dibuang: 24
cat("Jumlah variabel yang dipertahankan setelah filter method:", length(selected_filter_vars), "\n")
## Jumlah variabel yang dipertahankan setelah filter method: 14
tabel_filter_selection <- data.frame(
Kategori = c(
rep("Dibuang karena redundan", length(redundant_vars)),
rep("Dipertahankan", length(selected_filter_vars))
),
Variabel = c(redundant_vars, selected_filter_vars)
)
kable(
tabel_filter_selection,
caption = "Hasil Seleksi Fitur dengan Filter Method"
)
| Kategori | Variabel |
|---|---|
| Dibuang karena redundan | shooting |
| Dibuang karena redundan | defending_standing_tackle |
| Dibuang karena redundan | defending_marking_awareness |
| Dibuang karena redundan | attacking_finishing |
| Dibuang karena redundan | mentality_interceptions |
| Dibuang karena redundan | skill_dribbling |
| Dibuang karena redundan | defending_sliding_tackle |
| Dibuang karena redundan | movement_sprint_speed |
| Dibuang karena redundan | movement_acceleration |
| Dibuang karena redundan | power_long_shots |
| Dibuang karena redundan | dribbling |
| Dibuang karena redundan | attacking_volleys |
| Dibuang karena redundan | power_strength |
| Dibuang karena redundan | passing |
| Dibuang karena redundan | mentality_vision |
| Dibuang karena redundan | mentality_positioning |
| Dibuang karena redundan | Goal_Contribution_Potential |
| Dibuang karena redundan | skill_long_passing |
| Dibuang karena redundan | mentality_penalties |
| Dibuang karena redundan | physic |
| Dibuang karena redundan | attacking_crossing |
| Dibuang karena redundan | skill_ball_control |
| Dibuang karena redundan | skill_curve |
| Dibuang karena redundan | attacking_heading_accuracy |
| Dipertahankan | pace |
| Dipertahankan | defending |
| Dipertahankan | attacking_short_passing |
| Dipertahankan | skill_fk_accuracy |
| Dipertahankan | movement_agility |
| Dipertahankan | movement_reactions |
| Dipertahankan | movement_balance |
| Dipertahankan | power_shot_power |
| Dipertahankan | power_jumping |
| Dipertahankan | power_stamina |
| Dipertahankan | mentality_aggression |
| Dipertahankan | mentality_composure |
| Dipertahankan | Is_Wonderkid |
| Dipertahankan | Physical_Dominance |
Interpretasi: Berdasarkan filter method,
variabel dengan korelasi sangat tinggi terhadap variabel lain dianggap
memiliki informasi yang tumpang tindih. Oleh karena itu, salah satu
variabel dari pasangan yang redundan dapat dipertimbangkan untuk
dikeluarkan. Pemilihan variabel yang dibuang dilakukan dengan
mempertahankan variabel yang memiliki korelasi lebih kuat terhadap
overall, sehingga proses reduksi fitur tetap
mempertimbangkan relevansi terhadap target analisis.
Metode kedua menggunakan Random Forest Feature Importance.
Metode ini termasuk embedded method karena proses seleksi fitur
dilakukan di dalam algoritma pemodelan. Random Forest menilai seberapa
besar kontribusi setiap variabel dalam menurunkan kesalahan prediksi dan
membentuk pemisahan data yang informatif. Variabel dengan nilai
importance tinggi dapat dianggap lebih berpengaruh terhadap
nilai overall.
if (!requireNamespace("randomForest", quietly = TRUE)) {
stop("Paket randomForest belum terpasang. Jalankan install.packages('randomForest') terlebih dahulu.")
}
library(randomForest)
set.seed(123)
rf_model <- randomForest(
overall ~ .,
data = feature_selection_data,
ntree = 500,
importance = TRUE,
na.action = na.omit
)
# Mengambil nilai feature importance
importance_matrix <- randomForest::importance(rf_model)
importance_df <- data.frame(
Feature = rownames(importance_matrix),
IncMSE = importance_matrix[, "%IncMSE"],
IncNodePurity = importance_matrix[, "IncNodePurity"]
) %>%
arrange(desc(IncMSE))
# Menampilkan 15 variabel paling penting
top_importance <- importance_df %>% slice_head(n = 15)
kable(
top_importance,
digits = 3,
caption = "Lima Belas Variabel Terpenting Berdasarkan Random Forest"
)
| Feature | IncMSE | IncNodePurity | |
|---|---|---|---|
| Physical_Dominance | Physical_Dominance | 54.136 | 14603.373 |
| pace | pace | 49.299 | 2201.234 |
| movement_sprint_speed | movement_sprint_speed | 49.013 | 2178.513 |
| attacking_finishing | attacking_finishing | 46.281 | 3191.004 |
| attacking_crossing | attacking_crossing | 43.952 | 8466.834 |
| shooting | shooting | 39.380 | 6749.997 |
| power_stamina | power_stamina | 37.615 | 3414.506 |
| movement_acceleration | movement_acceleration | 37.189 | 1440.661 |
| defending | defending | 33.838 | 40837.330 |
| defending_standing_tackle | defending_standing_tackle | 32.717 | 17879.866 |
| power_jumping | power_jumping | 32.467 | 12088.305 |
| power_strength | power_strength | 32.179 | 1357.240 |
| Goal_Contribution_Potential | Goal_Contribution_Potential | 31.970 | 4463.513 |
| movement_reactions | movement_reactions | 30.829 | 222077.569 |
| physic | physic | 30.676 | 5027.931 |
ggplot(top_importance, aes(x = reorder(Feature, IncMSE), y = IncMSE)) +
geom_col(fill = "steelblue") +
coord_flip() +
labs(
title = "Top 15 Feature Importance terhadap Overall Rating",
subtitle = "Embedded Method: Random Forest",
x = "Variabel",
y = "Importance (%IncMSE)"
) +
theme_bw()
# Variabel yang direkomendasikan berdasarkan Random Forest
# Diambil dari 10 variabel dengan importance tertinggi.
rf_selected_vars <- importance_df %>%
slice_head(n = 10) %>%
pull(Feature)
kable(
data.frame(
Peringkat = seq_along(rf_selected_vars),
Variabel_Terpilih = rf_selected_vars
),
caption = "Rekomendasi Variabel Terpilih Berdasarkan Random Forest"
)
| Peringkat | Variabel_Terpilih |
|---|---|
| 1 | Physical_Dominance |
| 2 | pace |
| 3 | movement_sprint_speed |
| 4 | attacking_finishing |
| 5 | attacking_crossing |
| 6 | shooting |
| 7 | power_stamina |
| 8 | movement_acceleration |
| 9 | defending |
| 10 | defending_standing_tackle |
Interpretasi: Hasil Random Forest Feature
Importance menunjukkan variabel yang memiliki kontribusi paling
besar dalam menjelaskan variasi nilai overall. Variabel
yang berada pada peringkat atas dapat diprioritaskan sebagai prediktor
utama karena memiliki pengaruh relatif lebih kuat terhadap performa umum
pemain. Sebaliknya, variabel dengan nilai importance rendah
dapat dipertimbangkan untuk tidak digunakan dalam model lanjutan,
terutama apabila variabel tersebut juga terindikasi redundan pada tahap
filter method.
# Membandingkan variabel yang dipertahankan oleh filter method dan RF top 10
comparison_selection <- data.frame(
Variabel = unique(c(selected_filter_vars, rf_selected_vars)),
Dipertahankan_Filter_Method = unique(c(selected_filter_vars, rf_selected_vars)) %in% selected_filter_vars,
Masuk_Top10_Random_Forest = unique(c(selected_filter_vars, rf_selected_vars)) %in% rf_selected_vars
)
kable(
comparison_selection,
caption = "Perbandingan Hasil Filter Method dan Random Forest Feature Importance"
)
| Variabel | Dipertahankan_Filter_Method | Masuk_Top10_Random_Forest |
|---|---|---|
| pace | TRUE | TRUE |
| defending | TRUE | TRUE |
| attacking_short_passing | TRUE | FALSE |
| skill_fk_accuracy | TRUE | FALSE |
| movement_agility | TRUE | FALSE |
| movement_reactions | TRUE | FALSE |
| movement_balance | TRUE | FALSE |
| power_shot_power | TRUE | FALSE |
| power_jumping | TRUE | FALSE |
| power_stamina | TRUE | TRUE |
| mentality_aggression | TRUE | FALSE |
| mentality_composure | TRUE | FALSE |
| Is_Wonderkid | TRUE | FALSE |
| Physical_Dominance | TRUE | TRUE |
| movement_sprint_speed | FALSE | TRUE |
| attacking_finishing | FALSE | TRUE |
| attacking_crossing | FALSE | TRUE |
| shooting | FALSE | TRUE |
| movement_acceleration | FALSE | TRUE |
| defending_standing_tackle | FALSE | TRUE |
Berdasarkan dua metode seleksi fitur, variabel yang ideal untuk
diprioritaskan adalah variabel yang tidak redundan menurut filter
method dan juga memiliki nilai penting tinggi menurut Random
Forest. Kombinasi kedua metode ini membantu menghasilkan pemilihan fitur
yang lebih seimbang. Filter method berfokus pada pengurangan
redundansi antarvariabel, sedangkan Random Forest berfokus pada
kontribusi prediktif variabel terhadap overall. Dengan
demikian, hasil akhir seleksi fitur tidak hanya mempertimbangkan
hubungan linear antarvariabel, tetapi juga mempertimbangkan kemampuan
variabel dalam menjelaskan performa pemain secara model-based.
Tahap feature engineering menghasilkan tiga variabel baru,
yaitu Is_Wonderkid,
Goal_Contribution_Potential, dan
Physical_Dominance. Ketiga variabel tersebut memiliki dasar
substantif yang relevan dengan analisis pemain sepak bola, karena
masing-masing merepresentasikan potensi pemain muda, kemampuan
kontribusi gol, dan dominasi fisik. Selanjutnya, tahap feature
selection menunjukkan bahwa tidak semua atribut perlu digunakan
secara bersamaan karena terdapat potensi redundansi informasi
antarvariabel. Melalui filter method, variabel dengan korelasi
sangat tinggi dapat diseleksi agar model lebih efisien. Sementara itu,
Random Forest memberikan gambaran variabel mana yang paling berpengaruh
terhadap nilai overall. Kombinasi kedua metode ini
memberikan dasar yang lebih kuat untuk memilih fitur yang relevan
sebelum analisis multivariat atau pemodelan lanjutan dilakukan.
Principal Component Analysis (PCA) merupakan teknik reduksi dimensi yang mentransformasi variabel-variabel asli yang saling berkorelasi menjadi sekumpulan komponen utama yang ortogonal (tidak berkorelasi satu sama lain). Tujuannya adalah meringkas sebanyak mungkin informasi (varians) dari data asli ke dalam sejumlah kecil komponen, sehingga analisis menjadi lebih efisien dan mudah diinterpretasikan.
Pada tahap ini, PCA diterapkan terhadap seluruh variabel hasil
feature engineering — mencakup 35 atribut skill asli ditambah 3
variabel baru (Is_Wonderkid,
Goal_Contribution_Potential,
Physical_Dominance) — menggunakan standardisasi skala
(scale = TRUE) karena variabel-variabel tersebut memiliki
satuan dan skala yang berbeda.
library(tidyverse)
library(factoextra)
library(knitr)
# Variabel yang akan digunakan dalam PCA:
# variabel_skill (35 atribut) + 3 variabel hasil feature engineering
pca_vars <- c(variabel_skill, fitur_baru)
# Subset data numerik untuk PCA (tanpa NA)
df_pca_input <- df_fe %>%
select(short_name, player_positions, overall, age, potential,
all_of(pca_vars)) %>%
drop_na(all_of(pca_vars))
cat("Jumlah observasi untuk PCA:", nrow(df_pca_input), "\n")
## Jumlah observasi untuk PCA: 16343
cat("Jumlah variabel input PCA :", length(pca_vars), "\n")
## Jumlah variabel input PCA : 38
Standardisasi skala wajib diterapkan karena variabel baru hasil
feature engineering (Goal_Contribution_Potential,
Physical_Dominance) memiliki rentang nilai yang berbeda
dari variabel atribut asli (0–100). Tanpa standardisasi, variabel dengan
varians besar akan mendominasi komponen utama secara artifisial.
# Menjalankan PCA dengan standardisasi skala
pca_result <- prcomp(
df_pca_input %>% select(all_of(pca_vars)),
scale = TRUE
)
# Membalik arah kutub PC1 agar Nilai Positif = Atribut Ofensif Tinggi
pca_result$rotation[, "PC1"] <- -pca_result$rotation[, "PC1"]
pca_result$x[, "PC1"] <- -pca_result$x[, "PC1"]
# Ringkasan PCA
summary_pca <- summary(pca_result)
# Mengambil informasi varians dari ringkasan PCA
var_info <- summary_pca$importance
# Membuat tabel untuk 10 PC pertama
tabel_variance <- data.frame(
# Komponen = paste0("PC", 1:10),
Standar_Deviasi = round(pca_result$sdev[1:10], 4),
Prop_Variance = round(var_info["Proportion of Variance", 1:10], 4),
Kum_Variance = round(var_info["Cumulative Proportion", 1:10], 4)
)
kable(
tabel_variance,
col.names = c("Standar Deviasi", "Proporsi Varians",
"Varians Kumulatif"),
caption = "Tabel Proportion of Variance Hasil PCA (10 PC Pertama)",
align = "lrrr"
)
| Standar Deviasi | Proporsi Varians | Varians Kumulatif | |
|---|---|---|---|
| PC1 | 3.9781 | 0.4165 | 0.4165 |
| PC2 | 2.9098 | 0.2228 | 0.6393 |
| PC3 | 1.9166 | 0.0967 | 0.7359 |
| PC4 | 1.7172 | 0.0776 | 0.8135 |
| PC5 | 1.0379 | 0.0284 | 0.8419 |
| PC6 | 0.8720 | 0.0200 | 0.8619 |
| PC7 | 0.7912 | 0.0165 | 0.8784 |
| PC8 | 0.7372 | 0.0143 | 0.8927 |
| PC9 | 0.6715 | 0.0119 | 0.9045 |
| PC10 | 0.6424 | 0.0109 | 0.9154 |
prop_var <- var_info["Proportion of Variance", ]
cum_var <- var_info["Cumulative Proportion", ]
# Berapa PC untuk mencapai 80% dan 85%
pc_80 <- which(cum_var >= 0.80)[1]
pc_85 <- which(cum_var >= 0.85)[1]
cat(sprintf("PC1 menjelaskan %.2f%% varians total.\n", prop_var[1]*100))
## PC1 menjelaskan 41.65% varians total.
cat(sprintf("PC2 menjelaskan %.2f%% varians total.\n", prop_var[2]*100))
## PC2 menjelaskan 22.28% varians total.
cat(sprintf("PC1 + PC2 kumulatif : %.2f%%\n", cum_var[2]*100))
## PC1 + PC2 kumulatif : 63.93%
cat(sprintf("PC1 – PC3 kumulatif : %.2f%%\n", cum_var[3]*100))
## PC1 – PC3 kumulatif : 73.59%
cat(sprintf("PC1 – PC4 kumulatif : %.2f%%\n", cum_var[4]*100))
## PC1 – PC4 kumulatif : 81.35%
cat(sprintf("\nUntuk mencapai >= 80%% varians diperlukan %d PC.\n", pc_80))
##
## Untuk mencapai >= 80% varians diperlukan 4 PC.
cat(sprintf("Untuk mencapai >= 85%% varians diperlukan %d PC.\n", pc_85))
## Untuk mencapai >= 85% varians diperlukan 6 PC.
Interpretasi: Hasil PCA menunjukkan bahwa PC1 saja mampu menjelaskan sekitar 41,65% varians total, mengindikasikan adanya satu dimensi dominan yang mencerminkan atribut teknik pemain lapangan secara umum. PC2 menambahkan sekitar 22,28% varians, sehingga dua komponen pertama secara kumulatif menjelaskan ±63,93% varians. Empat komponen pertama (PC1–PC4) berhasil merangkum ±81,35% varians dari 38 variabel asal.
Dengan demikian, reduksi dimensi kelompok ini berhasil: dari 38 variabel, hanya 4 komponen utama yang diperlukan untuk merepresentasikan lebih dari 80% informasi data. Ini membuktikan bahwa terdapat struktur korelasi yang kuat antar atribut pemain, sehingga informasinya dapat dipadatkan secara efektif.
Sebagai acuan tambahan, eigenvalue dari PC1 hingga PC4 semuanya melebihi nilai 1 (kriteria Kaiser Rule), yang mengonfirmasi bahwa keempat komponen tersebut layak dipertahankan sebagai komponen bermakna.
# Eigenvalues = sdev^2
eigenvalues <- pca_result$sdev^2
tabel_eigen <- data.frame(
Komponen = paste0("PC", 1:10),
Eigenvalue = round(eigenvalues[1:10], 4),
Status = ifelse(eigenvalues[1:10] > 1, "Pertahankan (> 1)", "Abaikan (<= 1)")
)
kable(
tabel_eigen,
caption = "Eigenvalue Komponen Utama dan Keputusan Kaiser Rule",
align = "lrr"
)
| Komponen | Eigenvalue | Status |
|---|---|---|
| PC1 | 15.8257 | Pertahankan (> 1) |
| PC2 | 8.4667 | Pertahankan (> 1) |
| PC3 | 3.6732 | Pertahankan (> 1) |
| PC4 | 2.9487 | Pertahankan (> 1) |
| PC5 | 1.0771 | Pertahankan (> 1) |
| PC6 | 0.7603 | Abaikan (<= 1) |
| PC7 | 0.6260 | Abaikan (<= 1) |
| PC8 | 0.5434 | Abaikan (<= 1) |
| PC9 | 0.4509 | Abaikan (<= 1) |
| PC10 | 0.4127 | Abaikan (<= 1) |
fviz_eig(
pca_result,
addlabels = TRUE,
ylim = c(0, 45),
barfill = "steelblue",
barcolor = "white",
linecolor = "tomato",
ncp = 15,
main = "Scree Plot – Proporsi Varians Tiap Komponen Utama",
xlab = "Komponen Utama",
ylab = "Persentase Varians yang Dijelaskan (%)"
) +
geom_hline(
yintercept = 100 / length(pca_vars),
linetype = "dashed",
color = "darkgreen",
linewidth = 0.8
) +
annotate(
"text", x = 12, y = 100 / length(pca_vars) + 0.8,
label = "Rata-rata varians per variabel",
color = "darkgreen", size = 3
)
Scree Plot Hasil PCA
Membaca Scree Plot: Scree plot menampilkan besarnya varians yang dijelaskan oleh masing-masing PC secara berurutan. “Siku” (elbow) grafik terdapat pada PC5, di mana terjadi penurunan drastis dari PC4 ke PC5 (dari ~7,76% menjadi ~2,83%). Ini menguatkan keputusan mempertahankan 4 komponen utama berdasarkan Kaiser Rule. Garis putus-putus hijau menunjukkan rata-rata varians per variabel (100%/38 ≈ 2,63%); komponen yang berada di atas garis ini dianggap membawa informasi di atas rata-rata.
Loading factor menunjukkan seberapa kuat kontribusi setiap variabel asli terhadap masing-masing komponen utama. Nilai positif mengindikasikan variabel berkontribusi searah dengan komponen, sedangkan nilai negatif menunjukkan arah berlawanan.
# Mengambil loading factor (matriks rotasi)
loadings_df <- as.data.frame(pca_result$rotation[, 1:4])
loadings_df$Variabel <- rownames(loadings_df)
# Sempurnakan fungsi select dengan menyertakan kolom Variabel
loadings_df <- loadings_df %>%
select(Variabel, PC1, PC2, PC3, PC4) %>%
arrange(desc(abs(PC1)))
kable(
loadings_df %>% mutate(across(PC1:PC4, ~round(., 4))),
caption = "Loading Factor Variabel pada PC1 hingga PC4",
align = "lrrrr"
)
| Variabel | PC1 | PC2 | PC3 | PC4 | |
|---|---|---|---|---|---|
| dribbling | dribbling | 0.2366 | 0.0142 | 0.0812 | -0.0132 |
| Goal_Contribution_Potential | Goal_Contribution_Potential | 0.2295 | -0.0761 | -0.1454 | -0.0546 |
| skill_dribbling | skill_dribbling | 0.2265 | -0.0141 | 0.0681 | -0.0275 |
| shooting | shooting | 0.2263 | -0.0824 | -0.1432 | -0.0532 |
| power_long_shots | power_long_shots | 0.2217 | -0.0502 | -0.0973 | -0.0911 |
| mentality_positioning | mentality_positioning | 0.2210 | -0.0648 | -0.0493 | -0.0197 |
| mentality_vision | mentality_vision | 0.2204 | 0.0257 | 0.0406 | -0.1380 |
| passing | passing | 0.2204 | 0.1068 | 0.0907 | -0.1384 |
| skill_ball_control | skill_ball_control | 0.2201 | 0.0717 | 0.0060 | -0.0498 |
| skill_curve | skill_curve | 0.2147 | 0.0086 | 0.0634 | -0.0975 |
| attacking_finishing | attacking_finishing | 0.2118 | -0.1150 | -0.1390 | -0.0346 |
| power_shot_power | power_shot_power | 0.2082 | -0.0050 | -0.1660 | -0.0510 |
| attacking_volleys | attacking_volleys | 0.2045 | -0.0820 | -0.1593 | -0.0454 |
| skill_fk_accuracy | skill_fk_accuracy | 0.1971 | -0.0050 | 0.0023 | -0.1646 |
| attacking_crossing | attacking_crossing | 0.1892 | 0.0443 | 0.1812 | -0.0609 |
| mentality_composure | mentality_composure | 0.1860 | 0.1433 | -0.0731 | -0.0369 |
| attacking_short_passing | attacking_short_passing | 0.1811 | 0.1719 | 0.0307 | -0.1161 |
| mentality_penalties | mentality_penalties | 0.1811 | -0.0842 | -0.1992 | -0.0569 |
| movement_agility | movement_agility | 0.1742 | -0.0792 | 0.2402 | 0.1259 |
| Physical_Dominance | Physical_Dominance | 0.1623 | 0.1041 | 0.0440 | 0.3887 |
| movement_reactions | movement_reactions | 0.1592 | 0.1906 | -0.0725 | 0.0206 |
| skill_long_passing | skill_long_passing | 0.1505 | 0.1892 | 0.0959 | -0.1790 |
| movement_balance | movement_balance | 0.1343 | -0.0816 | 0.2922 | 0.0197 |
| movement_acceleration | movement_acceleration | 0.1342 | -0.0984 | 0.2453 | 0.3308 |
| pace | pace | 0.1284 | -0.0916 | 0.2225 | 0.3805 |
| movement_sprint_speed | movement_sprint_speed | 0.1145 | -0.0794 | 0.1881 | 0.3939 |
| power_stamina | power_stamina | 0.1057 | 0.1773 | 0.0368 | 0.1870 |
| power_jumping | power_jumping | 0.0585 | 0.1868 | -0.2609 | 0.3300 |
| defending_sliding_tackle | defending_sliding_tackle | -0.0461 | 0.2983 | 0.1837 | -0.0722 |
| defending_standing_tackle | defending_standing_tackle | -0.0372 | 0.3041 | 0.1734 | -0.0756 |
| defending | defending | -0.0342 | 0.3188 | 0.1410 | -0.0608 |
| defending_marking_awareness | defending_marking_awareness | -0.0341 | 0.3092 | 0.1498 | -0.0622 |
| physic | physic | 0.0316 | 0.2648 | -0.2264 | 0.2101 |
| mentality_interceptions | mentality_interceptions | -0.0288 | 0.3069 | 0.1602 | -0.0727 |
| mentality_aggression | mentality_aggression | 0.0278 | 0.2747 | -0.0598 | 0.0408 |
| Is_Wonderkid | Is_Wonderkid | 0.0218 | -0.0053 | 0.0389 | 0.0073 |
| power_strength | power_strength | -0.0153 | 0.2042 | -0.3250 | 0.1985 |
| attacking_heading_accuracy | attacking_heading_accuracy | 0.0143 | 0.1927 | -0.3203 | 0.1324 |
# PC1 – Top 12 variabel
p1 <- loadings_df %>%
slice_head(n = 12) %>%
ggplot(aes(x = reorder(Variabel, abs(PC1)), y = PC1,
fill = PC1 > 0)) +
geom_col(show.legend = FALSE) +
coord_flip() +
scale_fill_manual(values = c("tomato", "steelblue")) +
labs(title = "PC1 – Top 12 Loading Factor",
x = NULL, y = "Loading") +
theme_bw(base_size = 11)
# PC2 – Top 12 variabel
p2 <- as.data.frame(pca_result$rotation[, 1:4])
p2$Variabel <- rownames(p2)
p2 <- p2 %>% arrange(desc(abs(PC2))) %>% slice_head(n = 12) %>%
ggplot(aes(x = reorder(Variabel, abs(PC2)), y = PC2,
fill = PC2 > 0)) +
geom_col(show.legend = FALSE) +
coord_flip() +
scale_fill_manual(values = c("tomato", "steelblue")) +
labs(title = "PC2 – Top 12 Loading Factor",
x = NULL, y = "Loading") +
theme_bw(base_size = 11)
gridExtra::grid.arrange(p1, p2, ncol = 2)
# PC3
p3 <- as.data.frame(pca_result$rotation[, 1:4])
p3$Variabel <- rownames(p3)
p3 <- p3 %>% arrange(desc(abs(PC3))) %>% slice_head(n = 12) %>%
ggplot(aes(x = reorder(Variabel, abs(PC3)), y = PC3,
fill = PC3 > 0)) +
geom_col(show.legend = FALSE) +
coord_flip() +
scale_fill_manual(values = c("tomato", "steelblue")) +
labs(title = "PC3 – Top 12 Loading Factor",
x = NULL, y = "Loading") +
theme_bw(base_size = 11)
# PC4
p4 <- as.data.frame(pca_result$rotation[, 1:4])
p4$Variabel <- rownames(p4)
p4 <- p4 %>% arrange(desc(abs(PC4))) %>% slice_head(n = 12) %>%
ggplot(aes(x = reorder(Variabel, abs(PC4)), y = PC4,
fill = PC4 > 0)) +
geom_col(show.legend = FALSE) +
coord_flip() +
scale_fill_manual(values = c("tomato", "steelblue")) +
labs(title = "PC4 – Top 12 Loading Factor",
x = NULL, y = "Loading") +
theme_bw(base_size = 11)
gridExtra::grid.arrange(p3, p4, ncol = 2)
Berdasarkan analisis loading factor, setiap komponen utama dapat diberi nama substantif sebagai berikut:
PC1 — “Kemampuan Teknik Menyerang & Kreativitas”
PC1 memiliki loading positif tinggi pada variabel
dribbling, skill_dribbling,
shooting, Goal_Contribution_Potential,
power_long_shots, mentality_positioning,
mentality_vision, passing, dan
skill_ball_control. Komponen ini merangkum kemampuan teknis
ofensif pemain lapangan secara menyeluruh: kualitas mengolah bola,
ketajaman penyelesaian, dan kecerdasan membaca permainan. Pemain dengan
skor PC1 tinggi adalah pemain berkualifikasi tinggi secara teknis —
tipikal midfielder kreatif atau penyerang skillful.
PC2 — “Orientasi Bertahan & Kekuatan Fisik
Defensif” PC2 didominasi loading positif pada
defending, defending_marking_awareness,
mentality_interceptions,
defending_standing_tackle,
defending_sliding_tackle, dan
mentality_aggression. Komponen ini mencerminkan profil
pemain dengan spesialisasi bertahan — center-back,
defensive midfielder, atau pemain dengan gaya main keras dan
agresif. Nilai PC2 tinggi mengindikasikan pemain yang lebih mengutamakan
pertahanan daripada kreasi serangan.
PC3 — “Kekuatan Fisik Statis vs. Kelincahan Dinamis”
PC3 memiliki loading positif pada power_strength,
attacking_heading_accuracy, dan power_jumping,
namun loading negatif pada movement_balance,
movement_agility, dan movement_acceleration.
Komponen ini membedakan pemain berbadan besar dan kuat (menang duel
udara, fisik dominan) dengan pemain yang gesit dan lincah. Skor PC3
tinggi = pemain tipe target man atau bek tinggi; skor rendah =
pemain cepat dan lincah.
PC4 — “Kecepatan & Daya Ledak Fisik” PC4
didominasi loading positif pada movement_sprint_speed,
Physical_Dominance, pace, dan
movement_acceleration. Komponen ini secara spesifik
mengukur dimensi kecepatan berlari dan daya ledak sprint — sesuatu yang
tidak sepenuhnya tertangkap oleh PC1–PC3. Variabel
Physical_Dominance yang merupakan hasil feature
engineering memiliki loading tinggi di sini, menunjukkan
relevansinya dalam menangkap dimensi fisik yang unik.
tabel_pc <- data.frame(
Komponen = c("PC1", "PC2", "PC3", "PC4"),
Nama_Substantif = c(
"Kemampuan Teknik Menyerang & Kreativitas",
"Orientasi Bertahan & Kekuatan Fisik Defensif",
"Kekuatan Fisik Statis vs. Kelincahan Dinamis",
"Kecepatan & Daya Ledak Fisik"
),
Varians_Dijelaskan = c("41.65%", "22.28%", "9.67%", "7.76%"),
Variabel_Kunci = c(
"dribbling, shooting, Goal_Contribution_Potential, passing, mentality_vision",
"defending, defending_marking_awareness, mentality_interceptions, defending_standing_tackle",
"power_strength, attacking_heading_accuracy (+) vs. movement_balance, movement_agility (-)",
"movement_sprint_speed, Physical_Dominance, pace, movement_acceleration"
)
)
kable(
tabel_pc,
col.names = c("Komponen", "Nama Substantif", "Varians Dijelaskan", "Variabel Kunci"),
caption = "Ringkasan Penamaan dan Interpretasi Komponen Utama PCA",
align = "llrr"
)
| Komponen | Nama Substantif | Varians Dijelaskan | Variabel Kunci |
|---|---|---|---|
| PC1 | Kemampuan Teknik Menyerang & Kreativitas | 41.65% | dribbling, shooting, Goal_Contribution_Potential, passing, mentality_vision |
| PC2 | Orientasi Bertahan & Kekuatan Fisik Defensif | 22.28% | defending, defending_marking_awareness, mentality_interceptions, defending_standing_tackle |
| PC3 | Kekuatan Fisik Statis vs. Kelincahan Dinamis | 9.67% | power_strength, attacking_heading_accuracy (+) vs. movement_balance, movement_agility (-) |
| PC4 | Kecepatan & Daya Ledak Fisik | 7.76% | movement_sprint_speed, Physical_Dominance, pace, movement_acceleration |
Biplot menampilkan secara bersamaan posisi observasi (pemain) dalam ruang komponen utama dan arah panah variabel (loading vector). Panjang panah menunjukkan kekuatan kontribusi variabel, sementara sudut antar panah mengindikasikan korelasi.
# Menyiapkan skor PCA dengan informasi pemain
pca_scores_df <- as.data.frame(pca_result$x[, 1:4])
pca_scores_df$short_name <- df_pca_input$short_name
pca_scores_df$player_positions <- df_pca_input$player_positions
pca_scores_df$overall <- df_pca_input$overall
pca_scores_df$age <- df_pca_input$age
pca_scores_df$Is_Wonderkid <- df_pca_input$Is_Wonderkid
# Biplot standar menggunakan factoextra
fviz_pca_biplot(
pca_result,
axes = c(1, 2),
geom.ind = "point",
col.ind = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
col.var = "black",
repel = TRUE,
label = "var",
alpha.ind = 0.3,
title = "Biplot PCA – PC1 (Teknik Menyerang) vs PC2 (Kemampuan Bertahan)",
legend.title = "Kualitas Representasi (cos²)"
)
Biplot PC1 vs PC2
Membaca Biplot:
Panah variabel: Panah yang mengarah ke kanan
(positif PC1) mewakili variabel teknik menyerang
(dribbling, shooting, passing).
Panah yang mengarah ke atas (positif PC2) mewakili variabel bertahan
(defending, mentality_interceptions). Variabel
goalkeeping secara konsisten terletak terpisah karena telah
dihapus dari dataset, sementara atribut kiper yang tersisa memiliki
loading lemah.
Posisi pemain: Pemain yang terletak di kuadran kanan-bawah merupakan pemain dengan kemampuan teknik menyerang tinggi namun bertahan rendah (tipikal penyerang). Pemain di kuadran kanan-atas memiliki profil dua sisi (box-to-box midfielder). Pemain di kuadran kiri-atas adalah spesialis bertahan.
Sudut antar panah: Variabel-variabel dalam
kelompok yang sama (misal: defending,
defending_marking_awareness,
mentality_interceptions) membentuk sudut kecil antara satu
sama lain, menandakan korelasi tinggi — konsisten dengan temuan
filter method sebelumnya.
# Biplot yang menyoroti posisi wonderkid
pca_scores_df %>%
mutate(Kategori = ifelse(Is_Wonderkid == 1, "Wonderkid", "Non-Wonderkid")) %>%
ggplot(aes(x = PC1, y = PC2, color = Kategori, alpha = Kategori)) +
geom_point(size = 1.2) +
scale_color_manual(values = c("Non-Wonderkid" = "gray70",
"Wonderkid" = "#E63946")) +
scale_alpha_manual(values = c("Non-Wonderkid" = 0.25,
"Wonderkid" = 0.85)) +
geom_hline(yintercept = 0, linetype = "dashed", color = "gray40") +
geom_vline(xintercept = 0, linetype = "dashed", color = "gray40") +
labs(
title = "Distribusi Wonderkid dalam Ruang PC1 vs PC2",
subtitle = "Wonderkid = Usia ≤ 21 tahun & Potential ≥ 80",
x = "PC1 – Kemampuan Teknik Menyerang & Kreativitas",
y = "PC2 – Orientasi Bertahan & Kekuatan Fisik Defensif",
color = "Kategori",
alpha = "Kategori"
) +
theme_bw(base_size = 12)
Distribusi Wonderkid dalam Ruang PCA
# Menampilkan 15 wonderkid dengan skor PC1 tertinggi
top_wonderkid <- pca_scores_df %>%
filter(Is_Wonderkid == 1) %>%
arrange(desc(PC1)) %>%
slice_head(n = 15) %>%
select(short_name, player_positions, overall, age, PC1, PC2) %>%
mutate(across(c(PC1, PC2), ~round(., 3)))
kable(
top_wonderkid,
col.names = c("Nama Pemain", "Posisi", "Overall", "Usia",
"PC1 (Teknik Menyerang)", "PC2 (Bertahan)"),
caption = "15 Wonderkid dengan Skor PC1 (Kemampuan Teknik Menyerang) Tertinggi",
align = "llrrrr"
)
| Nama Pemain | Posisi | Overall | Usia | PC1 (Teknik Menyerang) | PC2 (Bertahan) |
|---|---|---|---|---|---|
| Lamine Yamal | RM, RW | 89 | 17 | 10.989 | -3.089 |
| D. Doué | RW, LW, CM, RM | 85 | 20 | 10.079 | 1.614 |
| R. Cherki | RW, RM, CAM | 81 | 21 | 9.068 | -2.524 |
| K. Yıldız | CAM, LM, LW, CM | 79 | 20 | 8.631 | -1.462 |
| A. Güler | RM, CAM, RW | 81 | 20 | 8.408 | -0.860 |
| João Neves | CM, CDM | 85 | 20 | 8.338 | 6.195 |
| Savinho | RW, LW, RM | 82 | 21 | 8.334 | -2.578 |
| Estêvão | RM, CAM, RW | 78 | 18 | 8.326 | -2.572 |
| A. Garnacho | CAM, LW, LM, CM | 77 | 21 | 7.819 | -2.228 |
| M. Tel | ST, LW, CAM | 77 | 20 | 7.582 | -2.776 |
| A. Fatawu | RM, RW | 76 | 21 | 7.374 | -0.401 |
| J. Gittens | LM, LW | 78 | 20 | 7.106 | -3.414 |
| F. Mastantuono | CAM, RW, ST | 77 | 17 | 7.074 | 0.100 |
| Endrick | ST, RW | 77 | 18 | 6.996 | -2.143 |
| Gavi | CM, CAM | 83 | 20 | 6.987 | 3.453 |
Interpretasi: Wonderkid yang berada di puncak skor PC1 adalah pemain muda dengan kemampuan teknik menyerang yang sudah menonjol di usianya. Sebagian besar di antaranya memiliki skor PC2 negatif atau rendah, yang mengonfirmasi bahwa mereka adalah pemain yang berorientasi menyerang, bukan bertahan.
Hasil PCA membuktikan bahwa meskipun dataset FC 26 memiliki 38 variabel, struktur informasinya dapat dirangkum ke dalam empat dimensi utama yang memiliki makna substantif jelas. Keempat dimensi ini tidak bersifat arbitrer, melainkan mencerminkan realitas sepak bola:
Keberhasilan merangkum >80% varians dari 38 variabel ke dalam 4 komponen membuktikan bahwa atribut pemain sepak bola tidak independen satu sama lain — ada pola korelasi yang kuat dan bermakna.
Variabel baru yang dibuat pada tahap feature engineering terbukti berkontribusi secara substantif dalam PCA:
Goal_Contribution_Potential memiliki
loading tinggi di PC1, mengonfirmasi bahwa kemampuan berkontribusi gol
merupakan bagian inti dari dimensi teknik menyerang.Physical_Dominance memiliki loading
dominan di PC4, menunjukkan bahwa variabel komposit ini berhasil
menangkap dimensi kecepatan dan daya ledak fisik yang tidak sepenuhnya
terwakili oleh variabel tunggal mana pun.Is_Wonderkid memiliki loading yang
lebih moderat, namun secara konsisten berasosiasi dengan PC1 yang tinggi
pada visualisasi distribusi wonderkid.Ini memvalidasi bahwa proses feature engineering yang dilakukan kelompok berhasil membentuk variabel yang substantif dan informatif secara statistik.
Melalui posisi pemain dalam ruang PC1–PC2, empat kuadran gaya main dapat diidentifikasi:
# Visualisasi kuadran gaya main
pca_scores_df %>%
mutate(
# Klasifikasi posisi utama berdasarkan player_positions
Posisi_Utama = case_when(
grepl("ST|CF|LW|RW|LF|RF", player_positions) ~ "Penyerang",
grepl("CAM|LAM|RAM|LM|RM|CM|LCM|RCM", player_positions) ~ "Gelandang",
grepl("CDM|LDM|RDM|LWB|RWB|LB|RB|CB|LCB|RCB", player_positions) ~ "Bek",
TRUE ~ "Lainnya"
)
) %>%
filter(Posisi_Utama != "Lainnya") %>%
ggplot(aes(x = PC1, y = PC2, color = Posisi_Utama)) +
geom_point(alpha = 0.35, size = 1.0) +
stat_ellipse(level = 0.75, linewidth = 1.0) +
scale_color_manual(values = c(
"Penyerang" = "#E63946",
"Gelandang" = "#2A9D8F",
"Bek" = "#264653"
)) +
geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
geom_vline(xintercept = 0, linetype = "dashed", color = "gray50") +
annotate("text", x = 9, y = -7, label = "Penyerang\nSkillful", size = 3.5,
fontface = "bold", color = "#E63946") +
annotate("text", x = 6, y = 6, label = "Gelandang\nBox-to-Box", size = 3.5,
fontface = "bold", color = "#2A9D8F") +
annotate("text", x = -7, y = 6, label = "Bek /\nGelandang Bertahan", size = 3.5,
fontface = "bold", color = "#264653") +
annotate("text", x = -5, y = -6, label = "Pemain\nNilaiannya Rendah", size = 3.5,
fontface = "italic", color = "gray50") +
labs(
title = "Pola Gaya Main Berdasarkan Ruang PC1 vs PC2",
subtitle = "Elips pada tingkat kepercayaan 75% per kelompok posisi",
x = "PC1 – Kemampuan Teknik Menyerang",
y = "PC2 – Orientasi Bertahan",
color = "Posisi Utama"
) +
theme_bw(base_size = 12)
Analisis Pola Gaya Main:
# Statistik rata-rata skor PCA untuk wonderkid vs non-wonderkid
perbandingan_wk <- pca_scores_df %>%
mutate(Kategori = ifelse(Is_Wonderkid == 1, "Wonderkid", "Non-Wonderkid")) %>%
group_by(Kategori) %>%
summarise(
N = n(),
Rata_PC1 = round(mean(PC1), 3),
Rata_PC2 = round(mean(PC2), 3),
Rata_PC3 = round(mean(PC3), 3),
Rata_PC4 = round(mean(PC4), 3),
.groups = "drop"
)
kable(
perbandingan_wk,
col.names = c("Kategori", "Jumlah",
"Rata-rata PC1 (Teknik Menyerang)",
"Rata-rata PC2 (Bertahan)",
"Rata-rata PC3 (Fisik Statis–Dinamis)",
"Rata-rata PC4 (Kecepatan)"),
caption = "Perbandingan Rata-rata Skor PCA: Wonderkid vs Non-Wonderkid",
align = "lrrrrr", # 6 karakter untuk 6 kolom Anda
digits = 3
)
| Kategori | Jumlah | Rata-rata PC1 (Teknik Menyerang) | Rata-rata PC2 (Bertahan) | Rata-rata PC3 (Fisik Statis–Dinamis) | Rata-rata PC4 (Kecepatan) |
|---|---|---|---|---|---|
| Non-Wonderkid | 15668 | -0.072 | 0.009 | -0.030 | -0.004 |
| Wonderkid | 675 | 1.661 | -0.217 | 0.689 | 0.104 |
Wonderkid memiliki rata-rata skor PC1 yang lebih tinggi dibandingkan pemain non-wonderkid, mengindikasikan bahwa pemain muda dengan potensi tinggi pada umumnya sudah unggul dalam dimensi teknik menyerang bahkan pada usia dini. Perbedaan ini bermakna praktis dalam konteks scouting: PC1 dapat dijadikan indikator awal kualitas teknik pemain muda.
Analisis yang telah dilakukan kelompok ini mencakup rangkaian tahapan yang komprehensif terhadap dataset FC 26, mulai dari eksplorasi awal, pembersihan data, rekayasa fitur, seleksi fitur, hingga reduksi dimensi melalui PCA. Berikut adalah kesimpulan akhir yang dapat ditarik:
tabel_kesimpulan <- data.frame(
No = 1:5,
Aspek = c(
"Kualitas Dataset",
"Feature Engineering",
"Feature Selection",
"Reduksi Dimensi (PCA)",
"Pola Wonderkid"
),
Kesimpulan = c(
"Dataset FC 26 (18.405 pemain, 110 variabel) berkualitas baik setelah penghapusan GK dan missing value. Data final untuk PCA mencakup 16.343 pemain lapangan dengan 38 variabel.",
"Tiga variabel baru berhasil dibentuk (Is_Wonderkid, Goal_Contribution_Potential, Physical_Dominance) dan terbukti signifikan secara statistik dalam PCA, khususnya Goal_Contribution_Potential (loading tinggi di PC1) dan Physical_Dominance (loading tinggi di PC4).",
"Filter method mengidentifikasi variabel-variabel redundan (korelasi |r| > 0,80). Random Forest mengonfirmasi variabel dengan kontribusi prediktif terbesar terhadap overall rating. Kombinasi keduanya menghasilkan seleksi fitur yang lebih andal.",
"PCA berhasil meringkas 38 variabel menjadi 4 komponen utama yang menjelaskan >81% varians total. Keempat komponen memiliki makna substantif: Teknik Menyerang (PC1), Kemampuan Bertahan (PC2), Fisik Statis vs. Dinamis (PC3), dan Kecepatan Eksplosif (PC4). Reduksi dimensi ini dinyatakan BERHASIL.",
"Terdapat 675 wonderkid (pemain usia ≤21, potential ≥80). Wonderkid cenderung memiliki skor PC1 di atas rata-rata, mengonfirmasi bahwa kemampuan teknik menyerang merupakan karakteristik utama pemain muda berbakat dalam dataset ini."
)
)
kable(
tabel_kesimpulan,
col.names = c("No.", "Aspek", "Kesimpulan"),
caption = "Kesimpulan Akhir Analisis Multivariat Dataset FC 26",
align = "cll"
)
| No. | Aspek | Kesimpulan |
|---|---|---|
| 1 | Kualitas Dataset | Dataset FC 26 (18.405 pemain, 110 variabel) berkualitas baik setelah penghapusan GK dan missing value. Data final untuk PCA mencakup 16.343 pemain lapangan dengan 38 variabel. |
| 2 | Feature Engineering | Tiga variabel baru berhasil dibentuk (Is_Wonderkid, Goal_Contribution_Potential, Physical_Dominance) dan terbukti signifikan secara statistik dalam PCA, khususnya Goal_Contribution_Potential (loading tinggi di PC1) dan Physical_Dominance (loading tinggi di PC4). |
| 3 | Feature Selection | Filter method mengidentifikasi variabel-variabel redundan (korelasi |r| > 0,80). Random Forest mengonfirmasi variabel dengan kontribusi prediktif terbesar terhadap overall rating. Kombinasi keduanya menghasilkan seleksi fitur yang lebih andal. |
| 4 | Reduksi Dimensi (PCA) | PCA berhasil meringkas 38 variabel menjadi 4 komponen utama yang menjelaskan >81% varians total. Keempat komponen memiliki makna substantif: Teknik Menyerang (PC1), Kemampuan Bertahan (PC2), Fisik Statis vs. Dinamis (PC3), dan Kecepatan Eksplosif (PC4). Reduksi dimensi ini dinyatakan BERHASIL. |
| 5 | Pola Wonderkid | Terdapat 675 wonderkid (pemain usia ≤21, potential ≥80). Wonderkid cenderung memiliki skor PC1 di atas rata-rata, mengonfirmasi bahwa kemampuan teknik menyerang merupakan karakteristik utama pemain muda berbakat dalam dataset ini. |
Hasil analisis ini memiliki sejumlah implikasi praktis bagi pengguna data sepak bola:
Efisiensi Scouting: Daripada mengevaluasi 38 atribut secara manual, empat skor komponen utama (PC1–PC4) dapat digunakan sebagai profil ringkas seorang pemain. Pemain dengan PC1 dan PC4 tinggi adalah calon pemain muda yang eksplosif dan skillful.
Pengelompokan Taktis: Visualisasi biplot PC1 vs PC2 menunjukkan bahwa pemain secara alami mengelompok berdasarkan peran taktisnya, yang dapat mendukung analisis keseimbangan skuad.
Validasi Feature Engineering: Variabel komposit
Goal_Contribution_Potential dan
Physical_Dominance terbukti secara statistik mampu
merangkum dimensi bermakna yang tidak tertangkap sepenuhnya oleh satu
variabel tunggal.
Dasar Analisis Lanjutan: Skor PC1–PC4 yang telah dihasilkan dapat digunakan sebagai input pada analisis klaster (cluster analysis) atau model regresi untuk memprediksi nilai transfer pemain, sebagai langkah analisis multivariat selanjutnya.
Analisis ini memiliki beberapa keterbatasan yang perlu diperhatikan:
Analisis ini diselesaikan menggunakan R dengan paket
tidyverse, factoextra,
randomForest, corrplot, dan
knitr. Dataset: FC 26 Player Dataset (Kaggle, September
2025).