如何重塑R DataFrame:将单行拆分为两行并迁移选项数据
如何将R中的选择实验宽数据重塑为长数据
这是个很常见的选择实验数据格式转换需求,我来给你分享两种实用的实现方法——用tidyverse工具包会非常简洁高效,偏好base R的话也能轻松搞定:
首先先把你提供的原始数据加载到R里:
# 原始输入数据 df <- structure(list(choice = structure(c(1L, 1L, 2L, 1L), .Label = c("option1", "option2"), class = "factor"), option1var1 = structure(c(1L, 1L, 1L, 1L), .Label = "A", class = "factor"), option1var2 = structure(c(1L, 1L, 1L, 2L), .Label = c("B", "H"), class = "factor"), option2var1 = structure(c(1L, 1L, 2L, 3L), .Label = c("C", "F", "I"), class = "factor"), option2var2 = structure(1:4, .Label = c("D", "E", "G", "K"), class = "factor")), .Names = c("choice", "option1var1", "option1var2", "option2var1", "option2var2"), class = "data.frame", row.names = c(NA, -4L))
方法一:用tidyverse(推荐)
tidyverse里的dplyr和tidyr组合是处理这类数据重塑的利器,代码简洁易懂:
library(tidyverse) long_df <- df %>% # 先给每个受访者生成唯一ID(用行号就行) mutate(respondent = row_number()) %>% # 核心步骤:把宽格式的option列转成长格式,同时拆分变量名 pivot_longer( cols = starts_with("option"), # 选中所有以option开头的列 names_to = c("option", ".value"), # 列名拆成两部分:option名称 + 属性变量名 names_pattern = "(option\\d)(var\\d)" # 正则表达式匹配列名结构(比如option1var1拆成option1和var1) ) %>% # 生成0/1的choice标记:当前option是受访者选的就标1,否则0 mutate(choice = as.integer(option == as.character(df$choice[respondent]))) %>% # 调整列顺序,和你要的目标结构对齐 select(respondent, choice, option, var1, var2) %>% # 把option转成因子,和目标数据结构一致 mutate(option = factor(option, levels = c("option1", "option2")))
运行完这段代码后,你直接str(long_df)就能看到结果和你期望的完全一致。
关键步骤说明
mutate(respondent = row_number()):给每行(每个受访者)生成唯一标识,这是目标数据里必须的列。pivot_longer:这是核心,通过正则表达式自动拆分列名,把option1和option2的对应属性合并到同一列,不用手动拆分再合并。mutate(choice = ...):通过匹配原始选择和当前行的option,快速生成数值型的选择标记。
方法二:用base R
如果你不想加载额外包,用base R的基础函数也能实现,思路是先分别处理两个option的数据,再合并:
# 先添加受访者ID df$respondent <- 1:nrow(df) # 处理option1的数据 option1_df <- df[, c("respondent", "choice", "option1var1", "option1var2")] names(option1_df)[3:4] <- c("var1", "var2") option1_df$option <- "option1" option1_df$choice <- as.integer(option1_df$choice == "option1") # 处理option2的数据 option2_df <- df[, c("respondent", "choice", "option2var1", "option2var2")] names(option2_df)[3:4] <- c("var1", "var2") option2_df$option <- "option2" option2_df$choice <- as.integer(option2_df$choice == "option2") # 合并两个数据框并排序,调整列顺序 long_df_base <- rbind(option1_df, option2_df) long_df_base <- long_df_base[order(long_df_base$respondent, long_df_base$option), ] long_df_base$option <- factor(long_df_base$option, levels = c("option1", "option2")) long_df_base <- long_df_base[, c("respondent", "choice", "option", "var1", "var2")]
这个方法虽然代码稍长,但逻辑很直观,适合不想依赖第三方包的场景。
内容的提问来源于stack exchange,提问作者KaC
相关产品推荐
相关产品推荐

