我想添加一个计算连续值数的列。 我在这里看到的大部分是如何计算重复值 (1,1,1,1,1(,我想在数字上升 1 时计算 a ( 5,6,7,8,9(。 ID列是我所拥有的,计数器列是我想创建的。 谢谢!
ID Counter
5 1
6 2
7 3
8 4
10 1
11 2
13 1
14 2
15 3
16 4
使用dplyr
包的解决方案。这个想法是计算每个数字之间的差异以创建一个分组列,然后为每个组分配计数器。
library(dplyr)
dat2 <- dat %>%
mutate(Diff = ID - lag(ID, default = 0),
Group = cumsum(Diff != 1)) %>%
group_by(Group) %>%
mutate(Counter = row_number()) %>%
ungroup() %>%
select(-Diff, -Group)
dat2
# # A tibble: 10 x 2
# ID Counter
# <int> <int>
# 1 5 1
# 2 6 2
# 3 7 3
# 4 8 4
# 5 10 1
# 6 11 2
# 7 13 1
# 8 14 2
# 9 15 3
# 10 16 4
数据
dat <- read.table(text = "ID
5
6
7
8
10
11
13
14
15
16",
header = TRUE, stringsAsFactors = FALSE)
循环版本很简单:
for (i in 2:length(ID))
if (diff(ID)[i-1] == 1)
counter[i] <- counter[i-1] +1
else
counter[i] <- 1
但是这个循环对于 n> 10^4 的表现会非常糟糕!我会试着想一个矢量解决方案!
您可以使用
s=df$ID-shift(df$ID)
s[is.na(s)]=1
ave(s,cumsum(s!=1),FUN=seq_along)
[1] 1 2 3 4 1 2 1 2 3 4
这个只使用高效的向量算术。思路如下:
1.取ID差额的累计和
2.如果跳跃大于 1,则减去该值
cum <- c(0, cumsum(diff(ID))) # take the cumulative difference of ID
ccm <- cum * c(1, (diff(ID) > 1)) # those with jump > 1 will remain its value
# subtract value with jump > 1 for all following numbers (see Link for reference)
# note: rep(0, n) is because ccm[...] starts at first non null value
counter <- cum - c(rep(0, which(diff(dat) != 1)[1]),
ccm[which(ccm != 0)][cumsum(ccm != 0)]) + 1
enter code here
注释:
nacnudus 的高效填充函数参考:使用上面行的值填充数据框
限制:Id 必须单调递增
这应该可以有效地处理您的数百万数据!
另一种解决方案:
breaks <- c(which(diff(ID)!=1), length(ID))
x <- c(breaks[1], diff(breaks))
unlist(sapply(x, seq_len))