Introdução

Este relatório investiga a relação entre PIB per capita e expectativa de vida utilizando dados do World Development Indicators (WDI). A literatura descreve a curva de Preston: países de baixa renda apresentam grandes ganhos de expectativa de vida quando a renda cresce, enquanto, em níveis mais altos de renda, os ganhos marginais diminuem. Essa forma sugere uma relação não linear entre renda (\(X\)) e vida (\(Y\)).

A estratégia é ajustar uma regressão usando expansões de Fourier, permitindo capturar curvaturas complexas sem especificar, de antemão, um polinômio. A complexidade é controlada via número de harmônicos \(p\), escolhido por validação cruzada leave-one-out (LOO-CV), e com apoio de AIC/BIC quando útil.

Dados e Pré-processamento

Utilizamos a base WDI com duas variáveis principais: PIB per capita (USD) — preditora \(X\) — e expectativa de vida (anos) — resposta \(Y\). A amostra é transversal (um ponto por país). O objetivo é descritivo, não causal.

Caminho do CSV: D:/Script_R/Aprendizado_Maquina_TrabGrupo/worldDevelopmentIndicators.csv

# Caminho fixo para o CSV
csv_path <- "D:/Script_R/Aprendizado_Maquina_TrabGrupo/worldDevelopmentIndicators.csv"
if (!file.exists(csv_path)) stop("CSV não encontrado em: ", csv_path)

# Ler dados
wdi <- read.csv(csv_path, stringsAsFactors = FALSE)

# Conferir colunas esperadas
stopifnot(all(c("GDPercapita", "LifeExpectancy") %in% names(wdi)))

# Remover NAs, se existirem
wdi <- subset(wdi, is.finite(GDPercapita) & is.finite(LifeExpectancy))

# Normalização preliminar (será usada no Q1 e seguintes)
xmin <- min(wdi$GDPercapita, na.rm = TRUE)
xmax <- max(wdi$GDPercapita, na.rm = TRUE)
wdi$x <- (wdi$GDPercapita - xmin) / (xmax - xmin)
wdi$y <- wdi$LifeExpectancy

cat("OK: wdi com", nrow(wdi), "linhas | x em [", round(min(wdi$x),3), ",", round(max(wdi$x),3), "]\n")
## OK: wdi com 211 linhas | x em [ 0 , 1 ]
summary(wdi[,c("GDPercapita","LifeExpectancy")])
##   GDPercapita     LifeExpectancy 
##  Min.   :   251   Min.   :45.33  
##  1st Qu.:  1682   1st Qu.:64.06  
##  Median :  5786   Median :72.49  
##  Mean   : 14150   Mean   :70.30  
##  3rd Qu.: 16863   3rd Qu.:76.75  
##  Max.   :103858   Max.   :83.48
cor(wdi$x, wdi$y)
## [1] 0.5965097

1 1) Normalização da covariável x (pergunta)

Pergunta 1. Normalize a covariável de modo que \(x \in (0,1)\). Para isso, faça \(x = \frac{x - x_{\min}}{x_{\max}-x_{\min}}\), onde \(x_{\min}\) e \(x_{\max}\) são os valores mínimos e máximos segundo a amostra usada.

Resposta 1. Aplicamos a normalização acima com base em GDPercapita. Isso estabiliza a base de Fourier, preserva a ordem entre observações e facilita a comparação de modelos.

xmin <- min(wdi$GDPercapita, na.rm = TRUE)
xmax <- max(wdi$GDPercapita, na.rm = TRUE)
wdi$x <- (wdi$GDPercapita - xmin) / (xmax - xmin)
range(wdi$x, na.rm = TRUE)
## [1] 0 1

2 2) LOO-CV do MSE para g(x) com p=1,…,30 (pergunta)

Pergunta 2. Usando mínimos quadrados e validação cruzada leave-one-out, estime o erro quadrático médio das regressões
\(g(x) = \beta_0 + \beta_1 \sin(2\pi x) + \beta_2 \cos(2\pi x) + \cdots + \beta_{2p-1} \sin(2\pi p x) + \beta_{2p} \cos(2\pi p x)\), para \(p=1,\dots,30\).

Resposta 2. Para cada \(p\), ajustamos um modelo linear com a base de Fourier e calculamos o MSE-LOO usando a fórmula exata (PRESS):
\(\widehat{y}i^{(-i)} = y_i - e_i/(1-h{ii})\) e \(\text{MSE-LOO} = \frac{1}{n}\sum_i (e_i/(1-h_{ii}))^2\).

# Base de Fourier com p harmônicos
fourier_basis <- function(x, p) {
  if (p < 1) return(data.frame())
  n <- length(x)
  out <- as.data.frame(matrix(NA_real_, nrow = n, ncol = 2*p))
  nm <- character(2*p)
  for (k in 1:p) {
    out[[2*k-1]] <- sin(2*pi*k*x)
    out[[2*k]]   <- cos(2*pi*k*x)
    nm[2*k-1] <- paste0("sin",k)
    nm[2*k]   <- paste0("cos",k)
  }
  names(out) <- nm
  out
}

# Ajuste LM para dado p
fit_fourier <- function(df, p) {
  X <- fourier_basis(df$x, p)
  dat <- data.frame(y = df$y, X)
  lm(y ~ ., data = dat)
}

# LOO para LM via PRESS
loo_from_lm <- function(model, y) {
  h <- lm.influence(model, do.coef = FALSE)$hat
  e <- resid(model)
  eps <- .Machine$double.eps^0.5
  denom <- pmax(1 - h, eps)
  loo_resid <- e / denom
  yhat_loo <- y - loo_resid
  mse <- mean(loo_resid^2)
  rmse <- sqrt(mse)
  list(yhat_loo = yhat_loo, mse = mse, rmse = rmse, h = h)
}
p_max <- 30L
risk <- data.frame(p = integer(), mse_loo = numeric(), rmse_loo = numeric())

for (p in 1:p_max) {
  m <- fit_fourier(wdi, p)
  loo <- loo_from_lm(m, wdi$y)
  risk <- rbind(risk, data.frame(p = p, mse_loo = loo$mse, rmse_loo = loo$rmse))
}
head(risk)

3 3) Gráfico do risco estimado vs p e escolha de p_esc (pergunta)

Pergunta 3. Plote o gráfico do risco estimado (MSE-LOO) vs \(p\). Qual o valor de \(p\) escolhido? Denotaremos por \(p_{esc}\).

Resposta 3. O \(p_{esc}\) é o \(p\) que minimiza o MSE-LOO. Destacamos essa escolha no gráfico com uma linha tracejada.

pesc <- risk$p[which.min(risk$mse_loo)]
cat("p_esc (mínimo MSE-LOO) =", pesc, "\n")
## p_esc (mínimo MSE-LOO) = 3
plot(risk$p, risk$mse_loo, type="b", pch=19, xlab="p (nº de harmônicos)",
     ylab="MSE - LOO", main="Risco preditivo (LOO) por p")
abline(v = pesc, lty = 2, col = "red")
legend("topright", legend = paste("p_esc =", pesc), lty=2, col="red", bty="n")

4 4) Curvas ajustadas (p=1, p=p_esc, p=30) sobre X vs Y (pergunta)

Pergunta 4. Plote as curvas ajustadas para \(p = 1\), \(p = p_{esc}\) e \(p = 30\) sobre o gráfico de dispersão de \(X\) por \(Y\), usando um grid em \([0,1]\). Qual curva parece mais razoável? Compare com polinômios vistos em aula.

Resposta 4. Comparamos as três curvas. Tipicamente, \(p=1\) é muito rígido; \(p=30\) pode ondular (overfitting); \(p=p_{esc}\) tende a equilibrar viés e variância, oferecendo melhor generalização — análogo ao observado com polinômios de grau intermediário.

pset <- unique(c(1L, pesc, 30L))
cols <- c("steelblue", "tomato", "darkgreen")
grid <- data.frame(x = seq(0, 1, length.out = 400))

plot(wdi$x, wdi$y, pch=16, col=gray(0.2), xlab="x normalizado (0-1)",
     ylab="Expectativa de vida", main="Curvas de Fourier sobre dispersão X vs Y")

for (j in seq_along(pset)) {
  p <- pset[j]
  m <- fit_fourier(wdi, p)
  Xg <- fourier_basis(grid$x, p)
  yg <- predict(m, newdata = Xg)
  lines(grid$x, yg, lwd = 2, col = cols[j])
}
legend("bottomright", legend = paste0("p = ", pset), col = cols, lwd = 2, bty = "n")

5 5) Preditos LOO vs Observados (p=1, p=p_esc, p=30) (pergunta)

Pergunta 5. Plote valores preditos (LOO) versus observados para \(p = 1\), \(p = p_{esc}\) e \(p = 30\). Qual \(p\) parece mais razoável?

Resposta 5. O melhor \(p\) é o que mantém os pontos mais próximos da reta 45° no gráfico Predito LOO vs Observado; valores de \(p\) muito altos tendem a degradar predição fora da amostra.

op <- par(mfrow=c(1, length(pset)), mar=c(4,4,2,1))
for (p in pset) {
  m <- fit_fourier(wdi, p)
  loo <- loo_from_lm(m, wdi$y)
  plot(wdi$y, loo$yhat_loo, pch=16, col=gray(0.2),
       xlab="Observado (Y)", ylab="Predito LOO",
       main=paste("p =", p))
  abline(0,1,col="red",lty=2)
}

par(op)

6 6) LOO-CV versus Data-splitting (pergunta)

Pergunta 6. Quais vantagens e desvantagens de se usar validação cruzada do tipo leave-one-out versus data-splitting?

Resposta 6.
- LOO-CV (leave-one-out)Vantagens: usa praticamente toda a amostra para treinar; não desperdiça dados; para modelos lineares, há fórmula fechada (PRESS), sendo eficiente. Desvantagens: pode ter maior variância que k-folds quando o modelo é instável; sem fórmula, é caro computacionalmente.
- Data-splitting (treino/teste)Vantagens: simples de implementar; avaliação em dados realmente “não vistos”. Desvantagens: resultados dependem da partição; desperdício de amostra (menos dados para treinar); alta variância; pode levar a escolhas subótimas de \(p\).

Conclusão: com amostras moderadas e modelos lineares, LOO-CV é preferível; com bases enormes/modelos pesados, usar k-fold (ex.: 5 ou 10) é um meio-termo eficiente.