R连续重复行并删除除

时间:2015-09-15 14:16:41

标签: r dataframe duplicates na

我遇到了一个可能很简单的问题 - 如何对连续的重复行进行求和并删除除第一行之外的所有行。并且,如果两个重复项之间存在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.)总结&#34;时间&#34;连续ia的列 - 即,如果数字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行。

3 个答案:

答案 0 :(得分:5)

使用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

答案 1 :(得分:3)

首先需要用它们周围的值替换NAs序列(如果它们是相同的)。 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)

答案 2 :(得分:2)

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方法。使用dplyrzoodata.table等软件包可以使用不同的选项,因为它们构建了专门的功能来完成我们在此处所做的工作。