我有这个例子data.frame:
my.df = data.frame(id = rep("a",10), start = seq(100, 1000, 100), end = seq(150, 1050, 100), flag = c(1,0,0,1,0,1,0,1,0,1))
> my.df
id start end flag
1 a 100 150 1
2 b 200 250 0
3 c 300 350 0
4 d 400 450 1
5 e 500 550 0
6 f 600 650 1
7 g 700 750 0
8 h 800 850 1
9 i 900 950 0
10 j 1000 1050 1
行是线性间隔,按my.df$start
排序,然后按升序排序my.df$end
。请注意,根据定义,任何两行my.df$flag
= 1的行都至少有一行,my.df$flag
= 0。
我想要的是以下列方式更新my.df$id
字段:
首先,使用my.df$flag
= 1更新行,以便my.df$flag
= 1行的任何外观都会将该行的更新my.df$id
字段从ai增加到a.i +1,其中i是一个初始化为0的整数。
然后,需要以下列方式更新my.df$flag
= 0的所有行:
从my.df
开头到my.df$flag
= 1的第一行的行将my.df$id
= a.1。任何两行my.df$flag
= 1的行(即任何两行my.df$flag
= 1 ai和a.i + 1)my.df$start
小于mid的行my.df$id
= ai的结尾与my.df$id
的开头之间的点= a.i + my.df$flag
= 1的两行中的1将使用my.df$id
= ai更新my.df$start
大于或等于相同中点的行将使用my.df$id
= a.i + 1进行更新。从my.df$flag
= 1的最后一行到my.df的最后一行之后my.df$flag
= 0的行将具有my.df$id
的最后一行的my.df$flag
值= 1.请注意,my.df
的第一行和/或最后一行可能实际上是my.df$flag
= 1的行。
因此,此示例的输出应为:
> my.updated.df
id start end flag
1 a.1 100 150 1
2 a.1 200 250 0
3 a.2 300 350 0
4 a.2 400 450 1
5 a.2 500 550 0
6 a.3 600 650 1
7 a.3 700 750 0
8 a.4 800 850 1
9 a.4 900 950 0
10 a.5 1000 1050 1
答案 0 :(得分:1)
您可以使用cumsum
上的d$flag
将数据拆分为“数据块”。对于其中的每一个,您将计算“结束”和“开始”之间的中点,并使用它来通过将其与d$id
进行比较来定义d$start
。我稍微修改了您的示例数据框,以便包含flag = 0
行出现在第一个flag=1
之前和最后一个flag=1
之后的边缘情况。请注意,如果d$id
是您示例my.df
中的一个因素,我们首先需要将其转换为字符才能使其生效(d$id <- as.character(d$id)
)。
d <- structure(list(id = c("a", "a", "a", "a", "a", "a", "a", "a",
"a", "a", "a", "a"), start = c(100, 100, 200, 300, 400, 500,
600, 700, 800, 900, 1000, 1000), end = c(110, 150, 250, 350,
450, 550, 650, 750, 850, 950, 1050, 1100), flag = c(0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0)), .Names = c("id", "start", "end",
"flag"), row.names = c(NA, 12L), class = "data.frame")
# Create a 'subset index'. Rows with the same index will be
# compared to the same midpoint.
d$subset.idx <- cumsum(d$flag)
# For each index, compute the midpoint that the 'start'
# value of each row with that index needs to be compared to
mid <- d[d$flag == 1, ]
mid$midpoint <- c((mid$start[2:nrow(mid)] - mid$end[1:(nrow(mid) - 1)]) / 2 +
mid$end[1:(nrow(mid) - 1)], 0)
mid <- mid[c("subset.idx", "midpoint")]
mid <- rbind(c(0, 0), mid) # before merging with d, add a row for subset.idx = 0
# Merge with d and assign id by comparing start to midpoint
d <- merge(d, mid)
d$id <- ifelse(d$start < d$midpoint,
paste0("a.", d$subset.idx),
paste0("a.", d$subset.idx + 1))
# Finally, handle edge cases, i.e. those with flag 0 before and after
# the first and last flag = 1 respectively
d[d$subset.idx == 0, "id"] <- "a.1"
d[d$subset.idx == max(d$subset.idx), "id"] <- paste0("a.", max(d$subset.idx))
d <- d[- which(names(d) %in% c("subset.idx", "midpoint"))]