Functions & Loops
Prakticum ~ Week 5
1 Pendahuluan
Tugas Advanced Practicum ini merupakan implementasi dari konsep fungsi dan perulangan (loops) dalam konteks Data Science. Terdapat 8 tugas utama yang harus diselesaikan, mulai dari simulasi data penjualan, Monte Carlo, hingga pembuatan dashboard KPI perusahaan. Semua kode akan menggunakan R dan dipublikasikan ke RPubs.
2 Soal 1 — Dynamic Multi-Formula Function
2.1 Penjelasan
Tugas ini meminta kita membangun sebuah fungsi bernama
compute_formula(x, formula) yang mampu menghitung empat
jenis formula matematika sekaligus, yaitu linear,
quadratic, cubic, dan
exponential. Fungsi ini dilengkapi dengan validasi
input sehingga jika pengguna memasukkan nama formula yang tidak dikenal,
program akan langsung menampilkan pesan error. Nested loop digunakan
untuk menghitung semua formula secara efisien, dan hasilnya
divisualisasikan dalam satu grafik interaktif untuk x = 1 sampai 20.
2.2 Langkah-Langkah Pengerjaan
Langkah 1 — Definisi Formula
Setiap formula didefinisikan dalam bentuk fungsi anonim di dalam sebuah list, sehingga mudah dipanggil secara iteratif:
- Linear: \(f(x) = 2x + 1\)
- Quadratic: \(f(x) = x^2 - 3x + 2\)
- Cubic: \(f(x) = x^3 - 2x^2 + x\)
- Exponential: \(f(x) = e^{0.3x}\)
Langkah 2 — Validasi Input
Sebelum menghitung, fungsi memeriksa apakah nama formula yang dimasukkan valid. Jika tidak, fungsi menghentikan eksekusi dengan pesan error yang informatif. Ini penting agar fungsi tidak berjalan dengan data yang salah.
Langkah 3 — Nested Loop & Visualisasi
Loop digunakan untuk mengiterasi setiap nama formula dalam list dan
menghitung nilainya untuk seluruh vektor x. Hasilnya digabungkan ke
dalam satu data frame, kemudian diubah ke format panjang (long format)
agar dapat divisualisasikan dalam satu grafik menggunakan
plotly.
library(plotly)
library(reshape2)
# Fungsi utama dengan validasi dan nested loop
compute_formula <- function(x, formula = "all") {
valid <- c("linear", "quadratic", "cubic", "exponential", "all")
if (!(formula %in% valid))
stop(paste("Formula tidak valid! Pilih:", paste(valid, collapse = ", ")))
# Definisi semua formula dalam list
formulas <- list(
linear = function(x) 2 * x + 1,
quadratic = function(x) x^2 - 3 * x + 2,
cubic = function(x) x^3 - 2 * x^2 + x,
exponential = function(x) exp(0.3 * x)
)
hasil <- data.frame(x = x)
# Loop untuk hitung semua formula sekaligus
target <- if (formula == "all") names(formulas) else formula
for (nm in target) {
hasil[[nm]] <- round(formulas[[nm]](x), 2)
}
return(hasil)
}
# Hitung untuk x = 1:20
df_formula <- compute_formula(1:20, formula = "all")
head(df_formula, 5)# Ubah ke format panjang untuk plotting
df_long <- melt(df_formula, id.vars = "x",
variable.name = "Formula", value.name = "Nilai")
warna <- c("linear" = "#2196F3", "quadratic" = "#4CAF50",
"cubic" = "#FF9800", "exponential" = "#E91E63")
fig <- plot_ly()
for (fm in unique(df_long$Formula)) {
d <- df_long[df_long$Formula == fm, ]
fig <- fig %>%
add_trace(x = d$x, y = d$Nilai, type = "scatter", mode = "lines+markers",
name = fm,
line = list(color = warna[fm], width = 2.5),
marker = list(color = warna[fm], size = 6),
text = paste0("<b>Formula:</b> ", fm,
"<br><b>x =</b> ", d$x,
"<br><b>f(x) =</b> ", d$Nilai),
hoverinfo = "text")
}
fig %>% layout(
title = list(text = "<b>Perbandingan Empat Formula Matematika (x = 1 sampai 20)</b>",
x = 0.5, font = list(size = 15)),
xaxis = list(title = "<b>Nilai x</b>", dtick = 2),
yaxis = list(title = "<b>f(x)</b>"),
legend = list(title = list(text = "<b>Formula</b>"), orientation = "h",
x = 0.5, xanchor = "center", y = -0.15),
hovermode = "closest",
plot_bgcolor = "white",
paper_bgcolor = "white",
margin = list(l = 60, r = 40, t = 70, b = 80)
)2.2.1 Interpretasi
Grafik memperlihatkan karakteristik pertumbuhan yang sangat berbeda dari keempat formula. Formula exponential tumbuh paling cepat — nilainya meledak secara drastis mendekati x = 20. Formula cubic juga tumbuh cepat namun masih jauh di bawah eksponensial. Formula quadratic membentuk parabola yang naik secara bertahap, sementara formula linear tumbuh paling lambat dan konsisten. Validasi input memastikan pengguna mendapat feedback langsung jika memasukkan nama formula yang salah.
3 Soal 2 — Nested Simulation: Multi-Sales & Discounts
3.1 Penjelasan
Soal ini meminta kita mensimulasikan data penjualan harian
menggunakan fungsi simulate_sales(n_salesperson, days).
Struktur fungsi menggunakan nested loop — loop luar
mengiterasi setiap salesperson, sedangkan loop dalam mengiterasi setiap
hari. Di dalam loop tersebut, terdapat nested function
untuk menghitung diskon kondisional berdasarkan nilai penjualan, serta
fungsi terpisah untuk menghitung penjualan kumulatif. Pendekatan ini
mencerminkan cara kerja laporan penjualan nyata di sebuah
perusahaan.
3.2 Langkah-Langkah Pengerjaan
Langkah 1 — Nested Function: Hitung Diskon
Aturan diskon bersifat kondisional berdasarkan
sales_amount:
- Penjualan ≥ 900 → diskon 20%
- Penjualan 600–899 → diskon 15%
- Penjualan 300–599 → diskon 10%
- Penjualan < 300 → diskon 5%
Langkah 2 — Nested Loop
Loop luar berjalan untuk setiap salesperson (1 sampai
n_salesperson). Di dalamnya, loop dalam berjalan untuk
setiap hari (1 sampai days). Pada setiap iterasi, penjualan
acak dibangkitkan, diskon dihitung, dan nilai kumulatif diperbarui
secara bertahap.
Langkah 3 — Summary & Visualisasi
Setelah semua iterasi selesai, data dirangkum per salesperson
menggunakan dplyr. Plot kumulatif menunjukkan tren
pertumbuhan penjualan bersih masing-masing salesperson dari hari ke
hari, sehingga manajemen dapat membandingkan performa dengan mudah.
library(dplyr)
library(knitr)
set.seed(42)
simulate_sales <- function(n_salesperson, days) {
# Nested function 1: hitung diskon
hitung_diskon <- function(amount) {
if (amount >= 900) return(0.20)
else if (amount >= 600) return(0.15)
else if (amount >= 300) return(0.10)
else return(0.05)
}
hasil <- data.frame()
# Nested loop: salesperson × hari
for (sp in 1:n_salesperson) {
kumulatif <- 0
for (d in 1:days) {
amount <- round(runif(1, 100, 1000), 0)
diskon <- hitung_diskon(amount)
net <- round(amount * (1 - diskon), 2)
kumulatif <- round(kumulatif + net, 2)
hasil <- rbind(hasil, data.frame(
sales_id = paste0("SP-", sp),
day = d,
sales_amount = amount,
discount_rate = paste0(diskon * 100, "%"),
net_sales = net,
cumulative = kumulatif
))
}
}
return(hasil)
}
df_sales <- simulate_sales(n_salesperson = 5, days = 10)
head(df_sales, 10)# Summary per salesperson
summary_sales <- df_sales %>%
group_by(sales_id) %>%
summarise(
Total_Penjualan = sum(sales_amount),
Total_Net = sum(net_sales),
Kumulatif_Akhir = max(cumulative),
.groups = "drop"
)
kable(summary_sales, caption = "Ringkasan Penjualan per Salesperson")| sales_id | Total_Penjualan | Total_Net | Kumulatif_Akhir |
|---|---|---|---|
| SP-1 | 6726 | 5692.15 | 5692.15 |
| SP-2 | 6309 | 5334.15 | 5334.15 |
| SP-3 | 6538 | 5484.45 | 5484.45 |
| SP-4 | 5675 | 4850.20 | 4850.20 |
| SP-5 | 6701 | 5634.80 | 5634.80 |
# Plot kumulatif interaktif
warna_sp <- c("#2196F3","#4CAF50","#FF9800","#E91E63","#9C27B0")
fig2 <- plot_ly()
for (i in seq_along(unique(df_sales$sales_id))) {
sp <- unique(df_sales$sales_id)[i]
d <- df_sales[df_sales$sales_id == sp, ]
fig2 <- fig2 %>%
add_trace(x = d$day, y = d$cumulative, type = "scatter",
mode = "lines+markers", name = sp,
line = list(color = warna_sp[i], width = 2.5),
marker = list(color = warna_sp[i], size = 7),
text = paste0("<b>", sp, "</b>",
"<br>Hari ke-", d$day,
"<br>Kumulatif: Rp ", format(d$cumulative, big.mark = ",")),
hoverinfo = "text")
}
fig2 %>% layout(
title = list(text = "<b>Penjualan Kumulatif per Salesperson (10 Hari)</b>",
x = 0.5, font = list(size = 15)),
xaxis = list(title = "<b>Hari ke-</b>", dtick = 1),
yaxis = list(title = "<b>Total Kumulatif (Rp)</b>"),
legend = list(title = list(text = "<b>Salesperson</b>"),
orientation = "h", x = 0.5, xanchor = "center", y = -0.18),
hovermode = "closest",
plot_bgcolor = "white",
paper_bgcolor = "white",
margin = list(l = 60, r = 40, t = 70, b = 90)
)3.2.1 Interpretasi
Hasil simulasi memperlihatkan 5 salesperson selama 10 hari dengan aturan diskon yang berbeda-beda tergantung nilai transaksi. Plot kumulatif menunjukkan bahwa pertumbuhan masing-masing salesperson relatif konsisten, namun ada perbedaan total akhir yang cukup signifikan. Salesperson dengan tren garis paling curam adalah yang paling produktif. Informasi ini sangat berguna bagi manajemen untuk menentukan target bonus dan merancang strategi insentif penjualan.
4 Soal 3 — Multi-Level Performance Categorization
4.1 Penjelasan
Fungsi categorize_performance(sales_amount) bertugas
mengklasifikasikan setiap nilai penjualan ke dalam 5 level kinerja:
Excellent, Very Good,
Good, Average, dan
Poor. Fungsi ini menggunakan loop untuk memproses
setiap elemen dalam vektor satu per satu, menerapkan logika kondisional
berdasarkan ambang batas yang telah ditentukan. Setelah klasifikasi
selesai, distribusi kategori dihitung persentasenya dan divisualisasikan
dalam dua jenis grafik untuk memudahkan analisis.
4.2 Langkah-Langkah Pengerjaan
Langkah 1 — Definisi Ambang Batas
Batas nilai untuk setiap kategori:
- ≥ 850 → Excellent
- 650–849 → Very Good
- 450–649 → Good
- 250–449 → Average
- < 250 → Poor
Langkah 2 — Loop Kategorisasi
Fungsi menggunakan seq_along() untuk mengiterasi setiap
elemen vektor. Di dalam setiap iterasi, nilai dibandingkan dengan ambang
batas menggunakan if-else if-else untuk menentukan
kategorinya.
Langkah 3 — Hitung Persentase & Visualisasi
Setelah seluruh data dikategorikan, persentase dihitung dengan membagi jumlah tiap kategori dengan total data. Hasil divisualisasikan dengan bar chart untuk perbandingan antar kategori dan pie chart untuk gambaran proporsi keseluruhan.
categorize_performance <- function(sales_amount) {
kategori <- character(length(sales_amount))
# Loop melalui setiap elemen vektor
for (i in seq_along(sales_amount)) {
val <- sales_amount[i]
if (val >= 850) kategori[i] <- "Excellent"
else if (val >= 650) kategori[i] <- "Very Good"
else if (val >= 450) kategori[i] <- "Good"
else if (val >= 250) kategori[i] <- "Average"
else kategori[i] <- "Poor"
}
return(kategori)
}
# Generate 200 data penjualan acak
set.seed(123)
sales_data <- round(runif(200, 50, 1000), 0)
hasil_kategori <- categorize_performance(sales_data)
# Hitung distribusi dan persentase
level_order <- c("Poor","Average","Good","Very Good","Excellent")
df_kat <- as.data.frame(table(hasil_kategori))
names(df_kat) <- c("Kategori","Jumlah")
df_kat$Persentase <- round(df_kat$Jumlah / sum(df_kat$Jumlah) * 100, 1)
df_kat$Kategori <- factor(df_kat$Kategori, levels = level_order)
df_kat <- df_kat[order(df_kat$Kategori), ]
kable(df_kat, caption = "Distribusi Kategori Kinerja dari 200 Data Penjualan")| Kategori | Jumlah | Persentase | |
|---|---|---|---|
| 4 | Poor | 32 | 16.0 |
| 1 | Average | 54 | 27.0 |
| 3 | Good | 43 | 21.5 |
| 5 | Very Good | 39 | 19.5 |
| 2 | Excellent | 32 | 16.0 |
warna_kat <- c("Poor" = "#EF5350","Average" = "#FF9800",
"Good" = "#FFCA28","Very Good" = "#66BB6A","Excellent" = "#42A5F5")
# Bar Chart Interaktif
fig_bar <- plot_ly(df_kat, x = ~Kategori, y = ~Jumlah,
type = "bar",
marker = list(color = warna_kat[as.character(df_kat$Kategori)],
line = list(color = "white", width = 1.5)),
text = ~paste0(Persentase, "%\n(n = ", Jumlah, ")"),
textposition = "outside",
hovertext = ~paste0("<b>Kategori: </b>", Kategori,
"<br><b>Jumlah: </b>", Jumlah, " orang",
"<br><b>Persentase: </b>", Persentase, "%"),
hoverinfo = "text") %>%
layout(title = list(text = "<b>Distribusi Kategori Kinerja — Bar Chart</b>",
x = 0.5, font = list(size = 14)),
xaxis = list(title = "<b>Kategori Kinerja</b>",
categoryorder = "array",
categoryarray = level_order),
yaxis = list(title = "<b>Jumlah Karyawan</b>"),
plot_bgcolor = "white",
paper_bgcolor = "white",
margin = list(l = 50, r = 30, t = 60, b = 60),
showlegend = FALSE)
# Pie Chart Interaktif
fig_pie <- plot_ly(df_kat, labels = ~Kategori, values = ~Jumlah,
type = "pie",
marker = list(colors = warna_kat[as.character(df_kat$Kategori)],
line = list(color = "white", width = 2)),
textinfo = "label+percent",
hovertext = ~paste0("<b>", Kategori, "</b>",
"<br>Jumlah: ", Jumlah, " orang",
"<br>Persentase: ", Persentase, "%"),
hoverinfo = "text",
textfont = list(size = 13)) %>%
layout(title = list(text = "<b>Proporsi Kategori Kinerja — Pie Chart</b>",
x = 0.5, font = list(size = 14)),
plot_bgcolor = "white",
paper_bgcolor = "white",
legend = list(orientation = "v", x = 1.0, y = 0.5),
margin = list(l = 20, r = 20, t = 60, b = 20))
fig_bar4.2.1 Interpretasi
Dari 200 data penjualan yang dibangkitkan secara acak, distribusi kategori kinerja cukup merata karena data menggunakan distribusi uniform. Bar chart memudahkan perbandingan jumlah absolut antar kategori, sementara pie chart memberikan gambaran proporsi keseluruhan secara sekilas. Pada data nyata, distribusi ini dapat digunakan manajemen untuk menilai komposisi tim dan merancang program pengembangan karyawan secara lebih terarah.
5 Soal 4 — Multi-Company Dataset Simulation
5.1 Penjelasan
Fungsi generate_company_data(n_company, n_employees)
mensimulasikan dataset lengkap multi-perusahaan menggunakan
nested loop — loop luar untuk setiap perusahaan dan
loop dalam untuk setiap karyawan. Di dalam loop tersebut, logika
kondisional menandai karyawan sebagai top performer
apabila KPI_score > 90. Setelah dataset terbentuk,
summary per perusahaan dihitung dan divisualisasikan untuk mendukung
pengambilan keputusan manajerial.
5.2 Langkah-Langkah Pengerjaan
Langkah 1 — Nested Loop
Loop luar: for (co in 1:n_company) mengiterasi setiap
perusahaan.
Loop dalam: for (emp in 1:n_employees) mengiterasi setiap
karyawan di dalamnya.
Pendekatan ini memastikan setiap kombinasi perusahaan–karyawan diproses
secara mandiri.
Langkah 2 — Conditional Logic: Top Performer
Setiap karyawan mendapat atribut top_performer
berdasarkan kondisi:
KPI_score > 90 → "Ya", selain itu
"Tidak".
Kondisi ini penting untuk program reward dan identifikasi talenta
terbaik.
Langkah 3 — Summary & Visualisasi
Setelah dataset lengkap terbentuk, data dirangkum menggunakan
dplyr untuk menghasilkan rata-rata gaji, rata-rata
performa, KPI maksimum, dan jumlah top performer per perusahaan.
Hasilnya divisualisasikan dalam dua grafik batang yang mudah
dipahami.
set.seed(99)
generate_company_data <- function(n_company, n_employees) {
dept <- c("Finance","HR","IT","Marketing","Operations")
hasil <- data.frame()
# Nested loop: perusahaan × karyawan
for (co in 1:n_company) {
for (emp in 1:n_employees) {
salary <- round(runif(1, 4000, 15000), 0)
department <- sample(dept, 1)
perf <- round(runif(1, 50, 100), 1)
kpi <- round(runif(1, 50, 100), 1)
top <- ifelse(kpi > 90, "Ya", "Tidak") # conditional logic
hasil <- rbind(hasil, data.frame(
company_id = paste0("Perusahaan-", co),
employee_id = paste0("E", co, "_", emp),
salary = salary,
department = department,
performance_score = perf,
KPI_score = kpi,
top_performer = top
))
}
}
return(hasil)
}
# Jalankan: 4 perusahaan × 30 karyawan
df_company <- generate_company_data(n_company = 4, n_employees = 30)
# Summary per perusahaan
summary_co <- df_company %>%
group_by(company_id) %>%
summarise(
Avg_Salary = round(mean(salary), 0),
Avg_Performance = round(mean(performance_score), 2),
Max_KPI = max(KPI_score),
Top_Performers = sum(top_performer == "Ya"),
.groups = "drop"
)
kable(summary_co, caption = "Summary per Perusahaan (4 Perusahaan × 30 Karyawan)")| company_id | Avg_Salary | Avg_Performance | Max_KPI | Top_Performers |
|---|---|---|---|---|
| Perusahaan-1 | 8554 | 71.89 | 99.8 | 9 |
| Perusahaan-2 | 9846 | 75.00 | 98.4 | 8 |
| Perusahaan-3 | 9259 | 74.40 | 99.3 | 7 |
| Perusahaan-4 | 10272 | 75.21 | 99.3 | 2 |
warna_co <- c("#2196F3","#4CAF50","#FF9800","#E91E63")
# Plot 1: Rata-rata gaji
fig_gaji <- plot_ly(summary_co, x = ~company_id, y = ~Avg_Salary,
type = "bar",
marker = list(color = warna_co,
line = list(color = "white", width = 1.5)),
text = ~paste0("Rp ", format(Avg_Salary, big.mark = ",")),
textposition = "outside",
hovertext = ~paste0("<b>", company_id, "</b>",
"<br>Avg Salary: Rp ",
format(Avg_Salary, big.mark = ",")),
hoverinfo = "text") %>%
layout(title = list(text = "<b>Rata-rata Gaji per Perusahaan</b>",
x = 0.5, font = list(size = 13)),
xaxis = list(title = ""), yaxis = list(title = "<b>Gaji (Rp)</b>"),
plot_bgcolor = "white", paper_bgcolor = "white",
showlegend = FALSE, margin = list(t = 60, b = 50))
# Plot 2: Jumlah top performer
fig_top <- plot_ly(summary_co, x = ~company_id, y = ~Top_Performers,
type = "bar",
marker = list(color = warna_co,
line = list(color = "white", width = 1.5)),
text = ~paste0(Top_Performers, " orang"),
textposition = "outside",
hovertext = ~paste0("<b>", company_id, "</b>",
"<br>Top Performer (KPI > 90): ",
Top_Performers, " orang"),
hoverinfo = "text") %>%
layout(title = list(text = "<b>Jumlah Top Performer (KPI > 90)</b>",
x = 0.5, font = list(size = 13)),
xaxis = list(title = ""), yaxis = list(title = "<b>Jumlah Karyawan</b>"),
plot_bgcolor = "white", paper_bgcolor = "white",
showlegend = FALSE, margin = list(t = 60, b = 50))
fig_gaji5.2.1 Interpretasi
Dataset berhasil dibuat untuk 4 perusahaan dengan total 120 karyawan. Masing-masing perusahaan memiliki profil yang berbeda karena data dibangkitkan secara acak. Grafik gaji rata-rata memperlihatkan perbedaan kompensasi antar perusahaan yang dapat menjadi bahan evaluasi kebijakan penggajian. Grafik top performer menunjukkan distribusi talenta terbaik — perusahaan dengan top performer terbanyak memiliki modal sumber daya manusia yang lebih kuat untuk bersaing.
6 Soal 5 — Monte Carlo Simulation: Pi & Probability
6.1 Penjelasan
Simulasi Monte Carlo adalah metode statistik yang menggunakan titik acak untuk memperkirakan nilai suatu besaran matematis. Pada soal ini, kita memperkirakan nilai π (pi) dengan cara melempar titik acak ke dalam kotak 2×2. Titik yang jatuh di dalam lingkaran satuan (jarak dari pusat ≤ 1) dihitung, lalu rasionya terhadap total titik digunakan untuk mengestimasi π. Selain itu, kita juga menghitung probabilitas titik jatuh dalam sub-kotak [0, 0.5] × [0, 0.5] dan membandingkannya dengan nilai teoritis.
6.2 Langkah-Langkah Pengerjaan
Langkah 1 — Bangkitkan Titik Acak
Sebanyak n_points titik dibangkitkan secara acak pada
koordinat (x, y) dalam rentang [−1, 1]. Setiap titik mewakili satu
“lemparan” dalam simulasi.
Langkah 2 — Cek Kondisi dengan Loop
Loop mengecek setiap titik: apakah \(x^2 +
y^2 \leq 1\) (dalam lingkaran) dan apakah \(0 \leq x \leq 0.5\), \(0 \leq y \leq 0.5\) (dalam sub-kotak).
Hasil dicatat sebagai TRUE atau FALSE.
Langkah 3 — Estimasi π & Probabilitas
\[\hat{\pi} = 4 \times \frac{\text{titik dalam lingkaran}}{n}\]
Probabilitas sub-kotak teoritis: \[P = \frac{0.5 \times 0.5}{2 \times 2} = \frac{0.25}{4} = 0.0625\]
set.seed(2024)
monte_carlo_pi <- function(n_points) {
x <- runif(n_points, -1, 1)
y <- runif(n_points, -1, 1)
dalam_lingkaran <- logical(n_points)
dalam_subkotak <- logical(n_points)
# Loop untuk cek setiap titik
for (i in 1:n_points) {
dalam_lingkaran[i] <- (x[i]^2 + y[i]^2) <= 1
dalam_subkotak[i] <- (x[i] >= 0 & x[i] <= 0.5 &
y[i] >= 0 & y[i] <= 0.5)
}
list(
pi_estimasi = round(4 * sum(dalam_lingkaran) / n_points, 6),
prob_subkotak = round(sum(dalam_subkotak) / n_points, 4),
df_plot = data.frame(
x = x, y = y,
status = ifelse(dalam_lingkaran, "Dalam Lingkaran", "Luar Lingkaran")
)
)
}
hasil_mc <- monte_carlo_pi(5000)
cat("=== Hasil Monte Carlo Simulation (n = 5.000 titik) ===\n")## === Hasil Monte Carlo Simulation (n = 5.000 titik) ===
## Estimasi π : 3.176
## Nilai π sebenarnya : 3.141593
## Selisih : 0.034407
## Prob. sub-kotak : 0.0626 (teoritis: 0.0625)
# Ambil 2000 titik untuk plot agar tidak terlalu berat
df_plot <- hasil_mc$df_plot[sample(nrow(hasil_mc$df_plot), 2000), ]
fig_mc <- plot_ly(df_plot, x = ~x, y = ~y, color = ~status,
colors = c("Dalam Lingkaran" = "#4CAF50",
"Luar Lingkaran" = "#EF5350"),
type = "scatter", mode = "markers",
marker = list(size = 3, opacity = 0.5),
text = ~paste0("<b>Status:</b> ", status,
"<br>x = ", round(x, 3),
"<br>y = ", round(y, 3)),
hoverinfo = "text") %>%
layout(
title = list(
text = paste0("<b>Monte Carlo — Estimasi π ≈ ",
hasil_mc$pi_estimasi, "</b>"),
x = 0.5, font = list(size = 14)),
xaxis = list(title = "<b>x</b>", range = c(-1.1, 1.1), dtick = 0.5,
zeroline = TRUE, zerolinecolor = "#888"),
yaxis = list(title = "<b>y</b>", range = c(-1.1, 1.1), dtick = 0.5,
zeroline = TRUE, zerolinecolor = "#888",
scaleanchor = "x", scaleratio = 1),
legend = list(title = list(text = "<b>Status Titik</b>"),
orientation = "h", x = 0.5, xanchor = "center", y = -0.18),
annotations = list(
list(x = 0.25, y = 0.55, text = "<b>Sub-kotak</b>",
showarrow = FALSE, font = list(size = 12, color = "#7B1FA2")),
list(x = 0.25, y = -1.0,
text = paste0("n = 5.000 | π ≈ ", hasil_mc$pi_estimasi,
" | Prob sub-kotak = ", hasil_mc$prob_subkotak),
showarrow = FALSE, font = list(size = 11, color = "#555"))
),
shapes = list(
# Lingkaran
list(type = "circle", x0 = -1, y0 = -1, x1 = 1, y1 = 1,
line = list(color = "#1565C0", width = 2.5)),
# Sub-kotak
list(type = "rect", x0 = 0, y0 = 0, x1 = 0.5, y1 = 0.5,
line = list(color = "#7B1FA2", width = 2, dash = "dash"))
),
plot_bgcolor = "white",
paper_bgcolor = "white",
margin = list(l = 60, r = 40, t = 60, b = 90)
)
fig_mc6.2.1 Interpretasi
Dengan 5.000 titik acak, estimasi nilai π yang dihasilkan sangat mendekati nilai sebenarnya (3.14159…). Titik hijau mewakili titik yang jatuh di dalam lingkaran, sedangkan titik merah berada di luar. Semakin banyak titik yang digunakan, semakin akurat estimasi π-nya — ini adalah prinsip utama metode Monte Carlo. Sub-kotak berwarna ungu menunjukkan area [0, 0.5] × [0, 0.5] dengan probabilitas teoritis 0.0625, dan hasil simulasi mendekati nilai tersebut dengan cukup baik.
7 Soal 6 — Advanced Data Transformation & Feature Engineering
7.1 Penjelasan
Pada soal ini kita membangun dua fungsi transformasi data:
normalize_columns(df) untuk normalisasi
min-max yang mengubah semua nilai numerik ke rentang
[0, 1], dan z_score(df) untuk standardisasi yang
menghasilkan distribusi dengan rata-rata 0 dan standar deviasi 1. Selain
itu, kita menambahkan dua fitur baru pada dataset:
performance_category untuk mengklasifikasikan level
kinerja, dan salary_bracket untuk mengelompokkan karyawan
berdasarkan rentang gaji. Distribusi data sebelum dan sesudah
transformasi kemudian dibandingkan secara visual.
# Fungsi normalisasi min-max (loop-based)
normalize_columns <- function(df) {
df_norm <- df
num_cols <- sapply(df, is.numeric)
for (col in names(df)[num_cols]) {
mn <- min(df[[col]], na.rm = TRUE)
mx <- max(df[[col]], na.rm = TRUE)
df_norm[[col]] <- round((df[[col]] - mn) / (mx - mn), 4)
}
return(df_norm)
}
# Fungsi z-score standardisasi (loop-based)
z_score <- function(df) {
df_z <- df
num_cols <- sapply(df, is.numeric)
for (col in names(df)[num_cols]) {
m <- mean(df[[col]], na.rm = TRUE)
s <- sd(df[[col]], na.rm = TRUE)
df_z[[col]] <- round((df[[col]] - m) / s, 4)
}
return(df_z)
}
# Terapkan ke kolom numerik df_company
df_num <- df_company[, c("salary", "performance_score", "KPI_score")]
df_norm <- normalize_columns(df_num)
df_z <- z_score(df_num)
# Tambah fitur baru
df_company$performance_category <- categorize_performance(df_company$performance_score)
df_company$salary_bracket <- cut(
df_company$salary,
breaks = c(0, 6000, 9000, 12000, Inf),
labels = c("Rendah (<6K)","Sedang (6K-9K)","Tinggi (9K-12K)","Sangat Tinggi (>12K)")
)
cat("=== Perbandingan Statistik Salary ===\n")## === Perbandingan Statistik Salary ===
cat("Sebelum → Min:", min(df_num$salary), "| Max:", max(df_num$salary),
"| Mean:", round(mean(df_num$salary), 0), "\n")## Sebelum → Min: 4014 | Max: 14804 | Mean: 9483
cat("Min-Max → Min:", min(df_norm$salary), "| Max:", max(df_norm$salary),
"| Mean:", round(mean(df_norm$salary), 4), "\n")## Min-Max → Min: 0 | Max: 1 | Mean: 0.5069
cat("Z-Score → Min:", round(min(df_z$salary), 3),
"| Max:", round(max(df_z$salary), 3),
"| Mean:", round(mean(df_z$salary), 6), "\n")## Z-Score → Min: -1.647 | Max: 1.602 | Mean: 2e-06
library(reshape2)
# Siapkan data gabungan untuk 3 kondisi
df_plot6 <- data.frame(
Nilai = c(df_num$salary, df_norm$salary, df_z$salary),
Kondisi = rep(c("Sebelum (Asli)", "Min-Max [0,1]", "Z-Score [μ=0]"),
each = nrow(df_num))
)
fig6 <- plot_ly(df_plot6, x = ~Nilai, color = ~Kondisi,
type = "histogram",
nbinsx = 20,
opacity = 0.8,
colors = c("Sebelum (Asli)" = "#2196F3",
"Min-Max [0,1]" = "#4CAF50",
"Z-Score [μ=0]" = "#FF9800")) %>%
layout(
barmode = "overlay",
title = list(text = "<b>Distribusi Salary: Sebelum vs Sesudah Transformasi</b>",
x = 0.5, font = list(size = 14)),
xaxis = list(title = "<b>Nilai</b>"),
yaxis = list(title = "<b>Frekuensi</b>"),
legend = list(title = list(text = "<b>Kondisi</b>"),
orientation = "h", x = 0.5, xanchor = "center", y = -0.18),
plot_bgcolor = "white",
paper_bgcolor = "white",
margin = list(l = 60, r = 40, t = 70, b = 90)
)
fig6# Boxplot KPI berdasarkan salary bracket
fig6b <- plot_ly(df_company, x = ~salary_bracket, y = ~KPI_score,
type = "box",
color = ~salary_bracket,
colors = c("#42A5F5","#66BB6A","#FF9800","#EF5350"),
text = ~paste0("<b>Bracket:</b> ", salary_bracket,
"<br><b>KPI:</b> ", KPI_score),
hoverinfo = "text") %>%
layout(
title = list(text = "<b>Distribusi KPI Score berdasarkan Salary Bracket</b>",
x = 0.5, font = list(size = 14)),
xaxis = list(title = "<b>Salary Bracket</b>"),
yaxis = list(title = "<b>KPI Score</b>"),
legend = list(title = list(text = "<b>Bracket</b>")),
plot_bgcolor = "white",
paper_bgcolor = "white",
margin = list(l = 60, r = 40, t = 70, b = 80),
showlegend = FALSE
)
fig6b7.1.1 Interpretasi
Histogram perbandingan memperlihatkan bahwa ketiga kondisi (asli, min-max, z-score) memiliki bentuk distribusi yang identik — yang berubah hanyalah skala nilainya. Min-max mengompresi semua nilai ke [0, 1], sementara z-score memusatkan data di sekitar 0. Boxplot KPI berdasarkan salary bracket membantu menjawab pertanyaan: apakah karyawan bergaji lebih tinggi cenderung memiliki KPI lebih baik? Jika median kotak bergerak naik seiring naiknya bracket gaji, maka ada korelasi positif yang patut diperhatikan manajemen dalam kebijakan kompensasi.
8 Soal 7 — Mini Project: Company KPI Dashboard
8.1 Penjelasan
Mini project ini mengintegrasikan semua konsep yang telah dipelajari ke dalam sebuah dashboard analitik yang komprehensif. Dataset berskala besar dibuat untuk 6 perusahaan dengan 60 karyawan masing-masing. Loop digunakan untuk mengkategorikan setiap karyawan ke dalam KPI tier (Bronze, Silver, Gold, Platinum). Kemudian serangkaian visualisasi canggih — grouped bar chart, scatter plot dengan regression line, dan analisis departemen — dibangun untuk mendukung pengambilan keputusan berbasis data.
set.seed(777)
df_dash <- generate_company_data(n_company = 6, n_employees = 60)
# Kategorisasi KPI tier dengan loop
kpi_tier <- character(nrow(df_dash))
for (i in 1:nrow(df_dash)) {
kpi <- df_dash$KPI_score[i]
if (kpi >= 90) kpi_tier[i] <- "Platinum"
else if (kpi >= 75) kpi_tier[i] <- "Gold"
else if (kpi >= 60) kpi_tier[i] <- "Silver"
else kpi_tier[i] <- "Bronze"
}
df_dash$KPI_tier <- factor(kpi_tier,
levels = c("Bronze","Silver","Gold","Platinum"))
# Summary per perusahaan
summary_dash <- df_dash %>%
group_by(company_id) %>%
summarise(
Avg_Salary = round(mean(salary), 0),
Avg_KPI = round(mean(KPI_score), 2),
Top_Performers = sum(top_performer == "Ya"),
Total = n(),
.groups = "drop"
) %>%
mutate(Pct_Top = paste0(round(Top_Performers / Total * 100, 1), "%"))
kable(summary_dash, caption = "Dashboard Summary — 6 Perusahaan × 60 Karyawan")| company_id | Avg_Salary | Avg_KPI | Top_Performers | Total | Pct_Top |
|---|---|---|---|---|---|
| Perusahaan-1 | 9567 | 76.17 | 16 | 60 | 26.7% |
| Perusahaan-2 | 9726 | 72.45 | 8 | 60 | 13.3% |
| Perusahaan-3 | 9098 | 73.28 | 10 | 60 | 16.7% |
| Perusahaan-4 | 9927 | 75.09 | 13 | 60 | 21.7% |
| Perusahaan-5 | 8663 | 76.95 | 14 | 60 | 23.3% |
| Perusahaan-6 | 9642 | 77.19 | 12 | 60 | 20% |
# Hitung distribusi KPI tier per perusahaan
tier_df <- df_dash %>%
group_by(company_id, KPI_tier) %>%
summarise(jumlah = n(), .groups = "drop")
warna_tier <- c("Bronze" = "#CD7F32","Silver" = "#A8A9AD",
"Gold" = "#FFD700","Platinum" = "#42A5F5")
fig7a <- plot_ly()
for (tier in c("Bronze","Silver","Gold","Platinum")) {
d <- tier_df[tier_df$KPI_tier == tier, ]
fig7a <- fig7a %>%
add_trace(x = d$company_id, y = d$jumlah,
type = "bar", name = tier,
marker = list(color = warna_tier[tier]),
text = d$jumlah, textposition = "inside",
hovertext = paste0("<b>", d$company_id, "</b>",
"<br>Tier: ", tier,
"<br>Jumlah: ", d$jumlah, " orang"),
hoverinfo = "text")
}
fig7a %>% layout(
barmode = "group",
title = list(text = "<b>Distribusi KPI Tier per Perusahaan</b>",
x = 0.5, font = list(size = 14)),
xaxis = list(title = ""),
yaxis = list(title = "<b>Jumlah Karyawan</b>"),
legend = list(title = list(text = "<b>KPI Tier</b>"),
orientation = "h", x = 0.5, xanchor = "center", y = -0.18),
plot_bgcolor = "white",
paper_bgcolor = "white",
margin = list(l = 60, r = 40, t = 70, b = 90)
)# Scatter plot: salary vs KPI dengan regression line per perusahaan
warna_co6 <- c("#2196F3","#4CAF50","#FF9800","#E91E63","#9C27B0","#00BCD4")
perusahaan_list <- unique(df_dash$company_id)
fig7b <- plot_ly()
for (i in seq_along(perusahaan_list)) {
co <- perusahaan_list[i]
d <- df_dash[df_dash$company_id == co, ]
fit <- lm(KPI_score ~ salary, data = d)
x_rng <- seq(min(d$salary), max(d$salary), length.out = 50)
y_pred <- predict(fit, newdata = data.frame(salary = x_rng))
# Titik scatter
fig7b <- fig7b %>%
add_trace(x = d$salary, y = d$KPI_score,
type = "scatter", mode = "markers",
name = co, legendgroup = co,
marker = list(color = warna_co6[i], size = 6, opacity = 0.7),
text = paste0("<b>", co, "</b>",
"<br>Salary: Rp ", format(d$salary, big.mark = ","),
"<br>KPI: ", d$KPI_score),
hoverinfo = "text", showlegend = TRUE)
# Garis regresi
fig7b <- fig7b %>%
add_trace(x = x_rng, y = y_pred,
type = "scatter", mode = "lines",
name = paste0(co, " (regresi)"), legendgroup = co,
line = list(color = warna_co6[i], width = 2, dash = "dash"),
hoverinfo = "none", showlegend = FALSE)
}
fig7b %>% layout(
title = list(text = "<b>Salary vs KPI Score per Perusahaan (+ Regression Line)</b>",
x = 0.5, font = list(size = 14)),
xaxis = list(title = "<b>Salary (Rp)</b>"),
yaxis = list(title = "<b>KPI Score</b>"),
legend = list(title = list(text = "<b>Perusahaan</b>"),
orientation = "h", x = 0.5, xanchor = "center", y = -0.2),
hovermode = "closest",
plot_bgcolor = "white",
paper_bgcolor = "white",
margin = list(l = 60, r = 40, t = 70, b = 100)
)# Analisis departemen: rata-rata salary
dept_sum <- df_dash %>%
group_by(department) %>%
summarise(Avg_Salary = round(mean(salary), 0),
Jumlah = n(), .groups = "drop") %>%
arrange(desc(Avg_Salary))
fig7c <- plot_ly(dept_sum,
x = ~reorder(department, -Avg_Salary),
y = ~Avg_Salary,
type = "bar",
marker = list(color = "#3F51B5",
line = list(color = "white", width = 1.5)),
text = ~paste0("Rp ", format(Avg_Salary, big.mark = ","),
"\n(", Jumlah, " org)"),
textposition = "outside",
hovertext = ~paste0("<b>", department, "</b>",
"<br>Avg Salary: Rp ",
format(Avg_Salary, big.mark = ","),
"<br>Jumlah: ", Jumlah, " karyawan"),
hoverinfo = "text") %>%
layout(
title = list(text = "<b>Rata-rata Salary per Departemen (Semua Perusahaan)</b>",
x = 0.5, font = list(size = 14)),
xaxis = list(title = "<b>Departemen</b>"),
yaxis = list(title = "<b>Avg Salary (Rp)</b>"),
plot_bgcolor = "white",
paper_bgcolor = "white",
showlegend = FALSE,
margin = list(l = 60, r = 40, t = 70, b = 60)
)
fig7c8.1.1 Interpretasi
Dashboard ini menyajikan analisis tiga lapis untuk 6 perusahaan dengan 360 karyawan total. Grouped bar chart memperlihatkan komposisi KPI tier per perusahaan — semakin banyak Platinum dan Gold, semakin kuat kualitas SDM-nya. Scatter plot dengan regression line menunjukkan arah hubungan antara gaji dan KPI di masing-masing perusahaan: jika garis regresi cenderung naik, berarti karyawan bergaji lebih tinggi umumnya memiliki KPI lebih baik. Analisis departemen membantu manajemen mengidentifikasi divisi mana yang memiliki rata-rata gaji tertinggi dan terendah, yang berguna untuk evaluasi struktur kompensasi secara menyeluruh.
9 Soal 8 — Automated Report Generation (Bonus)
9.1 Penjelasan
Soal bonus ini meminta kita membangun sistem pelaporan otomatis
menggunakan kombinasi fungsi dan loop. Fungsi
generate_report(df, co_id) mengekstrak semua informasi
penting dari satu perusahaan, kemudian sebuah loop mengeksekusinya untuk
seluruh perusahaan dalam dataset secara otomatis. Pendekatan ini
mencerminkan workflow nyata di dunia industri, di mana laporan harus
dibuat secara rutin untuk puluhan atau ratusan entitas sekaligus tanpa
intervensi manual. Laporan akhir dapat diekspor ke CSV untuk keperluan
lebih lanjut.
# Fungsi generate report untuk satu perusahaan
generate_report <- function(df, co_id) {
d <- df[df$company_id == co_id, ]
list(
company = co_id,
total_karyawan = nrow(d),
avg_salary = round(mean(d$salary), 0),
avg_kpi = round(mean(d$KPI_score), 2),
avg_perf = round(mean(d$performance_score), 2),
top_performers = sum(d$top_performer == "Ya"),
dept_terbanyak = names(sort(table(d$department), decreasing = TRUE))[1],
kpi_max = max(d$KPI_score),
kpi_min = min(d$KPI_score)
)
}
# Loop otomatis untuk semua perusahaan
co_list <- unique(df_dash$company_id)
semua_laporan <- list()
for (co in co_list) {
semua_laporan[[co]] <- generate_report(df_dash, co)
}
# Gabungkan ke satu data frame
df_laporan <- do.call(rbind, lapply(semua_laporan, function(x) {
data.frame(
Perusahaan = x$company,
Total_Karyawan = x$total_karyawan,
Avg_Salary = x$avg_salary,
Avg_KPI = x$avg_kpi,
Top_Performers = x$top_performers,
Dept_Terbanyak = x$dept_terbanyak,
KPI_Max = x$kpi_max,
KPI_Min = x$kpi_min,
stringsAsFactors = FALSE
)
}))
kable(df_laporan, caption = "Laporan Otomatis — 6 Perusahaan (Auto-Generated)")| Perusahaan | Total_Karyawan | Avg_Salary | Avg_KPI | Top_Performers | Dept_Terbanyak | KPI_Max | KPI_Min | |
|---|---|---|---|---|---|---|---|---|
| Perusahaan-1 | Perusahaan-1 | 60 | 9567 | 76.17 | 16 | Operations | 99.8 | 50.5 |
| Perusahaan-2 | Perusahaan-2 | 60 | 9726 | 72.45 | 8 | HR | 99.2 | 50.6 |
| Perusahaan-3 | Perusahaan-3 | 60 | 9098 | 73.28 | 10 | Operations | 99.6 | 50.4 |
| Perusahaan-4 | Perusahaan-4 | 60 | 9927 | 75.09 | 13 | Marketing | 98.0 | 50.8 |
| Perusahaan-5 | Perusahaan-5 | 60 | 8663 | 76.95 | 14 | HR | 98.5 | 50.4 |
| Perusahaan-6 | Perusahaan-6 | 60 | 9642 | 77.19 | 12 | HR | 99.8 | 51.6 |
# Visualisasi KPI Max vs Min vs Average per perusahaan
df_kpi_vis <- df_laporan[, c("Perusahaan","KPI_Max","KPI_Min","Avg_KPI")]
fig8 <- plot_ly()
# Area antara min dan max (shading)
for (i in 1:nrow(df_kpi_vis)) {
fig8 <- fig8 %>%
add_trace(x = c(df_kpi_vis$Perusahaan[i], df_kpi_vis$Perusahaan[i]),
y = c(df_kpi_vis$KPI_Min[i], df_kpi_vis$KPI_Max[i]),
type = "scatter", mode = "lines",
line = list(color = "#B0BEC5", width = 8),
hoverinfo = "none", showlegend = FALSE)
}
# KPI Max
fig8 <- fig8 %>%
add_trace(x = df_kpi_vis$Perusahaan, y = df_kpi_vis$KPI_Max,
type = "scatter", mode = "lines+markers",
name = "KPI Tertinggi",
line = list(color = "#4CAF50", width = 2.5),
marker = list(color = "#4CAF50", size = 10, symbol = "triangle-up"),
text = paste0("<b>KPI Tertinggi</b>: ", df_kpi_vis$KPI_Max),
hoverinfo = "text")
# KPI Min
fig8 <- fig8 %>%
add_trace(x = df_kpi_vis$Perusahaan, y = df_kpi_vis$KPI_Min,
type = "scatter", mode = "lines+markers",
name = "KPI Terendah",
line = list(color = "#EF5350", width = 2.5),
marker = list(color = "#EF5350", size = 10, symbol = "triangle-down"),
text = paste0("<b>KPI Terendah</b>: ", df_kpi_vis$KPI_Min),
hoverinfo = "text")
# KPI Average
fig8 <- fig8 %>%
add_trace(x = df_kpi_vis$Perusahaan, y = df_kpi_vis$Avg_KPI,
type = "scatter", mode = "lines+markers",
name = "KPI Rata-rata",
line = list(color = "#2196F3", width = 2.5, dash = "dot"),
marker = list(color = "#2196F3", size = 9, symbol = "diamond"),
text = paste0("<b>KPI Rata-rata</b>: ", df_kpi_vis$Avg_KPI),
hoverinfo = "text")
fig8 %>% layout(
title = list(text = "<b>Rentang KPI Score per Perusahaan — Laporan Otomatis</b>",
x = 0.5, font = list(size = 14)),
xaxis = list(title = "<b>Perusahaan</b>"),
yaxis = list(title = "<b>KPI Score</b>", range = c(45, 105)),
legend = list(title = list(text = "<b>Metrik</b>"),
orientation = "h", x = 0.5, xanchor = "center", y = -0.18),
hovermode = "closest",
plot_bgcolor = "white",
paper_bgcolor = "white",
margin = list(l = 60, r = 40, t = 70, b = 90)
)# Ekspor laporan ke CSV
write.csv(df_laporan, "laporan_otomatis_perusahaan.csv", row.names = FALSE)
cat("✅ File 'laporan_otomatis_perusahaan.csv' berhasil diekspor!\n\n")## ✅ File 'laporan_otomatis_perusahaan.csv' berhasil diekspor!
## === Ringkasan Eksekusi Automated Report ===
## Total perusahaan diproses : 6
## Total karyawan seluruh co. : 360
## Rata-rata top performer/co.: 12.2 orang
cat("Avg KPI tertinggi (co.) :", df_laporan$Perusahaan[which.max(df_laporan$Avg_KPI)],
"→", max(df_laporan$Avg_KPI), "\n")## Avg KPI tertinggi (co.) : Perusahaan-6 → 77.19
cat("Avg KPI terendah (co.) :", df_laporan$Perusahaan[which.min(df_laporan$Avg_KPI)],
"→", min(df_laporan$Avg_KPI), "\n")## Avg KPI terendah (co.) : Perusahaan-2 → 72.45
9.1.1 Interpretasi
Fungsi generate_report berhasil mengotomasi proses
pelaporan — cukup satu fungsi yang dipanggil dalam satu loop, dan
laporan untuk seluruh 6 perusahaan langsung tersedia tanpa perlu menulis
kode berulang. Visualisasi KPI range memperlihatkan kesenjangan antara
karyawan terbaik dan terburuk di setiap perusahaan: semakin sempit
rentang antara segitiga hijau (KPI max) dan merah (KPI min), semakin
merata kualitas SDM perusahaan tersebut. Laporan CSV yang diekspor dapat
langsung dibuka di Excel atau diolah lebih lanjut menggunakan tools BI
seperti Tableau atau Power BI.
10 Kesimpulan
Rangkuman Konsep yang Dikuasai
Dari 8 soal advanced practicum ini, kita telah berhasil mendemonstrasikan penguasaan konsep pemrograman data science secara menyeluruh:
- Dynamic Multi-Formula — Validasi input dan komputasi multi-formula dalam satu fungsi modular.
- Nested Simulation — Nested loop dengan diskon kondisional dan akumulasi penjualan harian.
- Performance Categorization — Loop berbasis vektor untuk klasifikasi 5 level kinerja beserta visualisasi distribusi.
- Multi-Company Simulation — Nested loop antar perusahaan dan karyawan dengan penandaan top performer.
- Monte Carlo — Estimasi π dan probabilitas menggunakan ribuan titik acak dengan loop.
- Data Transformation — Normalisasi dan standardisasi berbasis loop, dilengkapi feature engineering.
- KPI Dashboard — Analisis komprehensif multi-perusahaan dengan visualisasi lanjutan dan regression line.
- Automated Report — Otomasi laporan per perusahaan menggunakan fungsi dan loop, dengan ekspor CSV.
Pelajaran Utama
Kombinasi fungsi, loop, dan logika kondisional terbukti menjadi fondasi yang sangat kuat dalam membangun workflow data science yang efisien. Kode yang modular — artinya setiap tugas dikerjakan oleh fungsinya sendiri — membuat program lebih mudah dipahami, diuji, dan dikembangkan di masa mendatang. Inilah prinsip yang diterapkan oleh para data scientist profesional dalam proyek nyata sehari-hari.
11 Daftar Referensi
- Biztech Academy. (2024). Roadmap Belajar Data Science untuk Pemula. Biztech Academy. https://biztechacademy.id/roadmap-belajar-data-science-untuk-pemula/
- Nurcahyo, A. (2020). Algoritma Pemrograman 7A: Nested Looping. Scribd. https://www.scribd.com/presentation/682000605/Alpro-7A-Nested-Looping
- Ladal Institute. (2023). Working with R: A Comprehensive Tutorial. Ladal Institute. https://ladal.edu.au/tutorials/workingwithr/workingwithr.html
- Kassambara, A. (2020). Estimating Pi Using Monte Carlo Simulation in R. Towards Data Science. https://towardsdatascience.com/estimating-pi-using-monte-carlo-simulation-in-r-91d1f32406af/
- Government Arts College for Women. (2021). Programming in R - Unit 5: Loops and Functions. GACBE. https://gacbe.ac.in/pdf/ematerial/18MIT22C-U5.pdf
- DataCamp. (2023). Tutorial on Loops in R. DataCamp. https://www.datacamp.com/tutorial/tutorial-on-loops-in-r