Objetivo

Este trabalho investiga se a poluição do ar impacta o gasto com saúde dos países.

A análise é feita em duas etapas:

Etapa 1 — Teste t: Verificamos se países com alta poluição gastam mais com saúde do que países com baixa poluição, dividindo a amostra pela mediana do PM2.5.

Etapa 2 — Regressão linear: Estimamos o efeito puro da poluição sobre o gasto com saúde, controlando por variáveis que poderiam confundir essa relação (densidade populacional e percentual de idosos).


1. Importação e Limpeza dos Dados

Poluição do Ar (PM2.5)

air_pollution <- read_csv2(
  "C:/Users/Guilherme/Downloads/air polution/base_com_continentes.csv"
) |>
  select(-"Indicator Name", -"Indicator Code", -"Unnamed: 70") |>
  pivot_longer(
    cols      = -c("Continente", "Country Name", "Country Code"),
    names_to  = "ano",
    values_to = "pm25"
  ) |>
  rename(continente = Continente, pais = `Country Name`, codigo = `Country Code`) |>
  mutate(ano = as.integer(ano)) |>
  filter(ano == 2018) |>
  drop_na(pm25) |>
  filter(continente != "Outros")

air_pollution |> count(continente) |> kable(caption = "Países por Continente")
Países por Continente
continente n
Africa 54
America 32
Asia 46
Europe 43
Oceania 14

Gasto com Saúde

gasto_saude <- read_csv(
  "C:/Users/Guilherme/Downloads/petro/Gasto com saúde.csv",
  skip = 4
) |>
  select(-"Indicator Name", -"Indicator Code") |>
  pivot_longer(
    cols      = -c("Country Name", "Country Code"),
    names_to  = "ano",
    values_to = "gasto_saude_pct_gdp"
  ) |>
  rename(pais = "Country Name", codigo = "Country Code") |>
  mutate(ano = as.integer(ano)) |>
  filter(ano == 2018) |>
  drop_na(gasto_saude_pct_gdp)

Percentual de Idosos (65+)

pop_idosa <- read_csv(
  "C:/Users/Guilherme/Downloads/% 65+/Population (age group as % of total population).csv"
) |>
  rename(
    pais        = Economy,
    ano         = Year,
    codigo      = `Economy Code`,
    pct_65_mais = `Population ages 65 and above (% of total population)`
  ) |>
  drop_na() |>
  filter(!is.na(codigo) & codigo != "")

Densidade Populacional

pop_densidade <- read_csv(
  "C:/Users/Guilherme/Downloads/densidade populacional/API_EN.POP.DNST_DS2_en_csv_v2_1453.csv",
  skip = 4
) |>
  select(-"Indicator Name", -"Indicator Code") |>
  pivot_longer(
    cols      = -c("Country Name", "Country Code"),
    names_to  = "ano",
    values_to = "densidade_pop"
  ) |>
  rename(pais = "Country Name", codigo = "Country Code") |>
  mutate(ano = as.integer(ano)) |>
  filter(ano == 2018) |>
  drop_na(densidade_pop) |>
  filter(!is.na(codigo) & codigo != "")

2. Montagem da Base Principal

Usamos inner_join para manter apenas os países que aparecem nas duas bases simultaneamente — poluição e gasto com saúde. Países sem dados em qualquer uma das fontes são descartados.

paises_comuns_air <- inner_join(
  air_pollution |> select(codigo),
  gasto_saude   |> select(codigo),
  by = "codigo"
)

Air_2018       <- air_pollution |> filter(codigo %in% paises_comuns_air$codigo)
Health_2018    <- gasto_saude   |> filter(codigo %in% paises_comuns_air$codigo)
dados_trabalho <- inner_join(Air_2018, Health_2018, by = "codigo")

cat("Países na base principal:", nrow(dados_trabalho), "\n")
## Países na base principal: 186

3. Etapa 1 — Teste de Hipótese

Dividimos os países em dois grupos pela mediana do PM2.5:

H₀: A média do gasto com saúde é igual nos dois grupos.
H₁: A média do gasto com saúde é diferente nos dois grupos.

mediana_pm25 <- median(dados_trabalho$pm25)

dados_trabalho <- dados_trabalho |>
  mutate(grupo = ifelse(pm25 >= mediana_pm25, "Alta poluição", "Baixa poluição"))

table(dados_trabalho$grupo)
## 
##  Alta poluição Baixa poluição 
##             93             93

Pressuposto — Teste de Levene

Antes do teste t, verificamos se as variâncias dos dois grupos são iguais usando o teste de Levene:

  • Se p > 0.05 → variâncias iguais → teste t padrão (var.equal = TRUE)
  • Se p < 0.05 → variâncias diferentes → Welch t-test (var.equal = FALSE)
levene_result <- leveneTest(gasto_saude_pct_gdp ~ grupo, data = dados_trabalho)
levene_result
## Levene's Test for Homogeneity of Variance (center = median)
##        Df F value  Pr(>F)  
## group   1  2.9271 0.08879 .
##       184                  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
var_igual <- levene_result$`Pr(>F)`[1] > 0.05
cat("Variâncias iguais?", ifelse(var_igual, "SIM - teste t padrão", "NÃO - Welch t-test"), "\n")
## Variâncias iguais? SIM - teste t padrão

Estatísticas Descritivas

dados_trabalho |>
  group_by(grupo) |>
  summarise(
    n           = n(),
    media_saude = round(mean(gasto_saude_pct_gdp), 2),
    dp_saude    = round(sd(gasto_saude_pct_gdp), 2),
    media_pm25  = round(mean(pm25), 2)
  ) |>
  kable(caption = "Estatísticas Descritivas por Grupo")
Estatísticas Descritivas por Grupo
grupo n media_saude dp_saude media_pm25
Alta poluição 93 5.33 2.44 38.60
Baixa poluição 93 7.48 2.95 13.93

Teste t

resultado_teste <- t.test(
  gasto_saude_pct_gdp ~ grupo,
  data      = dados_trabalho,
  var.equal = var_igual
)
resultado_teste
## 
##  Two Sample t-test
## 
## data:  gasto_saude_pct_gdp by grupo
## t = -5.427, df = 184, p-value = 1.791e-07
## alternative hypothesis: true difference in means between group Alta poluição and group Baixa poluição is not equal to 0
## 95 percent confidence interval:
##  -2.933378 -1.369211
## sample estimates:
##  mean in group Alta poluição mean in group Baixa poluição 
##                     5.328214                     7.479508

Poder do Teste

O poder mede a capacidade do teste de detectar uma diferença real quando ela existe. Um poder baixo indica que, mesmo que exista diferença entre os grupos, o teste pode não conseguir detectá-la com o tamanho de amostra disponível.

  • d de Cohen — tamanho do efeito: diferença entre as médias dividida pelo desvio padrão combinado
  • Poder — probabilidade de rejeitar H₀ quando ela é falsa (ideal > 80%)
  • Erro Tipo 2 (β) — probabilidade de não detectar uma diferença real
media_alta  <- mean(dados_trabalho$gasto_saude_pct_gdp[dados_trabalho$grupo == "Alta poluição"])
media_baixa <- mean(dados_trabalho$gasto_saude_pct_gdp[dados_trabalho$grupo == "Baixa poluição"])
dp_alta     <- sd(dados_trabalho$gasto_saude_pct_gdp[dados_trabalho$grupo == "Alta poluição"])
dp_baixa    <- sd(dados_trabalho$gasto_saude_pct_gdp[dados_trabalho$grupo == "Baixa poluição"])
dp_pooled   <- sqrt((dp_alta^2 + dp_baixa^2) / 2)
d_cohen     <- (media_alta - media_baixa) / dp_pooled

n_grupo   <- min(table(dados_trabalho$grupo))
gl        <- 2 * n_grupo - 2
t_critico <- qt(1 - 0.05 / 2, df = gl)

poder <- pwr.t.test(n = n_grupo, d = d_cohen, sig.level = 0.05, type = "two.sample")

cat("╔══════════════════════════════════════════╗\n")
## ╔══════════════════════════════════════════╗
cat("║     RESULTADO — POLUIÇÃO vs SAÚDE        ║\n")
## ║     RESULTADO — POLUIÇÃO vs SAÚDE        ║
cat("╠══════════════════════════════════════════╣\n")
## ╠══════════════════════════════════════════╣
cat("║ Levene p-valor  :", round(levene_result$`Pr(>F)`[1], 4), "\n")
## ║ Levene p-valor  : 0.0888
cat("║ Variâncias      :", ifelse(var_igual, "Iguais", "Diferentes"), "\n")
## ║ Variâncias      : Iguais
cat("╠══════════════════════════════════════════╣\n")
## ╠══════════════════════════════════════════╣
cat("║ t observado     :", round(resultado_teste$statistic, 4), "\n")
## ║ t observado     : -5.427
cat("║ t crítico       : ±", round(t_critico, 4), "\n")
## ║ t crítico       : ± 1.9729
cat("║ p-valor         :", round(resultado_teste$p.value, 4), "\n")
## ║ p-valor         : 0
cat("║ alfa            : 0.05\n")
## ║ alfa            : 0.05
cat("╠══════════════════════════════════════════╣\n")
## ╠══════════════════════════════════════════╣
cat("║ d de Cohen      :", round(d_cohen, 4), "\n")
## ║ d de Cohen      : -0.7959
cat("║ Poder do teste  :", round(poder$power, 4), "\n")
## ║ Poder do teste  : 0.9997
cat("║ Erro Tipo 2     :", round(1 - poder$power, 4), "\n")
## ║ Erro Tipo 2     : 3e-04
cat("╠══════════════════════════════════════════╣\n")
## ╠══════════════════════════════════════════╣
cat("║ DECISÃO:", ifelse(resultado_teste$p.value < 0.05, "REJEITA H0", "NÃO REJEITA H0"), "\n")
## ║ DECISÃO: REJEITA H0
cat("╚══════════════════════════════════════════╝\n")
## ╚══════════════════════════════════════════╝

Visualizações — Teste t

ggplot(dados_trabalho, aes(x = gasto_saude_pct_gdp, fill = grupo)) +
  geom_density(alpha = 0.5) +
  geom_vline(xintercept = mean(dados_trabalho$gasto_saude_pct_gdp[dados_trabalho$grupo == "Alta poluição"]),
             color = "red", linetype = "dashed", show.legend = FALSE) +
  geom_vline(xintercept = mean(dados_trabalho$gasto_saude_pct_gdp[dados_trabalho$grupo == "Baixa poluição"]),
             color = "blue", linetype = "dashed", show.legend = FALSE) +
  scale_x_continuous(limits = c(0, 30)) +
  labs(
    title = "Distribuição do Gasto com Saúde por Grupo de Poluição (2018)",
    x     = "Gasto com Saúde (% do PIB)",
    y     = "Densidade",
    fill  = "Grupo de Poluição"
  ) +
  theme_minimal()

dados_trabalho <- dados_trabalho |>
  group_by(grupo) |>
  mutate(saude_centrado = gasto_saude_pct_gdp - mean(gasto_saude_pct_gdp)) |>
  ungroup()

ggplot(dados_trabalho, aes(x = saude_centrado, fill = grupo)) +
  geom_density(alpha = 0.5) +
  geom_vline(xintercept = 0, color = "black", linetype = "dashed", show.legend = FALSE) +
  facet_wrap(~ grupo, ncol = 1) +
  labs(
    title = "Distribuição do Gasto com Saúde Centrada na Média por Grupo (2018)",
    x     = "Desvio em relação à média do grupo (% do PIB)",
    y     = "Densidade",
    fill  = "Grupo de Poluição"
  ) +
  theme_minimal()

x <- seq(-4, 4, length.out = 1000)
y <- dt(x, df = gl)

ggplot(data.frame(x, y), aes(x, y)) +
  geom_line(linewidth = 1) +
  geom_area(data = subset(data.frame(x, y), x >  t_critico), aes(x, y), fill = "red", alpha = 0.4) +
  geom_area(data = subset(data.frame(x, y), x < -t_critico), aes(x, y), fill = "red", alpha = 0.4) +
  geom_vline(xintercept =  t_critico, color = "red",  linetype = "dashed") +
  geom_vline(xintercept = -t_critico, color = "red",  linetype = "dashed") +
  geom_vline(xintercept = resultado_teste$statistic, color = "blue", linetype = "solid", linewidth = 1) +
  annotate("text", x =  t_critico + 0.4, y = 0.35,
           label = paste("t crítico =",  round( t_critico, 2)), color = "red") +
  annotate("text", x = -t_critico - 0.4, y = 0.35,
           label = paste("t crítico =", round(-t_critico, 2)), color = "red") +
  annotate("text", x = resultado_teste$statistic, y = 0.38,
           label = paste("t obs =", round(resultado_teste$statistic, 2)), color = "blue") +
  labs(
    title = "Distribuição t com Regiões Críticas — Poluição vs Gasto com Saúde (2018)",
    x = "Valor t", y = "Densidade"
  ) +
  theme_minimal()


4. Etapa 2 — Regressão Linear

O teste t compara médias entre dois grupos, mas não controla por outros fatores. A regressão linear nos permite isolar o efeito puro da poluição sobre o gasto com saúde, removendo a influência de variáveis confundidoras.

Modelo estimado:

\[\text{Gasto\_Saúde}_i = \beta_0 + \beta_1 \cdot PM2.5_i + \beta_2 \cdot Densidade_i + \beta_3 \cdot Idosos_i + \beta_4 \cdot Continente_i + \varepsilon_i\]

Onde:

A interpretação do β₁ é: mantendo constantes a densidade, o percentual de idosos e o continente, um aumento de 1 µg/m³ no PM2.5 está associado a uma variação de β₁ pontos percentuais no gasto com saúde.

Montagem da Base de Regressão

Adicionamos as variáveis de controle à base principal, mantendo apenas países com dados em todas as fontes.

paises_regressao <- inner_join(
  dados_trabalho |> select(codigo),
  pop_densidade  |> select(codigo),
  by = "codigo"
) |>
  inner_join(pop_idosa |> select(codigo), by = "codigo")

base_regressao <- dados_trabalho |>
  filter(codigo %in% paises_regressao$codigo) |>
  inner_join(pop_densidade |> select(codigo, densidade_pop), by = "codigo") |>
  inner_join(pop_idosa     |> select(codigo, pct_65_mais),   by = "codigo")

cat("Países na regressão:", nrow(base_regressao), "\n")
## Países na regressão: 186

Regressão Geral

A regressão geral usa todos os países da amostra e inclui o continente como variável de controle. O indica quanto da variação no gasto com saúde é explicada pelo modelo, e o p-valor de β₁ indica se a poluição tem efeito estatisticamente significativo.

reg_geral <- lm(
  gasto_saude_pct_gdp ~ pm25 + densidade_pop + pct_65_mais + continente,
  data = base_regressao
)

summary(reg_geral)
## 
## Call:
## lm(formula = gasto_saude_pct_gdp ~ pm25 + densidade_pop + pct_65_mais + 
##     continente, data = base_regressao)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -5.6337 -1.5774 -0.2453  1.1060 10.3480 
## 
## Coefficients:
##                     Estimate Std. Error t value Pr(>|t|)    
## (Intercept)        5.0694408  0.6698388   7.568 1.96e-12 ***
## pm25              -0.0185102  0.0134033  -1.381 0.169006    
## densidade_pop     -0.0003835  0.0001308  -2.932 0.003812 ** 
## pct_65_mais        0.2096883  0.0569642   3.681 0.000308 ***
## continenteAmerica  0.7461409  0.6392688   1.167 0.244699    
## continenteAsia    -0.4393331  0.5165995  -0.850 0.396227    
## continenteEurope  -0.4752776  0.9342585  -0.509 0.611577    
## continenteOceania  2.5587005  0.8041919   3.182 0.001728 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.449 on 178 degrees of freedom
## Multiple R-squared:  0.3158, Adjusted R-squared:  0.2889 
## F-statistic: 11.74 on 7 and 178 DF,  p-value: 3.023e-12

Regressão por Continente

Rodamos a regressão separadamente para cada continente para verificar se o efeito da poluição sobre o gasto com saúde é homogêneo entre regiões ou varia. Isso é importante porque países africanos e europeus têm contextos econômicos e de saúde muito diferentes.

continentes <- unique(base_regressao$continente)

resultados_continente <- lapply(continentes, function(cont) {
  dados_cont <- base_regressao |> filter(continente == cont)
  if (nrow(dados_cont) < 5) return(NULL)

  reg <- lm(
    gasto_saude_pct_gdp ~ pm25 + densidade_pop + pct_65_mais,
    data = dados_cont
  )

  coef_pm25 <- coef(summary(reg))["pm25", ]

  data.frame(
    continente    = cont,
    n_paises      = nrow(dados_cont),
    beta1         = round(coef_pm25["Estimate"],   4),
    erro_padrao   = round(coef_pm25["Std. Error"], 4),
    t_valor       = round(coef_pm25["t value"],    4),
    p_valor       = round(coef_pm25["Pr(>|t|)"],   4),
    significativo = ifelse(coef_pm25["Pr(>|t|)"] < 0.05, "SIM", "NAO")
  )
})

tabela_betas <- do.call(rbind, resultados_continente)
kable(tabela_betas, caption = "β₁ da Poluição sobre Gasto com Saúde por Continente")
β₁ da Poluição sobre Gasto com Saúde por Continente
continente n_paises beta1 erro_padrao t_valor p_valor significativo
Estimate Africa 54 -0.0319 0.0192 -1.6641 0.1023 NAO
Estimate1 America 30 -0.1267 0.0696 -1.8215 0.0801 NAO
Estimate2 Asia 45 0.0144 0.0203 0.7095 0.4820 NAO
Estimate3 Europe 43 -0.0909 0.0383 -2.3738 0.0226 SIM
Estimate4 Oceania 14 -1.5160 0.6931 -2.1874 0.0536 NAO

5. Visualizações — Regressão

β₁ por Continente com Intervalo de Confiança

O gráfico mostra o β₁ estimado para cada continente com seu intervalo de confiança de 95%. Quando o intervalo não cruza o zero, o efeito é estatisticamente significativo. O ponto preto representa o β₁ da regressão geral.

ic_continente <- lapply(continentes, function(cont) {
  dados_cont <- base_regressao |> filter(continente == cont)
  if (nrow(dados_cont) < 5) return(NULL)

  reg  <- lm(
    gasto_saude_pct_gdp ~ pm25 + densidade_pop + pct_65_mais,
    data = dados_cont
  )
  ic   <- confint(reg)["pm25", ]
  beta <- coef(reg)["pm25"]

  data.frame(continente = cont, beta = beta, ic_inf = ic[1], ic_sup = ic[2])
})

df_ic <- do.call(rbind, ic_continente)

ic_geral <- confint(reg_geral)["pm25", ]
df_ic <- rbind(df_ic, data.frame(
  continente = "GERAL",
  beta       = coef(reg_geral)["pm25"],
  ic_inf     = ic_geral[1],
  ic_sup     = ic_geral[2]
))

ggplot(df_ic, aes(x = reorder(continente, beta), y = beta, color = continente == "GERAL")) +
  geom_point(size = 4) +
  geom_errorbar(aes(ymin = ic_inf, ymax = ic_sup), width = 0.2, linewidth = 0.8) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
  coord_flip() +
  scale_color_manual(values = c("TRUE" = "black", "FALSE" = "steelblue"), guide = "none") +
  labs(
    title    = "Beta da Poluicao sobre Gasto com Saude por Continente (2018)",
    subtitle = "Controlando por densidade populacional e % de idosos",
    x        = "Continente",
    y        = "Beta (PM2.5 -> Gasto com Saude % PIB)"
  ) +
  theme_minimal()

 ggplot(df_ic, aes(x = reorder(continente, beta), y = beta, color = continente == "GERAL")) +
   geom_point(size = 4) +
   geom_errorbar(aes(ymin = ic_inf, ymax = ic_sup), width = 0.2, linewidth = 0.8) +
   geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
   coord_flip(ylim = c(-0.5, 0.5)) +                        # limita o eixo
   scale_color_manual(values = c("TRUE" = "black", "FALSE" = "steelblue"), guide = "none") +
   geom_text(aes(label = round(beta, 3)),                    # mostra o valor do beta
             hjust = -0.3, size = 3.5, color = "black") +
   labs(
     title    = "Beta da Poluicao sobre Gasto com Saude por Continente (2018)",
     subtitle = "Controlando por densidade populacional e % de idosos",
     x        = "Continente",
     y        = "Beta (PM2.5 -> Gasto com Saude % PIB)"
   ) +
   theme_minimal()

Scatter — Poluição vs Gasto com Saúde

ggplot(base_regressao, aes(x = pm25, y = gasto_saude_pct_gdp, color = continente)) +
  geom_point(alpha = 0.7, size = 2) +
  geom_smooth(method = "lm", se = FALSE, color = "black", linewidth = 1) +
  labs(
    title  = "Poluicao do Ar vs Gasto com Saude (2018)",
    x      = "PM2.5 (µg/m³)",
    y      = "Gasto com Saude (% do PIB)",
    color  = "Continente"
  ) +
  theme_minimal()


6. Conclusão

Teste t: Com p-valor = 0, rejeitamos H₀ — há diferença significativa no gasto com saúde entre países de alta e baixa poluição.

Regressão: O β₁ estimado na regressão geral representa o efeito puro da poluição sobre o gasto com saúde, controlando por densidade, idosos e continente. A análise por continente permite identificar heterogeneidade regional nessa relação — um β₁ negativo indica que mais poluição está associada a menor gasto com saúde (típico de países em desenvolvimento), enquanto um β₁ positivo indica o contrário.


Fontes: