R: R EDA 探索性分析
最后更新:2026-08-26
前面 6 课我们学了描述统计 + 概率分布 + 假设检验 + 回归——都是"分析"工具。但数据分析的第一步不是建模,而是EDA(Exploratory Data Analysis)——探索数据"长什么样"。这一课学 R EDA 完整方法论。
读完这一课你就能用 R 完整探索任何数据集:数据形状、分布、异常、缺失、相关——为后续建模铺路。
1. 你将学到
- EDA 完整流程(5 步)
- 数据形状:str / dim / nrow / ncol
- 分布:summary / skimr
- 缺失值:md.pattern / naniar
- 分布可视化:直方图 / 箱线 / 密度图
- 关系:散点图 / 相关矩阵
- 异常值:箱线 + IQR
- 自动化 EDA(DataExplorer / SmartEDA)
2. 一个陌生数据集的痛点
(1) 痛点:100 列的 CSV 怎么开始?
Bob收到一份 100 列、10000 行的客户数据,manager问:"先分析一下这数据"。他盯着 Excel 5 分钟,不知道从哪开始。
(2) R 的解法
library(DataExplorer)
# 一行 EDA 报告
create_report(df, output_file = "eda_report.html")
1 行代码 → 完整 EDA HTML 报告(30+ 页图表 + 统计)。
3. EDA 完整流程(5 步)
(1) 5 步法
graph TB
A[1. 数据形状] --> B[2. 数据类型]
B --> C[3. 缺失值分析]
C --> D[4. 分布探索]
D --> E[5. 关系探索]
A --> A1[dim/str/head]
B --> B1[summary/skimr]
C --> C1[md.pattern/naniar]
D --> D1[直方图/箱线]
E --> E1[散点/相关矩阵]
style A fill:#fff3cd
style B fill:#cce5ff
style C fill:#d4edda
style D fill:#f8d7da
style E fill:#e1d4ff
(2) 5 步法速查
| 步骤 | 目标 | 关键函数 |
|---|---|---|
| 1. 形状 | 数据多大? | dim() nrow() ncol() str() |
| 2. 类型 | 列什么类型? | sapply(df, class) summary() |
| 3. 缺失 | 缺多少? | colSums(is.na()) skimr naniar |
| 4. 分布 | 数值范围? | hist() boxplot() geom_density() |
| 5. 关系 | 列之间相关? | pairs() cor() corrplot |
4. 步骤 1:数据形状
# 准备数据
df <- iris # 用 iris 演示
# 基本信息
dim(df) # [1] 150 5 ← 150 行 5 列
nrow(df) # [1] 150
ncol(df) # [1] 5
names(df) # 列名
str(df) # 结构
# 'data.frame': 150 obs. of 5 variables:
# $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 ...
# $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 ...
# $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 ...
# $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 ...
# $ Species : Factor w/ 3 levels "setosa",...
# 数据预览
head(df, 3) # 前 3 行
tail(df, 3) # 后 3 行
5. 步骤 2:类型与摘要
(1) 数值列 vs 分类列
# 列类型
sapply(df, class)
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# "numeric" "numeric" "numeric" "numeric" "factor"
# 自动识别
library(dplyr)
df |> summarise(across(everything(), class))
(2) summary() 一行摘要
summary(iris)
# Sepal.Length Sepal.Width Petal.Length Petal.Width
# Min. :4.30 Min. :2.00 Min. :1.00 Min. :0.1
# 1st Qu.:5.10 1st Qu.:2.80 1st Qu.:1.60 1st Qu.:0.3
# Median :5.80 Median :3.00 Median :4.35 Median :1.3
# Mean :5.84 Mean :3.05 Mean :3.76 Mean :1.2
# 3rd Qu.:6.40 3rd Qu.:3.30 3rd Qu.:5.10 3rd Qu.:1.8
# Max. :7.90 Max. :4.40 Max. :6.90 Max. :2.5
# Species
# setosa :50
# versicolor:50
# virginica :50
(3) skimr 高级摘要
install.packages("skimr")
library(skimr)
skim(iris)
# ── Data Summary ────────────────────────
# Values
# Number of rows 150
# Number of columns 5
# ── Variable type: factor ──
# Species: 1 unique, 50 each
# ── Variable type: numeric ──
# Sepal.Length: mean=5.84, sd=0.83, p0=4.3, p25=5.1, p50=5.8, p75=6.4, p100=7.9
# ...(每个变量 20+ 指标)
6. 步骤 3:缺失值分析
(1) 缺失值统计
# 模拟含缺失的数据
df <- data.frame(
a = c(1, 2, NA, 4),
b = c("x", NA, "z", "w"),
c = c(NA, 2, 3, NA)
)
# 缺失值数量
colSums(is.na(df))
# a b c
# 1 1 2
# 缺失值比例
colMeans(is.na(df)) * 100
# a b c
# 25 25 50
# 整行 NA
sum(!complete.cases(df)) # [1] 3
(2) naniar 高级缺失值可视化
install.packages("naniar")
library(naniar)
# 缺失值模式
vis_miss(iris) # iris 无缺失,会画空图
# 模拟含缺失
df_with_na <- iris
df_with_na[sample(150, 20), 1] <- NA
df_with_na[sample(150, 10), 3] <- NA
vis_miss(df_with_na)
# 缺失相关性
gg_miss_upset(df_with_na)
# 缺失 vs 变量关系
ggplot(df_with_na, aes(x = Sepal.Length, y = Petal.Length)) +
geom_miss_point() # 红点是缺失
7. 步骤 4:分布可视化
(1) 单变量分布
library(ggplot2)
# 直方图
ggplot(iris, aes(x = Sepal.Length)) +
geom_histogram(bins = 30, fill = "skyblue", color = "white") +
labs(title = "Sepal.Length 分布")
# 密度图
ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
geom_density(alpha = 0.5) +
labs(title = "按 Species 的 Sepal.Length 分布")
# 箱线图(识别异常值)
ggplot(iris, aes(y = Sepal.Length)) +
geom_boxplot(fill = "lightblue", outlier.color = "red") +
labs(title = "Sepal.Length 箱线图")
# 按组分箱线图
ggplot(iris, aes(x = Species, y = Sepal.Length, fill = Species)) +
geom_boxplot() +
labs(title = "按 Species 的 Sepal.Length 分布")
(2) 多变量分布
# 散点图 + 回归
ggplot(iris, aes(x = Sepal.Length, y = Petal.Length, color = Species)) +
geom_point(size = 3) +
geom_smooth(method = "lm", se = FALSE) +
labs(title = "Sepal vs Petal 长度")
# 成对图(散点图矩阵)
library(GGally)
ggpairs(iris, aes(color = Species))
(3) 相关矩阵
# Calculate相关系数
cor_matrix <- cor(iris |> select(-Species))
print(round(cor_matrix, 2))
# 可视化相关矩阵
library(corrplot)
corrplot(cor_matrix, method = "circle", type = "upper")
# ggplot2 版本
library(reshape2)
melted <- melt(cor_matrix)
ggplot(melted, aes(Var1, Var2, fill = value)) +
geom_tile() +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
8. 步骤 5:异常值检测
(1) IQR 法(最稳健)
detect_outliers <- function(x) {
q1 <- quantile(x, 0.25, na.rm = TRUE)
q3 <- quantile(x, 0.75, na.rm = TRUE)
iqr <- q3 - q1
lower <- q1 - 1.5 * iqr
upper <- q3 + 1.5 * iqr
x < lower | x > upper
}
# 应用
iris |>
mutate(across(where(is.numeric), detect_outliers, .names = "{.col}_out")) |>
select(ends_with("_out")) |>
summarise(across(everything(), sum))
# Sepal.Length_out Sepal.Width_out Petal.Length_out Petal.Width_out
# 0 4 0 0
(2) 3σ 法(仅正态数据)
detect_outliers_z <- function(x, threshold = 3) {
z <- (x - mean(x, na.rm = TRUE)) / sd(x, na.rm = TRUE)
abs(z) > threshold
}
9. 自动化 EDA
(1) DataExplorer
install.packages("DataExplorer")
library(DataExplorer)
# 1. 一行报告
create_report(iris, output_file = "eda_report.html")
# 2. 报告内容
plot_intro(iris) # 数据介绍
plot_missing(iris) # 缺失值
plot_histogram(iris) # 所有数值列直方图
plot_density(iris) # 密度图
plot_bar(iris) # 分类列条形图
plot_boxplot(iris) # 箱线图
plot_scatterplot(iris) # 散点图矩阵
plot_correlation(iris) # 相关矩阵
(2) SmartEDA
install.packages("SmartEDA")
library(SmartEDA)
ExpReport(iris, op_file = "smarteda_report.html")
ExpNumStat(iris) # 数值统计
ExpCatStat(iris) # 分类统计
10. 完整示例:iris + mpg 双数据集 EDA
下面是一个完整工作流示例,把本课所有 EDA 知识串起来。
▶ 示例:iris + mpg 双数据集完整 EDA
# ============================================
# iris + mpg 双数据集完整 EDA
# 功能:5 步 EDA 完整流程
# ============================================
library(ggplot2)
library(dplyr)
library(skimr)
library(naniar)
library(GGally)
# 1. 步骤 1:数据形状
cat("=== 步骤 1:数据形状 ===\n")
cat("iris:", nrow(iris), "行 ×", ncol(iris), "列\n")
cat("mpg:", nrow(mpg), "行 ×", ncol(mpg), "列\n\n")
# 2. 步骤 2:类型 + 摘要
cat("=== 步骤 2:类型与摘要 ===\n")
cat("iris 列类型:\n")
print(sapply(iris, class))
cat("\nmpg 列类型:\n")
print(sapply(mpg, class))
cat("\niris 摘要:\n")
print(summary(iris))
cat("\nmpg 摘要:\n")
print(summary(mpg |> select(displ, year, cyl, cty, hwy)))
# 3. 步骤 3:缺失值分析
cat("\n=== 步骤 3:缺失值 ===\n")
cat("iris 缺失值:", sum(is.na(iris)), "个\n")
cat("mpg 缺失值:", sum(is.na(mpg)), "个\n\n")
# 模拟含缺失数据
set.seed(42)
iris_na <- iris
iris_na[sample(150, 20), 1] <- NA
iris_na[sample(150, 10), 3] <- NA
vis_miss(iris_na, cluster = TRUE)
gg_miss_upset(iris_na)
# 4. 步骤 4:分布可视化
cat("\n=== 步骤 4:分布可视化 ===\n")
# 4.1 数值变量分布
iris |>
select(-Species) |>
pivot_longer(everything(), names_to = "variable", values_to = "value") |>
ggplot(aes(x = value)) +
geom_histogram(bins = 20, fill = "skyblue", color = "white") +
facet_wrap(~ variable, scales = "free") +
labs(title = "iris 4 个数值变量分布")
# 4.2 按组分
ggplot(iris, aes(x = Species, y = Sepal.Length, fill = Species)) +
geom_boxplot() +
labs(title = "按 Species 的 Sepal.Length 箱线图")
# 4.3 散点图矩阵
ggpairs(iris, aes(color = Species))
# 5. 步骤 5:相关矩阵
cat("\n=== 步骤 5:相关矩阵 ===\n")
cor_matrix <- cor(iris |> select(-Species))
print(round(cor_matrix, 2))
library(corrplot)
corrplot(cor_matrix, method = "circle", type = "upper",
addCoef.col = "black", number.cex = 0.8)
# 6. 异常值检测
cat("\n=== 步骤 6:异常值检测 ===\n")
detect_outliers <- function(x) {
q1 <- quantile(x, 0.25, na.rm = TRUE)
q3 <- quantile(x, 0.75, na.rm = TRUE)
iqr <- q3 - q1
lower <- q1 - 1.5 * iqr
upper <- q3 + 1.5 * iqr
sum(x < lower | x > upper, na.rm = TRUE)
}
iris |>
summarise(across(where(is.numeric), detect_outliers)) |>
print()
# 7. 自动化报告
cat("\n=== 步骤 7:自动化报告 ===\n")
library(DataExplorer)
create_report(iris, output_file = "iris_eda_report.html")
cat("iris_eda_report.html 已生成\n")
create_report(mpg, output_file = "mpg_eda_report.html")
cat("mpg_eda_report.html 已生成\n")
# 8. 业务洞察总结
cat("\n=== 业务洞察 ===\n")
cat("1. iris 4 数值变量均无缺失\n")
cat("2. Setosa 物种的 Petal.Length 显著小于其他两个\n")
cat("3. Petal.Length 和 Petal.Width 高度相关(0.96)\n")
cat("4. Sepal.Width 分布近似正态\n")
cat("5. mpg 11 数值变量,38 个车型\n")
预期输出:30+ 页 EDA HTML 报告 + 多个统计图表。
❓ 常见问题
📖 小节
- EDA 5 步法:形状 → 类型 → 缺失 → 分布 → 关系
- 形状:
dimnrowncolstr看数据规模 - 类型:
summaryskimr看每个变量统计 - 缺失:
colSums(is.na)计数 +naniar::vis_miss可视化 - 分布:
hist/boxplot/density单变量 +pairs/ggpairs多变量 - 相关:
cor()+corrplot可视化相关矩阵 - 异常值:IQR 法(稳健)< Q1 - 1.5×IQR 或 > Q3 + 1.5×IQR
- 自动化:
DataExplorer::create_report()一行生成完整 HTML 报告 - EDA 是建模前必做——不 EDA 不建模
- 相关 ≠ 因果——只有实验能证明因果
📝 作业
-
基础题:用 R 内置
mtcars数据集做完整 EDA:① 形状 ② 摘要 ③ 缺失 ④ 4 个数值变量直方图 ⑤ 相关矩阵。截图保存。 -
基础题:模拟 1 个含 20% 缺失值的数据框(1000 行 5 列),用
naniar::vis_miss()可视化缺失模式,对比 3 种处理策略(删除/均值填补/中位数填补)的效果。 -
基础题:用
iris画 4 个数值变量的相关矩阵(corrplot),找出 2 个最相关的变量对,验证散点图。 -
进阶题:用
mpg数据集做完整 EDA:① 形状 ② 摘要 ③ 按class分组的箱线图 ④ 按class的散点图矩阵 ⑤ 相关矩阵 ⑥ 自动化报告。截图保存。 -
挑战题:构造 1 个含 10000 行 20 列的混合数据集(含数值/分类/缺失/异常值),用
DataExplorer::create_report()生成完整 EDA 报告(HTML 30+ 页),并基于报告写 1 段业务洞察总结(500 字)。