两个额外的选项(带有一个多行的示例数据框,以更好地显示代码的工作):
1) 以 R 为底:
l <- lapply(split.default(d[-1], cumsum(grepl('Start$', names(d)[-1]))),
setNames, c('DateRangeStart','DateRangeEnd','Value'))
data.frame(ID = d[,1], do.call(rbind, l), row.names = NULL)
这使:
ID DateRangeStart DateRangeEnd Value
1 1 1/1/90 3/1/90 4.4
2 2 1/2/90 3/2/90 6.1
3 1 4/5/91 6/7/91 6.2
4 2 4/6/91 6/8/91 3.2
5 1 5/5/95 6/6/96 3.3
6 2 5/5/97 6/6/98 1.3
2)与tidyverse
:
library(dplyr)
library(purrr)
split.default(d[-1], cumsum(grepl('Start$', names(d)[-1]))) %>%
map_dfr(~set_names(., c('DateRangeStart','DateRangeEnd','Value'))) %>%
bind_cols(ID = rep(d$ID, nrow(.)/nrow(d)), .)
3)使用sjmisc
-package:
library(sjmisc)
to_long(d, keys = 'group',
values = c('DateRangeStart','DateRangeEnd','Value'),
c('DateRange1Start','DateRange2Start','DateRange3Start'),
c('DateRange1End','DateRange2End','DateRange3End'),
c('Value1','Value2','Value3'))[,-2]
如果您还想要一个组/时间列,您可以将上述方法调整为:
1) 以 R 为底:
l <- lapply(split.default(d[-1], cumsum(grepl('Start$', names(d)[-1]))),
setNames, c('DateRangeStart','DateRangeEnd','Value'))
data.frame(ID = d[,1],
group = rep(seq_along(l), each = nrow(d)),
do.call(rbind, l), row.names = NULL)
这使:
ID group DateRangeStart DateRangeEnd Value
1 1 1 1/1/90 3/1/90 4.4
2 2 1 1/2/90 3/2/90 6.1
3 1 2 4/5/91 6/7/91 6.2
4 2 2 4/6/91 6/8/91 3.2
5 1 3 5/5/95 6/6/96 3.3
6 2 3 5/5/97 6/6/98 1.3
2)与tidyverse
:
split.default(d[-1], cumsum(grepl('Start$', names(d)[-1]))) %>%
map_dfr(~set_names(., c('DateRangeStart','DateRangeEnd','Value'))) %>%
bind_cols(ID = rep(d$ID, nrow(.)/nrow(d)),
group = rep(1:(nrow(.)/nrow(d)), each = nrow(d)), .)
3)使用sjmisc
-package:
library(sjmisc)
to_long(d, keys = 'group', recode.key = TRUE,
values = c('DateRangeStart','DateRangeEnd','Value'),
c('DateRange1Start','DateRange2Start','DateRange3Start'),
c('DateRange1End','DateRange2End','DateRange3End'),
c('Value1','Value2','Value3'))
使用数据:
d <- read.table(text = "ID DateRange1Start DateRange1End Value1 DateRange2Start DateRange2End Value2 DateRange3Start DateRange3End Value3
1 1/1/90 3/1/90 4.4 4/5/91 6/7/91 6.2 5/5/95 6/6/96 3.3
2 1/2/90 3/2/90 6.1 4/6/91 6/8/91 3.2 5/5/97 6/6/98 1.3", header = TRUE, stringsAsFactors = FALSE)