R: R Estatística Descritiva

Última atualização: 2026-08-26

Nas 22 aulas anteriores, aprendemos sobre as “ferramentas” do R — vetores, data frames e ggplot2. Agora, vamos passar para o verdadeiro “valor” do R — a análise estatística. Nesta aula, começaremos com o conceito mais básico: “estatística descritiva”. Usaremos o R para calcular métricas importantes, como média, mediana e desvio-padrão, e “resumir” os dados em alguns números.

Ao concluir esta lição, você será capaz de gerar um “relatório estatístico” para qualquer conjunto de dados usando apenas três linhas de código R.

1. O que você vai aprender



2. A história do boletim escolar de um aluno

(1) Desafio: Como você “resumiria” 1.000 alunos?

No final do semestre, o professor Bob precisa gerar boletins de notas para 1.000 alunos. Cada aluno está cursando 5 disciplinas e, para cada uma delas, ele precisa calcular:

Cálculos manuais? Fórmulas do Excel? Isso leva duas horas; usando o R summary()——

(2) Solução usando R

R
# 1. One line summary shows 5 key metrics
summary(scores$math)
#   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#   45.0    72.0    82.0    81.5    92.0    99.0

# 2. One line skimr View the full report
library(skimr)
skim(scores$math)
# ── Variable type: numeric ──
#   min  max mean sd   p25  p50  p75  hist
#   45  99  81.5 12  72  82  92  ▇▇▇▇▇

# 3. One line dplyr Grouped Statistics
scores |> group_by(class) |> summarise(
  Average Score = mean(math),
  Median = median(math),
  Standard Deviation = sd(math),
  Highest = max(math),
  Lowest = min(math),
  Number of people = n()
)

3 linhas de código → um boletim escolar completo.



3. Três categorias principais de estatística descritiva

(1) Visão geral das três principais categorias

100%
graph TB
    A[Descriptive Statistics] --> B[Central Tendency<br/>Central Tendency]
    A --> C[Degree of dispersion<br/>Dispersion]
    A --> D[Distribution Patterns<br/>Shape]
    B --> E[mean Median mode]
    C --> F[sd var range IQR]
    D --> G[Skewness skewness<br/>Fengdu kurtosis]
    
    style A fill:#fff3cd
    style B fill:#d4edda
    style C fill:#cce5ff
    style D fill:#f8d7da

(2) Tabela de referência rápida

Categoria Função Significado
Tendência central mean() Média aritmética
Tendência central median() Mediana (50º percentil)
Centralizado mode() Modo (requer o pacote DescTools)
Discreto sd() Desvio-padrão
Discreto var() Variância
Discreto range() Valores extremos (mín./máx.)
Discreto IQR() Intervalo interquartil (Q3-Q1)
Discreto mad() Desvio absoluto mediano
Distribuição skewness() Asimetria (requer e1071)
Distribuição kurtosis() Kurtose (requer e1071)


4. Tendência central

(1) mean() Média

R
x <- c(85, 90, 78, 92, 88)

mean(x)              # [1] 86.6
mean(x, na.rm = TRUE) # Skip NA
mean(x, trim = 0.1)   # Truncated Mean (Remove the top and bottom 10%)
⚠️ Observação: A média é altamente suscetível a valores atípicos. Se os dados contiverem um único valor atípico de 10.000, a média ficará distorcida para cima. Use a mediana para distribuições assimétricas.

(2) median() Mediana

R
median(c(85, 90, 78, 92, 88))  # [1] 88
median(c(85, 90, 78, 92, 10000))  # [1] 90  ← Not affected by 10000 Impact
💡 Dica: A mediana é mais robusta do que a média. Em projetos do mundo real, dê prioridade à mediana (especialmente para distribuições assimétricas, como renda e preços de imóveis).

(3) Modo (Funções especiais)

R
# R does not have a built-in mode(), use the DescTools package
install.packages("DescTools")
library(DescTools)

Mode(c(1, 2, 2, 3, 3, 3, 4))  # [1] 3


5. Grau de dispersão

(1) sd() / var() Desvio-padrão / Variância

R
x <- c(85, 90, 78, 92, 88)

sd(x)    # [1] 5.32  ← Standard Deviation
var(x)   # [1] 28.3  <- Variance (sd^2)

Desvio-padrão = a “distância média” dos pontos de dados em relação à média. Quanto maior o valor, mais dispersos estão os dados.

(2) Valores extremos de range()

R
x <- c(85, 90, 78, 92, 88)

range(x)              # [1] 78 92  ← Minimum and Maximum
diff(range(x))        # [1] 14   ← Range

(3) IQR() Intervalo Interquartil

R
x <- c(85, 90, 78, 92, 88, 70, 95, 65, 88, 92)

IQR(x)                # [1] 11.5  ← Q3 - Q1
quantile(x, c(0.25, 0.5, 0.75))
#   25%   50%   75% 
# 78.25  88.0  89.75
💡 Dica: O IQR é uma medida discreta robusta — ele não é afetado por valores atípicos e é frequentemente usado para identificar anomalias (Q1 - 1.5*IQR ~ Q3 + 1.5*IQR).

(4) Desvio absoluto da mediana em mad()

R
mad(c(85, 90, 78, 92, 10000))  # Extremely Robust Discrete Measures
# [1] 4.45


6. Quantis

(1) quantile() Quantil

R
x <- 1:100

# Default 0%, 25%, 50%, 75%, 100%
quantile(x)
#   0%  25%  50%  75% 100% 
#  1.0 25.75 50.5 75.25 100.0

# Custom Percentiles
quantile(x, probs = c(0.1, 0.5, 0.9))
#  10%  50%  90% 
# 10.9 50.5 90.1

(2) Percentis comuns

Percentil Função Significado
Q0 (0%) min(x) Mínimo
1º trimestre (25%) quantile(x, 0.25) Quartil inferior
2º trimestre (50%) median(x) Mediana
3º trimestre (75%) quantile(x, 0.75) Quartil superior
4º trimestre (100%) max(x) Máximo


7. summary() — Uma única linha de estatísticas resumidas

R
x <- c(85, 90, 78, 92, 88, NA, 75, 95)

summary(x)
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
#   75.00   81.50   88.00   87.62   90.50   95.00       1

6 métricas principais + contagem de NA — tudo em uma única linha!

R
# Data Frame
df <- data.frame(
  age = c(20, 25, 30, 35),
  score = c(85, 90, 78, 92)
)
summary(df)
#       age            score     
#  Min.   :20.00   Min.   :78.00  
#  1st Qu.:23.75   1st Qu.:83.25  
#  Median :27.50   Median :87.50  
#  Mean   :27.50   Mean   :86.25  
#  3rd Qu.:31.25   3rd Qu.:90.50  
#  Max.   :35.00   Max.   :92.00


8. skimr: Estatística Avançada e Abrangente

R
install.packages("skimr")
library(skimr)

x <- c(85, 90, 78, 92, 88, 70, 95, 65, 88, 92)

skim(x)
# ── Data Summary ────────────────────────
# Values                           x
# Number of rows                   10
# Number of distinct                8
# Mean                            84.2
# Standard deviation             10.13
# Min                              65
# Max                              95
# Median                          87.5
# ... (More Metrics)

skim() Oferece mais de 20 métricas — 10 vezes mais detalhadas do que summary().



9. Estatística descritiva por grupo

(1) dplyr + group_by + summarise

R
library(dplyr)

# Simulation 3 Cls × 5 Student Grades
scores <- tibble(
  class = rep(c("1Cls", "2Cls", "3Cls"), each = 5),
  student = paste0("S", 1:15),
  math = c(85, 78, 92, 65, 88,    # 1 Cls
           90, 75, 80, 95, 70,    # 2 Cls
           82, 88, 76, 91, 85),   # 3 Cls
  english = c(78, 85, 88, 70, 92,
              82, 80, 90, 88, 75,
              88, 90, 78, 92, 85)
)

# Class Statistics
class_stats <- scores |>
  group_by(class) |>
  summarise(
    Number of people = n(),
    Mathematical Average = mean(math),
    Median in Mathematics = median(math),
    Mathematical Standard Deviation = sd(math),
    Top in Math = max(math),
    Lowest in Math = min(math),
    MathematicsIQR = IQR(math),
    Average English Score = mean(english)
  )

print(class_stats)
# A tibble: 3 × 9
#   class  Number of people Mathematical Average Median in Mathematics Mathematical Standard Deviation Top in Math Lowest in Math MathematicsIQR Average English Score
#   <chr> <int>    <dbl>    <dbl>      <dbl>    <dbl>    <dbl>   <dbl>    <dbl>
# 1 1Cls       5     81.6       85       11.4       92       65    17       82.6
# 2 2Cls       5     82        80        10.5       95       70    20       83
# 3 3Cls       5     84.4       85        6.02      91       76    12      86.6

(2) Discriminação por múltiplos indicadores (across)

R
# Calculate statistics for all numeric columns at once
scores |>
  group_by(class) |>
  summarise(across(where(is.numeric), list(
    mean = mean,
    sd = sd,
    median = median
  )))

(3) Sintaxe antiga para tapply (para referência)

R
# Use tapply
tapply(scores$math, scores$class, mean)
# 1Cls 2Cls 3Cls 
# 81.6 82.0 84.4


10. Exercício prático: Boletim escolar completo para 1.000 alunos

A seguir, apresentamos um exemplo de um fluxo de trabalho completo que reúne todas as estatísticas descritivas abordadas nesta aula.

▶ Exemplo: Relatório abrangente sobre 1.000 alunos e 5 disciplinas

R 📖 Somente leitura
# ============================================
# 1000 Student 5 Course Comprehensive Grade Report
# Features: Complete Descriptive Statistics + Grouping + Ranking
# ============================================

library(dplyr)
library(tidyr)
library(ggplot2)

# 1. Prepare data
set.seed(42)
n <- 1000
students <- tibble(
  id = 1:n,
  class = sample(c("1Cls", "2Cls", "3Cls", "4Cls", "5Cls"), n, replace = TRUE),
  gender = sample(c("M", "F"), n, replace = TRUE),
  math = round(rnorm(n, 80, 12)),
  english = round(rnorm(n, 78, 15)),
  physics = round(rnorm(n, 75, 14)),
  chemistry = round(rnorm(n, 76, 13)),
  biology = round(rnorm(n, 80, 10))
)

cat("=== Data Volume:", nrow(students), "rows ===\n")

# 2. University-wide Comprehensive Statistics
cat("\n=== University-wide Comprehensive Statistics ===\n")
overall <- students |>
  summarise(across(c(math, english, physics, chemistry, biology),
                   list(mean = mean, sd = sd, median = median),
                   .names = "{.col}_{.fn}"))
print(overall)

# 3. Statistics by Class
cat("\n=== Math Statistics for Each Class ===\n")
class_stats <- students |>
  group_by(class) |>
  summarise(
    Number of people = n(),
    Average = round(mean(math), 2),
    Median = median(math),
    Standard Deviation = round(sd(math), 2),
    Highest = max(math),
    Lowest = min(math),
    Q1 = quantile(math, 0.25),
    Q3 = quantile(math, 0.75),
    IQR = round(IQR(math), 2)
  ) |>
  arrange(desc(Average))
print(class_stats)

# 4. Grouped by gender
cat("\n=== All genders 5 Class Average ===\n")
gender_stats <- students |>
  group_by(gender) |>
  summarise(across(c(math, english, physics, chemistry, biology),
                   mean, .names = "{.col}_Average"))
print(gender_stats)

# 5. Each Student's Total Score and Rank
cat("\n=== Top 10 Students (Total Score) ===\n")
students <- students |>
  mutate(total = math + english + physics + chemistry + biology,
         average = round(total / 5, 2))

top10 <- students |>
  arrange(desc(total)) |>
  head(10) |>
  select(id, class, gender, total, average)
print(top10)

# 6. Identify the outliers (IQR method)
cat("\n=== Students with Outliers in Math Scores ====\n")
math_q1 <- quantile(students$math, 0.25)
math_q3 <- quantile(students$math, 0.75)
math_iqr <- IQR(students$math)
lower <- math_q1 - 1.5 * math_iqr
upper <- math_q3 + 1.5 * math_iqr

outliers <- students |>
  filter(math < lower | math > upper) |>
  select(id, class, math)

cat("Normal Range:", lower, "-", upper, "\n")
cat("Number of outliers:", nrow(outliers), "\n")
print(head(outliers, 5))

# 7. Use summary() to view by subject
cat("\n=== Mathematics summary ===\n")
print(summary(students$math))

# 8. Use skimr for advanced report
library(skimr)
cat("\n=== skimr Report ===\n")
print(skim(students |> select(math, english, physics)))

# 9. Write a report
write_csv(students, "student_report.csv")
write_csv(class_stats, "class_stats.csv")
cat("\n=== The report has been generated ===\n")
73 linhas de lógica (limite de 40, somente leitura)

Resultado esperado (trecho):

TEXT 📖 Somente leitura
=== Math Statistics for Each Class ===
# A tibble: 5 × 9
  class  Number of people Average Median Standard Deviation Highest Lowest    Q1    Q3   IQR
  <chr> <int> <dbl> <dbl>  <dbl> <int> <int> <dbl> <dbl> <dbl>
1 5Cls    201  81.0    81   12.0   114    44  72    90    18
2 1Cls    195  80.6    81   11.6   115    47  73    88    15
3 3Cls    203  79.8    80   11.8   110    49  71    88    17
4 2Cls    201  79.4    80   12.1   109    44  70    88    18
5 4Cls    200  79.1    79   12.4   116    45  70    89    19

❓ Perguntas Frequentes

P: Média ou mediana? R: Use a média para dados simétricos e a mediana para dados assimétricos. A média é geralmente usada por padrão, mas a mediana é utilizada para dados assimétricos, como renda, preços de imóveis e tempos de espera.

P: sd ou var? R: Use sd de forma consistente para todas as unidades (as mesmas unidades dos dados originais); var é o quadrado de sd (as unidades são os dados originais²). sd(x) = sqrt(var(x)).

P: Qual devo escolher, summary() ou skim()? R: summary é conciso (6 métricas), enquanto skim é detalhado (mais de 20 métricas). Use summary para uma visão geral rápida e skim para uma análise aprofundada.

P: Como se deve lidar com NA? R: Adicione na.rm = TRUE a todas as funções para ignorar NA. Caso contrário, os resultados para vetores que contenham NA serão todos NA.

P: Como o IQR é usado para identificar valores atípicos? R: Definição padrão: Valores atípicos = < Q1 - 1,5×IQR ou > Q3 + 1,5×IQR. Esse método é mais robusto do que a regra do desvio padrão (pois não pressupõe uma distribuição normal).

P: Como se calculam a assimetria e a curtose? R: Use e1071::skewness() e e1071::kurtosis(). Se a assimetria for > 0, a distribuição é assimétrica para a direita; se for < 0, é assimétrica para a esquerda. Se a curtose for > 0, a distribuição é mais acentuada do que uma distribuição normal; se for < 0, ela é mais achatada.


📖 Resumo


📝 Exercícios

  1. Problema básico: Construa um vetor x <- c(85, 90, 78, 92, 88, NA, 75, 95), calcule os valores usando mean(), median(), sd() e var() (observe na.rm = TRUE) e verifique os 8 resultados.

  2. Exercício básico: Use summary() e quantile(x, c(0, 0.25, 0.5, 0.75, 1)) para calcular as métricas estatísticas do mesmo vetor e compare os dois resultados.

  3. Problema básico: Crie um data frame (3 turmas × 5 alunos × 2 disciplinas: Matemática e Inglês) e use dplyr::group_by + summarise + across para calcular a média e o desvio padrão de todas as disciplinas em todas as turmas em uma única operação.

  4. Exercício avançado: Simule as notas de 1.000 alunos em 5 disciplinas, use skimr::skim() para gerar um relatório completo, identifique valores atípicos nas notas de matemática (usando o método do IQR) e calcule a porcentagem de alunos com notas atípicas.

  5. Desafio: Fluxo de trabalho completo — simule as notas de 1.000 alunos em 5 disciplinas: ① Descrição geral ② Descrição agrupada por turma ③ Descrição agrupada por gênero ④ Classificação ⑤ Detecção de valores atípicos ⑥ Gere um relatório em CSV + um relatório em texto Markdown (use knitr::kable() para renderizar tabelas). Salve capturas de tela do processo.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%