R语言纵向数据分析实战:从宽数据到长数据的3步转换与4种可视化
2026/7/9 22:56:05 网站建设 项目流程

R语言纵向数据分析实战:从宽数据到长数据的3步转换与4种可视化

纵向数据在医学研究、心理学实验和社会学调查中无处不在。想象一下,你手头有一份记录了500名患者在不同时间点的抑郁评分数据,或者是一组学生在连续三个学期的考试成绩。这类数据最迷人的地方在于,它们能揭示个体随时间变化的轨迹——就像给每个研究对象拍摄了一段"成长纪录片"。

但现实往往骨感。当你兴奋地打开数据集,看到的可能是这样的结构:

患者ID性别基线评分3个月评分6个月评分
001231815
002282219

这种"宽格式"数据就像把多部电影胶片横向拼接在一起,虽然节省空间,却让时间维度的分析变得棘手。本文将带你用R语言的tidyrggplot2工具包,完成从数据整理到可视化的完整工作流。

1. 数据转换:三步骤重塑时间维度

1.1 理解长宽数据差异

宽格式数据的特点是:

  • 每个时间点的测量值占据单独一列
  • 时间信息隐藏在列名中(如"基线评分"、"3个月评分")
  • 适合人类阅读但不利于分析

长格式数据的优势在于:

  • 每个时间点的测量值独占一行
  • 显式的时间变量列
  • 适合统计建模和可视化

1.2 核心转换代码

使用tidyr::pivot_longer()完成转换:

library(tidyverse) # 示例牙科生长数据集 dental_wide <- data.frame( id = 1:10, sex = rep(c("男", "女"), each=5), y8 = rnorm(10, 25, 2), y10 = rnorm(10, 28, 2), y12 = rnorm(10, 30, 2) ) dental_long <- dental_wide %>% pivot_longer( cols = starts_with("y"), # 选择需要转换的列 names_to = "age", # 新列名:存储原列名 values_to = "distance" # 新列名:存储原数值 ) %>% mutate( age = parse_number(age), # 从"y8"提取数字8 age_factor = factor(paste(age, "岁")) # 创建因子型年龄 )

转换后的数据结构:

idsexagedistanceage_factor
1824.58 岁
11027.810 岁

1.3 处理常见问题

问题1:列名模式不一致当时间点列名没有统一前缀时:

# 不规则列名处理示例 df_long <- df_wide %>% pivot_longer( cols = c(基线评分, 三月随访, 六月随访), names_to = "时间点", values_to = "评分" )

问题2:需要保留元数据添加变量标签保持数据可读性:

library(labelled) dental_long <- dental_long %>% set_variable_labels( age = "测量时年龄(岁)", distance = "牙齿生长距离(mm)" )

2. 探索性分析:四类可视化揭示时间模式

2.1 意大利面条图(Spaghetti Plot)

展示个体轨迹的经典方法:

ggplot(dental_long, aes(x = age, y = distance, group = id)) + geom_line(alpha = 0.5) + labs(x = "年龄(岁)", y = "生长距离(mm)") + theme_minimal()

当样本量较大时(>50),建议添加趋势线:

ggplot(dental_long, aes(x = age, y = distance)) + geom_line(aes(group = id), alpha = 0.2) + geom_smooth(method = "lm", se = FALSE, color = "red", size = 1.5) + facet_wrap(~ sex) # 按性别分面

2.2 分组箱线图

比较不同时间点的分布差异:

ggplot(dental_long, aes(x = age_factor, y = distance, fill = sex)) + geom_boxplot() + geom_jitter(width = 0.1, alpha = 0.3) + # 添加数据点 scale_fill_manual(values = c("#E69F00", "#56B4E9")) + labs(x = "", y = "牙齿生长距离(mm)", fill = "性别")

关键参数说明:

  • width: 控制箱线图宽度
  • alpha: 调整透明度避免重叠
  • position_dodge: 分组并列显示

2.3 相关性矩阵

检验不同时间点测量值的关联强度:

library(GGally) # 使用宽格式数据 ggpairs(dental_wide, columns = 3:5, # 选择需要分析的列 mapping = aes(color = sex), lower = list(continuous = wrap("smooth", alpha = 0.3)))

输出解读:

  • 对角线:变量分布直方图
  • 下三角:散点图与平滑曲线
  • 上三角:相关系数及显著性

2.4 时间轨迹图

展示群体平均变化趋势:

dental_long %>% group_by(sex, age) %>% summarise( mean = mean(distance), se = sd(distance)/sqrt(n()) ) %>% ggplot(aes(x = age, y = mean, color = sex)) + geom_line() + geom_point(size = 3) + geom_errorbar(aes(ymin = mean - 1.96*se, ymax = mean + 1.96*se), width = 0.2) + scale_x_continuous(breaks = unique(dental_long$age)) + labs(x = "年龄(岁)", y = "平均生长距离(mm)", color = "性别")

3. 进阶技巧:提升分析深度的实用方法

3.1 处理缺失数据

纵向数据常见缺失模式及处理:

缺失类型R代码示例适用场景
列表删除na.omit()缺失较少时
线性插补approx()连续变量
多重插补mice::mice()复杂缺失
# 线性插补示例 dental_complete <- dental_long %>% group_by(id) %>% mutate( distance = approx(age, distance, xout = age)$y ) %>% ungroup()

3.2 添加参考线

增强可视化解释性:

ggplot(dental_long, aes(x = age, y = distance)) + geom_hline(yintercept = 25, linetype = "dashed", color = "gray") + geom_vline(xintercept = 10, linetype = "dotted", color = "blue") + # ...其他图层

3.3 交互式可视化

plotly创建动态图表:

library(plotly) p <- ggplot(dental_long, aes(x = age, y = distance, color = sex)) + geom_line(aes(group = id), alpha = 0.3) + geom_smooth(se = FALSE) ggplotly(p)

4. 案例实战:牙科生长数据分析全流程

4.1 数据准备

加载内置数据集并转换:

data("Orthodont", package = "nlme") ortho_long <- Orthodont %>% mutate( Subject = as.character(Subject), age = age - 8 # 以8岁为基准 )

4.2 可视化组合

创建多面板图形:

library(patchwork) p1 <- ggplot(ortho_long, aes(x = age, y = distance, group = Subject)) + geom_line(alpha = 0.5) p2 <- ggplot(ortho_long, aes(x = age, y = distance, fill = Sex)) + geom_boxplot() p3 <- ggplot(ortho_long, aes(x = distance, fill = Sex)) + geom_density(alpha = 0.5) + facet_wrap(~ age) (p1 + p2) / p3 # 使用patchwork组合图形

4.3 统计摘要

生成专业统计表格:

ortho_long %>% group_by(Sex, age) %>% summarise( Mean = mean(distance), SD = sd(distance), N = n(), .groups = "drop" ) %>% knitr::kable(digits = 2)

输出示例:

SexageMeanSDN
022.881.5216
123.811.6016

在RMarkdown环境中,添加kableExtra::kable_styling()可以让表格更美观。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询