从开始/结束间隔点扩展有序的代码系列

时间:2016-03-21 22:56:12

标签: r dataframe

我有一个以下类型的数据框

> foo <- data.frame(start = c(7, 12, 23, 30), end = c(10, 16, 27, 35), code = rep("A", 4))
> foo
  start end code
1     7  10    A
2    12  16    A
3    23  27    A
4    30  35    A

我的目标是创建一个新的数据框series,它扩展先前在开始/结束点压缩的有序系列,同时包含{{1}中编码区间之外的点的代码B. }}:

foo

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:3)

您可以使用Map,这是lapply的多变量版本:

foo2 <- do.call(rbind, Map(function(s, e, c){data.frame(time = seq(s, e), 
                                                        code = c)}, 
                           foo$start, foo$end, foo$code))
head(foo2, 10)
#    time code
# 1     7    A
# 2     8    A
# 3     9    A
# 4    10    A
# 5    12    A
# 6    13    A
# 7    14    A
# 8    15    A
# 9    16    A
# 10   23    A

该函数将time作为seqstart添加到end的数据框架和code作为该行的代码。 do.call(rbind捕获从每一行创建的data.frames并重新组合它们。

然后,我们可以使用mergeis.na填充剩余的级别:

foo3 <- merge(foo2, data.frame(time = 1:max(foo$end)), all.y = TRUE)
foo3$code <- as.character(foo3$code)    # change from factor to character
foo3$code[is.na(foo3$code)] <- 'B'
head(foo3, 10)
#    time code
# 1     1    B
# 2     2    B
# 3     3    B
# 4     4    B
# 5     5    B
# 6     6    B
# 7     7    A
# 8     8    A
# 9     9    A
# 10   10    A

如果您希望将数据保持为系数(合理),则可以在合并后替换两行:

foo3$code <- factor(foo3$code, levels = c('A', NA), labels = c('A', 'B'), exclude = NULL)

是等效的,除了将避免转换为vector。

如果你不介意code是一个角色向量而你只有 得到的代码是&#34; A&#34;和&#34; B&#34;,您实际上可以从完整的data.frame向后工作,然后通过使用"A"汇编序列重新插入apply值,这有点简单:< / p>

foo4 <- data.frame(time = seq(1, max(foo$end)), code = 'B', stringsAsFactors = FALSE)
foo4$code[unlist(apply(foo[,1:2], 1, function(x){seq(x[1], x[2])}))] <- 'A'

答案 1 :(得分:2)

另一种选择,使用data.table

library(data.table)
# create a new table with time and code columns
bar <- data.table(time = 1:max(foo$end), code = "A")
# sub-assign "B" to code column
bar[!time %in% foo[,list(start:end), by = 1:nrow(foo)]$V1, code := "B"]

答案 2 :(得分:0)

使用一些sequencerep吃:

out <- data.frame(
  time=seq(1, max(foo$end)),
  code="B",
  stringsAsFactors=FALSE
)

cnts <- foo$end - foo$start + 1
out$code[sequence(cnts) + rep(foo$start, cnts) - 1] <- as.character(rep(foo$code, cnts))

out

#   time code
#1     1    B
#2     2    B
#3     3    B
#4     4    B
#5     5    B
#6     6    B
#7     7    A
#8     8    A
#9     9    A
#10   10    A
#11   11    B
#...