Laporan ini menyajikan analisis pertumbuhan berat ayam pada dataset ChickWeight menggunakan model non-linear logistik dan membandingkannya dengan regresi linear pada data yang sama. Kami melaporkan ukuran goodness-of-fit berupa SSE (Sum of Squared Errors) dan R², menampilkan visualisasi hasil pemodelan, dan mendiskusikan mengapa model non-linear lebih sesuai untuk fenomena pertumbuhan biologis yang umumnya bersifat sigmoidal.
Selain itu, laporan ini juga memuat simulasi pertumbuhan
eksponensial (misalnya analogi pertumbuhan bakteri), estimasi
parameternya dengan nls(), serta interpretasi hasilnya.
Model logistik (parameterisasi
SSlogis)
\[
f(t;\,\text{Asym}, x_{\text{mid}}, \text{scal}) \;=\;
\frac{\text{Asym}}{1 + \exp\left(\frac{x_{\text{mid}} -
t}{\text{scal}}\right)}
\] dengan:
Regresi linear
\[
y_i \;=\; \beta_0 + \beta_1 t_i + \varepsilon_i,\quad \varepsilon_i \sim
\mathcal{N}(0,\sigma^2)
\]
Ukuran Goodness-of-Fit
\[
\text{SSE} = \sum_{i=1}^{n} (y_i - \hat{y}_i)^2,\qquad
\text{SST} = \sum_{i=1}^{n} (y_i - \bar{y})^2,\qquad
R^2 = 1 - \frac{\text{SSE}}{\text{SST}}
\] Untuk model nls, \(R^2\) dihitung sebagai pseudo-\(R^2\) dengan rumus di
atas.
data("ChickWeight", package = "datasets")
# Pilih satu ekor ayam agar bentuk kurva terlihat jelas dan comparable
# Jika ingin ganti, ubah nilai chick_id berikut (1–50).
chick_id <- 1
dat <- subset(ChickWeight, Chick == chick_id)
# Tampilkan ringkasan
summary(dat)
## weight Time Chick Diet
## Min. : 42.00 Min. : 0.00 1 :12 1:12
## 1st Qu.: 62.75 1st Qu.: 5.50 18 : 0 2: 0
## Median : 99.50 Median :11.00 16 : 0 3: 0
## Mean :111.67 Mean :10.92 15 : 0 4: 0
## 3rd Qu.:154.50 3rd Qu.:16.50 13 : 0
## Max. :205.00 Max. :21.00 9 : 0
## (Other): 0
head(dat)
# Model non-linear logistik dengan self-start
m_nl <- nls(weight ~ SSlogis(Time, Asym, xmid, scal), data = dat)
# Koefisien & interval kepercayaan (normal approximation agar stabil)
coef_nl <- coef(m_nl)
ci_nl <- confint.default(m_nl)
coef_nl
## Asym xmid scal
## 937.03024 35.22296 11.40521
ci_nl
## 2.5 % 97.5 %
## Asym 23.945795 1850.11468
## xmid 18.931692 51.51424
## scal 9.630959 13.17946
m_lm <- lm(weight ~ Time, data = dat)
summary(m_lm)
##
## Call:
## lm(formula = weight ~ Time, data = dat)
##
## Residuals:
## Min 1Q Median 3Q Max
## -14.3202 -11.3081 -0.3444 11.1162 17.5346
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 24.4654 6.7279 3.636 0.00456 **
## Time 7.9879 0.5236 15.255 2.97e-08 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 12.29 on 10 degrees of freedom
## Multiple R-squared: 0.9588, Adjusted R-squared: 0.9547
## F-statistic: 232.7 on 1 and 10 DF, p-value: 2.974e-08
# Prediksi & residu
pred_nl <- predict(m_nl)
pred_lm <- predict(m_lm)
y <- dat$weight
ybar <- mean(y)
# SSE
sse_nl <- sum((y - pred_nl)^2)
sse_lm <- sum((y - pred_lm)^2)
# SST
sst <- sum((y - ybar)^2)
# R^2
r2_nl <- 1 - sse_nl / sst
r2_lm <- summary(m_lm)$r.squared
# Tabel ringkas
comp <- data.frame(
Model = c("Nonlinear (Logistik)", "Linear"),
SSE = c(sse_nl, sse_lm),
R2 = c(r2_nl, r2_lm)
)
comp
library(ggplot2)
# Buat grid waktu halus untuk kurva yang mulus
grid_t <- data.frame(Time = seq(min(dat$Time), max(dat$Time), length.out = 200))
# Prediksi pada grid
grid_t$pred_nl <- predict(m_nl, newdata = grid_t)
grid_t$pred_lm <- predict(m_lm, newdata = grid_t)
ggplot(dat, aes(Time, weight)) +
geom_point(size = 2, alpha = 0.8) +
geom_line(data = grid_t, aes(Time, pred_nl), linewidth = 1) +
geom_line(data = grid_t, aes(Time, pred_lm), linewidth = 1, linetype = "dashed") +
labs(title = paste("Chick", chick_id, ": Nonlinear Logistik vs Regresi Linear"),
subtitle = "Garis penuh: Nonlinear (SSlogis) | Garis putus-putus: Linear",
x = "Waktu (hari)", y = "Berat") +
theme_minimal(base_size = 12)
Secara biologis, pertumbuhan berat makhluk hidup sering mengikuti pola sigmoidal: fase lambat (adaptasi), diikuti cepat (eksponensial), lalu jenuh (mendekati asimtot). Model logistik menangkap ketiga fase ini melalui parameter \(\text{Asym}\), \(x_{\text{mid}}\), dan \(\text{scal}\). Sebaliknya, regresi linear mengasumsikan laju pertambahan konstan sepanjang waktu, sehingga tidak mampu merepresentasikan perlambatan alami menjelang kedewasaan.
Dari hasil perbandingan metrik, SSE yang lebih kecil dan R² (pseudo-\(R^2\)) yang lebih tinggi pada model logistik mengindikasikan kecocokan yang lebih baik dengan data. Visualisasi juga menunjukkan bahwa kurva logistik mengikuti pola data secara lebih realistis, terutama pada bagian awal dan akhir pertumbuhan, di mana regresi linear cenderung over/under-fit.
nls()Kita mensimulasikan proses pertumbuhan eksponensial yang sering digunakan untuk memodelkan pertumbuhan bakteri pada tahap awal:
\[ y(t) \;=\; A\,\exp(rt) \;+\; \varepsilon,\qquad \varepsilon \sim \mathcal{N}(0,\sigma^2) \]
dengan \(A>0\) adalah konstanta skala (ukuran awal) dan \(r>0\) adalah laju pertumbuhan.
set.seed(123)
n <- 60
t <- seq(0, 6, length.out = n) # waktu (jam atau satuan lain)
A0 <- 5 # true A
r0 <- 0.45 # true r
sigma <- 2 # noise sd
y_true <- A0 * exp(r0 * t)
y_obs <- y_true + rnorm(n, sd = sigma)
simdat <- data.frame(t = t, y = y_obs, y_true = y_true)
head(simdat)
nls()m_exp <- nls(y ~ A * exp(r * t), data = simdat,
start = list(A = 1, r = 0.1))
coef_exp <- coef(m_exp)
ci_exp <- confint.default(m_exp)
coef_exp
## A r
## 4.9987017 0.4511008
ci_exp
## 2.5 % 97.5 %
## A 4.6505225 5.3468810
## r 0.4373722 0.4648293
pred_exp <- predict(m_exp)
sse_exp <- sum((simdat$y - pred_exp)^2)
sst_exp <- sum((simdat$y - mean(simdat$y))^2)
r2_exp <- 1 - sse_exp / sst_exp
data.frame(SSE = sse_exp, R2 = r2_exp)
# Visualisasi: data, true curve, dan fitted curve
grid_s <- data.frame(t = seq(min(simdat$t), max(simdat$t), length.out = 200))
grid_s$pred_true <- A0 * exp(r0 * grid_s$t)
grid_s$pred_fit <- predict(m_exp, newdata = grid_s)
ggplot(simdat, aes(t, y)) +
geom_point(size = 2, alpha = 0.8) +
geom_line(data = grid_s, aes(t, pred_true), linewidth = 1, linetype = "dotted") +
geom_line(data = grid_s, aes(t, pred_fit), linewidth = 1) +
labs(title = "Simulasi Pertumbuhan Eksponensial: Data vs True Curve vs Fitted",
subtitle = "Titik: data ber-noise | Garis putus-putus: true | Garis penuh: fitted nls",
x = "Waktu (t)", y = "y") +
theme_minimal(base_size = 12)
Hasil estimasi nls() mengembalikan parameter \(\hat{A}\) dan \(\hat{r}\) yang mendekati
nilai sebenarnya \((A_0, r_0)\), dengan
R² tinggi yang menandakan kecocokan model yang baik
terhadap data simulasi. Perbedaan kecil antara kurva
true dan fitted terutama berasal dari
komponen noise \(\varepsilon\). Semakin
kecil \(\sigma\), kurva fitted akan
semakin menumpuk pada kurva true.
nls() mampu mengestimasi parameter
pertumbuhan dengan akurat pada data yang sesuai dengan struktur model,
dan metrik goodness-of-fit mengonfirmasi kecocokan
tersebut.```