R: Data frames e fatores no R
Última atualização: 2026-08-26
Nas últimas 9 aulas, aprendemos sobre vetores, matrizes e listas — cada um deles com suas limitações. Data frames (data.frame) resolvem todos esses problemas: são tão fáceis de ler quanto uma planilha do Excel e tão eficientes quanto uma matriz. Nesta aula, vamos aprender sobre a verdadeira “estrela” do R — o data frame.
Os data frames e o tidyverse estão no cerne da ciência de dados no R. A partir desta aula, vamos mergulhar oficialmente no mundo da “análise de dados com o R”.
1. O que você vai aprender
- Diferenças entre
data.frame()etibble() - Criação, visualização, acesso e modificação de quadros de dados
- Filtrar, selecionar, organizar
- Variável categórica fatorial (fator)
- Introdução ao dplyr (Os “cinco fundamentos” do processamento de dados)
- Agregação agrupada (group_by + summarise)
- Aplicação prática: Análise abrangente dos dados dos funcionários
2. Uma história sobre como converter arquivos do Excel para o R
(1) Problema: o Excel não consegue lidar com isso
A planilha de pesquisa de mercado de Chen tem 10.000 linhas × 8 colunas:
EmployeesID Name Department Salary Years Performance Gender Start Date
2024001 Alice Data Department 15000 3 A M 2021-03-15
2024002 Bob Engineering Department 18000 5 A+ M 2019-08-20
...
Calcular os salários médios por “departamento”, classificar por “desempenho” e identificar os funcionários com salários mais altos... Isso leva 30 minutos no Excel, com fórmulas aninhadas a ponto de travar o programa.
(2) Solução usando R
library(dplyr)
# 5 Code execution complete 5 An Analysis
df |>
group_by(Department) |>
summarise(Average Wage = mean(Salary), Number of people = n()) |>
arrange(desc(Average Wage)) |>
filter(Average Wage > 15000)
5 linhas de código em vez de 30 minutos no Excel. Esse é o poder do DataFrame + dplyr.
3. data.frame: o “personagem principal” do R
(1) O que é um data frame?
graph TB
A["Data Frame data.frame"] --> B["Each column = 1 equal-length vectors"]
A --> C["Each line = 1 records"]
A --> D["Mixed Types(Each column is independent)"]
A --> E["The bottom layer is'A list of vectors of equal length'"]
style A fill:#fff3cd
style B fill:#cce5ff
style C fill:#d4edda
style D fill:#f8d7da
style E fill:#e1d4ff
Um data frame é uma "lista de vetores de comprimento igual":
- Cada coluna é um vetor (do mesmo tipo)
- Todas as colunas têm o mesmo comprimento
- Colunas diferentes podem ser de tipos diferentes (colunas numéricas + colunas de caracteres + colunas lógicas)
(2) Criar um data frame
# Methods 1:data.frame()(Basics R)
df <- data.frame(
name = c("Alice", "Bob", "Charlie"),
age = c(25, 30, 35),
score = c(95, 88, 92),
passed = c(TRUE, TRUE, TRUE)
)
print(df)
# name age score passed
# 1 Alice 25 95 TRUE
# 2 Bob 30 88 TRUE
# 3 Charlie 35 92 TRUE
# Methods 2:tibble(tidyverse Version,Recommendations)
# install.packages("tibble")
library(tibble)
df2 <- tibble(
name = c("Alice", "Bob", "Charlie"),
age = c(25, 30, 35),
score = c(95, 88, 92)
)
print(df2)
(3) data.frame x tibble
| Função | data.frame | tibble |
|---|---|---|
| Imprimir | Imprimir todas as linhas por padrão (pode fazer com que o sistema trave ao lidar com conjuntos de dados grandes) | Imprimir as primeiras 10 linhas + tipos de colunas por padrão |
| Nome da coluna | Aceita caracteres especiais | Verificar validade |
| Subconjunto de um subconjunto | df[, "col"] Retorna um vetor |
Sempre retorna um tibble |
| Desempenho | Mais lento | Mais rápido |
| String | Converter em fator por padrão | Manter como string |
# View Structure
str(df)
# 'data.frame': 3 obs. of 4 variables:
# $ name : chr "Alice" "Bob" "Charlie"
# $ age : num 25 30 35
# $ score : num 95 88 92
# $ passed: logi TRUE TRUE TRUE
# Summary Statistics
summary(df)
# name age score passed
# Length:3 Min. :25 Min. :88 Mode :logical
# Class :character 1st Qu.:27 Median :92 TRUE:3
# Mode :character Mean :30 Mean :91 NA's :0
# 3rd Qu.:32 3rd Qu.:93
# Max. :35 Max. :95
4. Acesso a DataFrames
(1) 4 maneiras de acessar
| Método | Sintaxe | Retorno | Finalidade |
|---|---|---|---|
df[i, j] |
Linha i, coluna j | Escalar/Vetor/DataFrame | Combinação de linha e coluna |
df[i, ] |
Linha i | DataFrame | Obter linha |
df[, j] |
Coluna j | Vetor (R básico) / Quadro de dados | Extrair coluna |
df$name |
Por nome da coluna | Vetor | Obter coluna |
df[["name"]] |
Por nome da coluna | Vetor | Obter coluna |
df <- data.frame(
name = c("Alice", "Bob", "Charlie"),
age = c(25, 30, 35),
score = c(95, 88, 92)
)
# Retrieve a single element
df[2, 3] # [1] 88
df[2, "score"] # [1] 88
# Select the entire row
df[1, ] # Entire row (Data Frame)
# name age score
# 1 Alice 25 95
# Round an entire column
df[, "age"] # Digital Vectors [1] 25 30 35
df$age # Ibid.
df[["age"]] # Ibid.
(2) Índice lógico (filtro)
# Find the Fraction > 90 line
df[df$score > 90, ]
# name age score
# 1 Alice 25 95
# 3 Charlie 35 92
# Multiple conditions
df[df$age > 25 & df$score > 85, ]
(3) ⚠️ Importante: Como recuperar colunas no R básico em comparação com o tibble
# base R:Retrieve the column return vector
df[, "age"] # [1] 25 30 35 ← Digital Vectors
# tibble:Retrieve and return the column tibble
library(tibble)
tb <- as_tibble(df)
tb[, "age"] # ← tibble(1 row 1 col)
# Want to extract a vector from tibble: Use [[ ]] or $
tb[["age"]] # [1] 25 30 35 ← Digital Vectors
[, "col"] do tibble não é convertido automaticamente em um vetor. Trata-se de um recurso de “segurança” do design — ele impede que o sistema interprete erroneamente grandes data frames como vetores, o que poderia causar o congelamento de toda a saída de dados.
5. Modificação da estrutura de dados
(1) Adicionar uma coluna
# Use $ to add
df$city <- c("Beijing", "Shanghai", "Guangzhou")
# Use transform()
df <- transform(df, bonus = score * 100)
# Use within() to reference column names
df <- within(df, level <- ifelse(score >= 90, "A", "B"))
print(df)
# name age score city bonus level
# 1 Alice 25 95 Beijing 9500 A
# 2 Bob 30 88 Shanghai 8800 B
# 3 Charlie 35 92 Guangzhou 9200 A
(2) Modificar colunas
# Array Assignment
df$age <- df$age + 1
# Condition Modification
df$score[df$name == "Bob"] <- 90
(3) Excluir uma coluna
# Assign NULL
df$bonus <- NULL
df$level <- NULL
(4) Adicionar/Excluir linhas
# Add a row: Use rbind
new_row <- data.frame(name = "Diana", age = 28, score = 85, city = "Shenzhen")
df <- rbind(df, new_row)
# Delete Row:Using Negative Indexes
df <- df[-1, ] # Delete 1st row
6. Fator: variável categórica
(1) Por que os fatores são necessários?
No R, usar fatores para representar variáveis categóricas (como “baixo/médio/alto”) é mais eficaz do que usar vetores de caracteres:
# Character vector(Disorder)
gender_char <- c("M", "F", "M", "F", "M")
# factor(Orderly + Finite values)
gender_factor <- factor(gender_char, levels = c("M", "F"))
gender_factor
# [1] M F M F M
# Levels: M F
(2) As vantagens dos fatores
graph TB
A["Character vector 'Low' 'Mid' 'High'"] --> B["factor factor<br/>+ levels Order<br/>+ Finite values<br/>+ Save memory"]
A --> C["Disadvantages: Cannot sort and compare"]
B --> D["Advantages: Can be compared for size<br/>Can be grouped in order<br/>Statistics/Knowing the Number of Categories in Modeling"]
style A fill:#f8d7da
style B fill:#d4edda
style D fill:#cce5ff
# Compare Sizes(Characters cannot,Factors can)
sizes <- factor(c("S", "L", "Mid", "L", "S"),
levels = c("S", "Mid", "L"),
ordered = TRUE)
sizes[1] < sizes[2] # TRUE <- Characters can't do that!
(3) Operações comuns com fatores
# View levels
levels(sizes)
# [1] "S" "Mid" "L"
# Frequency Count
table(sizes)
# sizes
# S Mid L
# 2 1 2
# Reorder
sizes <- factor(sizes, levels = c("L", "Mid", "S")) # Reverse the order
levels(sizes)
# [1] "L" "Mid" "S"
forcats (abordado na Lição 11) para lidar com fatores, pois ele é mais elegante do que o R básico.
(4) Fatores na estrutura de dados
# data.frame() Convert character strings to factors by default (This is a trap!)
df <- data.frame(
name = c("Alice", "Bob"), # Character vector
stringsAsFactors = FALSE # Disable Auto-Conversion(Recommendations)
)
str(df)
# $ name: chr "Alice" "Bob" ← Preserve characters
stringsAsFactors = FALSE por padrão, mas códigos mais antigos podem usar um valor diferente. Recomenda-se escrever explicitamente stringsAsFactors = FALSE.
7. Introdução ao dplyr: os cinco fundamentos do processamento de dados
dplyr está no cerne do tidyverse; cinco funções abrangem 80% dos cenários de processamento de dados:
(1) Instalação e carregamento
install.packages("dplyr")
library(dplyr)
(2) Função de cinco partes
| Função | Finalidade | Equivalente em SQL |
|---|---|---|
filter() |
Filtrar linhas | WHERE |
select() |
Selecionar coluna | SELECT |
mutate() |
Adicionar/Modificar coluna | — |
arrange() |
Ordenar | ORDER BY |
summarise() |
Estatísticas agregadas | GROUP BY |
(3) O operador encadeado |>
# |> is R 4.1+'s "pipe symbol", Pass the result from the previous step to the next step
df |> filter(age > 25) |> select(name, age)
(4) Prática: Processamento de dados de funcionários
# Prepare the data
employees <- tibble(
id = 2024001:2024010,
name = c("Alice", "Bob", "Charlie", "Diana", "Eve",
"Frank", "Grace", "Henry", "Ivy", "Jack"),
department = c("Data Department", "Engineering Department", "Data Department", "Product Department", "Engineering Department",
"Data Department", "Engineering Department", "Product Department", "Data Department", "Engineering Department"),
salary = c(15000, 18000, 16000, 20000, 17000,
15500, 19000, 21000, 16500, 17500),
years = c(3, 5, 4, 7, 4, 2, 6, 8, 3, 5),
performance = factor(
c("A", "A+", "B", "A+", "A", "B", "A", "A+", "B", "A"),
levels = c("B", "A", "A+"),
ordered = TRUE
)
)
# 1. filter:Screening Data Department Employees
data_dept <- employees |> filter(department == "Data Department")
# 2. select:Select a subset of columns
basic_info <- employees |> select(name, department, salary)
# 3. mutate:Add an "Annual Salary" column
employees <- employees |> mutate(annual_salary = salary * 12)
# 4. arrange:Sort by salary in descending order
ranked <- employees |> arrange(desc(salary))
# 5. summarise:By Department
dept_stats <- employees |>
group_by(department) |>
summarise(
Number of people = n(),
Average Wage = mean(salary),
Highest Salary = max(salary),
Total Annual Salary = sum(annual_salary)
) |>
arrange(desc(Average Wage))
print(dept_stats)
# # A tibble: 3 × 5
# department Number of people Average Wage Highest Salary Total Annual Salary
# <chr> <int> <dbl> <dbl> <dbl>
# 1 Product Department 2 20500 21000 492000
# 2 Engineering Department 4 17875 19000 858000
# 3 Data Department 4 15750 16500 756000
(5) Exemplo de uma combinação de 5 etapas
# Comprehensive Example:Identify High-Performing, High-Earning Employees
top_talent <- employees |>
filter(performance %in% c("A+", "A")) |> # Performance Screening A+ or A
filter(salary > 16000) |> # ② Filter by High Salary
mutate(salary_level = ifelse(salary > 18000, "High", "Upper-middle")) |> # ③ Add Category
arrange(desc(salary)) |> # ④ Sort
select(name, department, salary, performance, salary_level) # ⑤ Select Column
print(top_talent)
# # A tibble: 3 × 5
# name department salary performance salary_level
# <chr> <chr> <dbl> <ord> <chr>
# 1 Henry Product Department 21000 A+ High
# 2 Diana Product Department 20000 A+ High
# 3 Bob Engineering Department 18000 A+ Upper-middle
8. Exemplo completo: Análise abrangente dos dados dos funcionários
A seguir, apresentamos um exemplo de um fluxo de trabalho completo que reúne todos os conceitos abordados nesta aula.
▶ Exemplo: Análise abrangente dos dados dos funcionários da empresa
# ============================================
# Comprehensive Analysis of Company Employee Data
# Features:Using a DataFrame + dplyr Comprehensive Analysis 10 employees
# ============================================
library(dplyr)
# 1. Prepare data
employees <- tibble(
id = 2024001:2024010,
name = c("Alice", "Bob", "Charlie", "Diana", "Eve",
"Frank", "Grace", "Henry", "Ivy", "Jack"),
department = c("Data Department", "Engineering Department", "Data Department", "Product Department", "Engineering Department",
"Data Department", "Engineering Department", "Product Department", "Data Department", "Engineering Department"),
salary = c(15000, 18000, 16000, 20000, 17000,
15500, 19000, 21000, 16500, 17500),
years = c(3, 5, 4, 7, 4, 2, 6, 8, 3, 5),
performance = factor(
c("A", "A+", "B", "A+", "A", "B", "A", "A+", "B", "A"),
levels = c("B", "A", "A+"),
ordered = TRUE
)
)
cat("=== Raw Data ===\n")
print(employees)
# 2. View Structure
cat("\n=== Data Structures ===\n")
str(employees)
# 3. Summary Statistics
cat("\n=== Abstract ===\n")
summary(employees)
# 4. By Department
cat("\n=== By Department ===\n")
dept_summary <- employees |>
group_by(department) |>
summarise(
Number of people = n(),
Average Wage = mean(salary),
Median Wage = median(salary),
Highest Salary = max(salary),
Minimum Wage = min(salary),
Average Length of Service = round(mean(years), 1)
) |>
arrange(desc(Average Wage))
print(dept_summary)
# 5. Identify High-Performing Employees (A+ or A)
cat("\n=== Employees with Outstanding Performance ===\n")
top_perf <- employees |>
filter(performance %in% c("A+", "A")) |>
arrange(desc(salary)) |>
select(name, department, salary, performance, years)
print(top_perf)
# 6. Add"Pay Grade"col
cat("\n=== Salary Grade Classification ===\n")
employees <- employees |>
mutate(
salary_level = factor(
ifelse(salary >= 18000, "High",
ifelse(salary >= 16000, "Mid", "Low")),
levels = c("Low", "Mid", "High"),
ordered = TRUE
),
annual_salary = salary * 12
)
# By Pay Grade
level_summary <- employees |>
group_by(salary_level) |>
summarise(Number of people = n(), Average Wage = mean(salary))
print(level_summary)
# 7. Identify the Best Employees (High Salary + High Performance + Senior)
cat("\n=== Top Employee (High Salary + Outstanding Performance + Senior) ===\n")
top_talent <- employees |>
filter(salary >= 17000, performance == "A+", years >= 5) |>
select(name, department, salary, years, performance, annual_salary)
print(top_talent)
Resultado esperado (trecho):
=== By Department ===
# A tibble: 3 × 7
department Number of people Average Wage Median Wage Highest Salary Minimum Wage Average Length of Service
<chr> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Product Department 2 20500 20500 21000 20000 7.5
2 Engineering Department 4 17875 17750 19000 17000 4.5
3 Data Department 4 15750 15750 16500 15000 3
=== Employees with Outstanding Performance ===
# A tibble: 6 × 5
name department salary performance years
<chr> <chr> <dbl> <ord> <dbl>
1 Henry Product Department 21000 A+ 8
2 Diana Product Department 20000 A+ 7
3 Bob Engineering Department 18000 A+ 5
4 Grace Engineering Department 19000 A 6
5 Eve Engineering Department 17000 A 4
6 Jack Engineering Department 17500 A 5
❓ Perguntas Frequentes
P: Como faço para escolher entre
data.frameetibble? R: Usetibblepara novos projetos — ele é mais adequado para impressão, tem melhor desempenho e possui tipos de dados mais restritos. Enquanto estiver aprendendo, comece comdata.frame(não é preciso carregar nenhum pacote) e mude paratibbleassim que estiver familiarizado com ele.
P: Quais são as vantagens dos fatores? R: Três vantagens principais: ① Podem ser comparados quanto à magnitude (
ordered = TRUE) ② Economizam memória (armazenam apenas codificações inteiras) ③ Permitem a análise estatística e a modelagem quando o número de categorias é conhecido (evitando o problema do “valor desconhecido”). O tidyverse recomenda o uso do pacoteforcatspara lidar com fatores.
P: Qual é a relação entre o dplyr e o R básico? R: O dplyr é uma camada de abstração moderna para o R básico.
filter(df, ...)substituidf[...], eselect(df, ...)substituidf[, ...]. O dplyr é mais legível e consistente, além de seguir o padrão tidyverse para ciência de dados.
P: Qual é a diferença entre
|>e%>%? R:|>é o símbolo de pipe nativo do R 4.1+ (não é necessário carregar nenhum pacote), enquanto%>%é o símbolo de pipe do pacotemagrittr(o antigo tidyverse). O código mais recente usa|>, mas%>%ainda é comum em códigos e tutoriais mais antigos.
P: Qual é a diferença entre
mutateetransform? R:mutate()pode fazer referência a uma coluna que acabou de ser criada (mutate(df, y = x * 2, z = y + 1)), enquantotransform()não pode. É por isso quemutateé mais popular no tidyverse.
📖 Resumo
- Um data frame é uma “lista de vetores de comprimento igual”, em que cada coluna possui um tipo de dados distinto e cada linha contém um registro de dados.
data.frame()Noções básicas de R,tibbleO tidyverse moderno (recomendado para novos projetos)- 4 acessos:
df[i, j]df$namedf[["name"]]df[, j] - Um fator é uma “variável categórica ordenada”; os níveis determinam a ordem, economizando memória
- Conjunto de cinco peças dplyr:
filterselectmutatearrangesummarise group_by() | summarise()Realizar agregação de grupos;|>símbolo de pipe para encadear várias operaçõesmutatefaz referência à coluna que acabou de ser criada (o quetransformnão consegue fazer), e é por isso quemutateé mais popular no tidyverse
📝 Exercícios
-
Exercício básico: Use
data.frame()para criar um dataframestudents(6 alunos × 4 colunas: nome/idade/nota/aprovado). Imprima os dataframesstr()esummary()e acesse todas as colunas da terceira linha. -
Problema básico: Converta a coluna
namedo problema anterior parafactor(3 níveis) e compare as diferenças entreas.character()eas.numeric(). Verifique se o fator permite a comparação de magnitudes (>). -
Problema básico: Instale e carregue
dplyr; em seguida, usefilter()para filtrar os alunos descore > 85com base nostudentsdo problema anterior e classifique-os em ordem decrescente por pontuação usandoarrange(). -
Exercício avançado: Use
tibblepara criar um data framesales(10 linhas × 4 colunas: produto/região/valor/data). ① Usemutate()para somardiscount = amount * 0.1; ② Usegroup_by(region) + summarise()para calcular o total de vendas de cada região; ③ Usearrange(desc())para classificar as regiões. -
Desafio: Utilizando dados simulados de funcionários (10 funcionários, 3 departamentos, salário/anos de serviço/desempenho), conclua a análise em 7 etapas: ① Carregue o dplyr ② Calcule o número de funcionários e o salário médio por departamento ③ Identifique os funcionários com salários altos e ≥ 5 anos de serviço ④ Use
mutatepara adicionar uma coluna de salário anual ⑤ Usecase_when(ouifelse) para categorizar por faixas salariais ⑥ Classifique por desempenho ⑦ Grave em um novo data frametop_employeese salve como um arquivo CSV (write.csv()).