R对连续的重复行求和并删除除第一个以外的所有行
R sum consecutive duplicate rows and remove all but first
我遇到了一个可能很简单的问题 - 如何对连续的重复行求和并删除除第一行以外的所有行。并且,如果两个重复项之间有一个 NA
(例如 2,na,2
),也将它们相加并删除除第一个条目之外的所有条目。
到目前为止一切顺利,这是我的样本数据
ia<-c(1,1,2,NA,2,1,1,1,1,2,1,2)
time<-c(4.5,2.4,3.6,1.5,1.2,4.9,6.4,4.4, 4.7, 7.3,2.3, 4.3)
a<-as.data.frame(cbind(ia, time))
示例输出
a
ia time
1 1 4.5
2 1 2.4
3 2 3.6
4 NA 1.5
5 2 1.2
6 1 4.9
7 1 6.4
8 1 4.4
9 1 4.7
10 2 7.3
11 1 2.3
12 2 4.3
现在我想
1.) 对连续 ia 的 "time" 列求和 - 即,如果数字 1 紧接着出现两次或更多次,则对时间求和,在我的例子中,将列时间的第一行和第二行求和为 4.5+2.4
.
2.) 如果两个相同的数字(ia 列)之间有 NA
(i.e., ia = 2, NA, 2)
,则也将所有这些时间相加。
3.) 只保留第一次出现的 ia
,并删除其余的。
最后,我想要这样的东西:
a
ia time
1 1 6.9
3 2 6.3
6 1 20.4
10 2 7.3
11 1 2.3
12 2 4.3
我找到这个求和,但是没有考虑连续因子
aggregate(time~ia,data=a,FUN=sum)
我发现这个是为了删除
a[cumsum(rle(as.numeric(a[,1]))$lengths),]
虽然 rle 方法保留最后一个条目,但我想保留第一个。我也不知道如何处理 NAs
.
如果我有 1-NA-2
的模式,那么 NA
不应该与它们中的任何一个一起计算,在这种情况下,应该删除 NA
行。
nas <- which(is.na(df$ia))
add.index <- sapply(nas, function(x) {logi <- which(as.logical(df$ia))
aft <- logi[logi > x][1]
fore <- tail(logi[logi< x], 1)
if(df$ia[aft] == df$ia[fore]) aft else NA})
df$ia[nas] <- df$ia[add.index]
df <- df[complete.cases(df),]
首先我们判断列的NA值是否被同一个值包围。如果是,周围的值将替换 NA。如果数据有连续的NA值就没有问题。
接下来我们做一个标准的分组求和运算。 cumsum
允许我们根据数字的变化创建一个独特的组。
df$grps <- cumsum(c(F, !df$ia[-length(df$ia)] == df$ia[-1]))+1
aggregate(time ~ grps, df, sum)
# grps time
# 1 1 6.9
# 2 2 6.3
# 3 3 20.4
# 4 4 7.3
# 5 5 2.3
# 6 6 4.3
这是一种base R
方法。对于 dplyr
、zoo
或 data.table
等包,可以使用不同的选项,因为它们内置了专门的功能来完成我们在这里所做的事情。
您首先需要用它们周围的值替换 NA 序列(如果它们相同)。 This answer 显示动物园的 na.locf
函数,它用最后一次观察填充 NA。通过测试向后或向前携带值是否相同,可以过滤掉不需要的NA,然后进行向前携带:
library(dplyr)
library(zoo)
a %>%
filter(na.locf(ia) == na.locf(ia, fromLast = TRUE)) %>%
mutate(ia = na.locf(ia))
#> ia time
#> 1 1 4.5
#> 2 1 2.4
#> 3 2 3.6
#> 4 2 1.5
#> 5 2 1.2
#> 6 1 4.9
#> 7 1 6.4
#> 8 1 4.4
#> 9 2 7.3
#> 10 1 2.3
#> 11 2 4.3
现在您已经修复了这些 NA,您可以使用 cumsum
对连续的值集进行分组。完整的解决方案是:
result <- a %>%
filter(na.locf(ia) == na.locf(ia, fromLast = TRUE)) %>%
mutate(ia = na.locf(ia)) %>%
mutate(change = ia != lag(ia, default = FALSE)) %>%
group_by(group = cumsum(change), ia) %>%
summarise(time = sum(time))
result
#> Source: local data frame [6 x 3]
#> Groups: group [?]
#>
#> group ia time
#> (int) (dbl) (dbl)
#> 1 1 1 6.9
#> 2 2 2 6.3
#> 3 3 1 15.7
#> 4 4 2 7.3
#> 5 5 1 2.3
#> 6 6 2 4.3
如果要删除 group
列,请使用附加行:
result %>%
ungroup() %>%
select(-group)
使用 data.table
(如 RHertel 对 na.locf
的建议):
library(data.table)
library(zoo)
setDT(a)[na.locf(ia, fromLast=T)==na.locf(ia), sum(time), cumsum(c(T,!!diff(na.locf(ia))))]
# id V1
#1: 1 6.9
#2: 2 6.3
#3: 3 20.4
#4: 4 7.3
#5: 5 2.3
#6: 6 4.3
我遇到了一个可能很简单的问题 - 如何对连续的重复行求和并删除除第一行以外的所有行。并且,如果两个重复项之间有一个 NA
(例如 2,na,2
),也将它们相加并删除除第一个条目之外的所有条目。
到目前为止一切顺利,这是我的样本数据
ia<-c(1,1,2,NA,2,1,1,1,1,2,1,2)
time<-c(4.5,2.4,3.6,1.5,1.2,4.9,6.4,4.4, 4.7, 7.3,2.3, 4.3)
a<-as.data.frame(cbind(ia, time))
示例输出
a
ia time
1 1 4.5
2 1 2.4
3 2 3.6
4 NA 1.5
5 2 1.2
6 1 4.9
7 1 6.4
8 1 4.4
9 1 4.7
10 2 7.3
11 1 2.3
12 2 4.3
现在我想
1.) 对连续 ia 的 "time" 列求和 - 即,如果数字 1 紧接着出现两次或更多次,则对时间求和,在我的例子中,将列时间的第一行和第二行求和为 4.5+2.4
.
2.) 如果两个相同的数字(ia 列)之间有 NA
(i.e., ia = 2, NA, 2)
,则也将所有这些时间相加。
3.) 只保留第一次出现的 ia
,并删除其余的。
最后,我想要这样的东西:
a
ia time
1 1 6.9
3 2 6.3
6 1 20.4
10 2 7.3
11 1 2.3
12 2 4.3
我找到这个求和,但是没有考虑连续因子
aggregate(time~ia,data=a,FUN=sum)
我发现这个是为了删除
a[cumsum(rle(as.numeric(a[,1]))$lengths),]
虽然 rle 方法保留最后一个条目,但我想保留第一个。我也不知道如何处理 NAs
.
如果我有 1-NA-2
的模式,那么 NA
不应该与它们中的任何一个一起计算,在这种情况下,应该删除 NA
行。
nas <- which(is.na(df$ia))
add.index <- sapply(nas, function(x) {logi <- which(as.logical(df$ia))
aft <- logi[logi > x][1]
fore <- tail(logi[logi< x], 1)
if(df$ia[aft] == df$ia[fore]) aft else NA})
df$ia[nas] <- df$ia[add.index]
df <- df[complete.cases(df),]
首先我们判断列的NA值是否被同一个值包围。如果是,周围的值将替换 NA。如果数据有连续的NA值就没有问题。
接下来我们做一个标准的分组求和运算。 cumsum
允许我们根据数字的变化创建一个独特的组。
df$grps <- cumsum(c(F, !df$ia[-length(df$ia)] == df$ia[-1]))+1
aggregate(time ~ grps, df, sum)
# grps time
# 1 1 6.9
# 2 2 6.3
# 3 3 20.4
# 4 4 7.3
# 5 5 2.3
# 6 6 4.3
这是一种base R
方法。对于 dplyr
、zoo
或 data.table
等包,可以使用不同的选项,因为它们内置了专门的功能来完成我们在这里所做的事情。
您首先需要用它们周围的值替换 NA 序列(如果它们相同)。 This answer 显示动物园的 na.locf
函数,它用最后一次观察填充 NA。通过测试向后或向前携带值是否相同,可以过滤掉不需要的NA,然后进行向前携带:
library(dplyr)
library(zoo)
a %>%
filter(na.locf(ia) == na.locf(ia, fromLast = TRUE)) %>%
mutate(ia = na.locf(ia))
#> ia time
#> 1 1 4.5
#> 2 1 2.4
#> 3 2 3.6
#> 4 2 1.5
#> 5 2 1.2
#> 6 1 4.9
#> 7 1 6.4
#> 8 1 4.4
#> 9 2 7.3
#> 10 1 2.3
#> 11 2 4.3
现在您已经修复了这些 NA,您可以使用 cumsum
对连续的值集进行分组。完整的解决方案是:
result <- a %>%
filter(na.locf(ia) == na.locf(ia, fromLast = TRUE)) %>%
mutate(ia = na.locf(ia)) %>%
mutate(change = ia != lag(ia, default = FALSE)) %>%
group_by(group = cumsum(change), ia) %>%
summarise(time = sum(time))
result
#> Source: local data frame [6 x 3]
#> Groups: group [?]
#>
#> group ia time
#> (int) (dbl) (dbl)
#> 1 1 1 6.9
#> 2 2 2 6.3
#> 3 3 1 15.7
#> 4 4 2 7.3
#> 5 5 1 2.3
#> 6 6 2 4.3
如果要删除 group
列,请使用附加行:
result %>%
ungroup() %>%
select(-group)
使用 data.table
(如 RHertel 对 na.locf
的建议):
library(data.table)
library(zoo)
setDT(a)[na.locf(ia, fromLast=T)==na.locf(ia), sum(time), cumsum(c(T,!!diff(na.locf(ia))))]
# id V1
#1: 1 6.9
#2: 2 6.3
#3: 3 20.4
#4: 4 7.3
#5: 5 2.3
#6: 6 4.3