如何用tidyverse在R中将竖线分隔列表转为长格式?
R数据框拆分与格式转换解决方案
原始数据
foo <- data.frame(x=c(1,2,3), y=c("a", "b|c", "d|e|f")) foo # x y # 1 1 a # 2 2 b|c # 3 3 d|e|f
需求1:转换为长格式
目标输出:
foo_long <- data.frame(x=c(1,2,2,3,3,3), y=c("a", "b", "c", "d", "e", "f")) foo_long # x y # 1 1 a # 2 2 b # 3 2 c # 4 3 d # 5 3 e # 6 3 f
当前进度
已通过str_split将y列拆分为列表列,但未展开:
foo_long <- foo %>% mutate(y=str_split(y, "\\|")) foo_long # x y # 1 1 a # 2 2 b, c # 3 3 d, e, f str(foo_long) # 'data.frame': 3 obs. of 2 variables: # $ x: num 1 2 3 # $ y:List of 3 # ..$ : chr "a" # ..$ : chr "b" "c" # ..$ : chr "d" "e" "f"
实现方法
方法1:tidyverse管道式实现
使用tidyr::unnest()直接展开列表列:
library(tidyr) library(dplyr) foo_long <- foo %>% mutate(y = str_split(y, "\\|")) %>% unnest(y)
方法2:基础R实现
通过重复x值+拆分展开y值:
y_split <- strsplit(foo$y, "\\|") foo_long <- data.frame( x = rep(foo$x, sapply(y_split, length)), y = unlist(y_split) )
需求2:转换为二进制宽格式(补充需求)
目标输出:
foo_long2 <- data.frame(x=c(1,2,3), a=c(1,0,0), b=c(0,1,0), c=c(0,1,0), d=c(0,0,1), e=c(0,0,1), f=c(0,0,1)) foo_long2 # x a b c d e f # 1 1 1 0 0 0 0 0 # 2 2 0 1 1 0 0 0 # 3 3 0 0 0 1 1 1
实现方法
方法1:tidyverse管道式实现
先转长格式,再用pivot_wider生成二进制列:
foo_long2 <- foo %>% mutate(y = str_split(y, "\\|")) %>% unnest(y) %>% mutate(value = 1) %>% pivot_wider(names_from = y, values_from = value, values_fill = 0) %>% as.data.frame() # 若需转换为普通data.frame而非tibble
方法2:基础R实现
手动初始化矩阵并填充值:
# 获取所有唯一的y类别 all_y <- unique(unlist(strsplit(foo$y, "\\|"))) # 创建结果数据框 foo_long2 <- data.frame( x = foo$x, matrix(0, nrow = nrow(foo), ncol = length(all_y)) ) colnames(foo_long2)[-1] <- all_y # 为对应位置填充1 for(i in seq(nrow(foo))){ y_vals <- strsplit(foo$y[i], "\\|")[[1]] foo_long2[i, y_vals] <- 1 }
内容的提问来源于stack exchange,提问作者dfrankow
相关产品推荐
相关产品推荐

