【问题标题】:R sum consecutive duplicate rows and remove all but firstR对连续重复行求和并删除除第一个之外的所有行
【发布时间】:2015-12-11 20:23:36
【问题描述】:

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

【问题讨论】:

  • 如果你有1-NA-2的模式呢? NA 应该计为 1、2 还是两者都不计?另外,是否连续有多个 NA?
  • 如果我有 1-NA-2 的模式,那么 NA 不应该与它们中的任何一个一起计算,在这种情况下应该删除 NA。是的,连续也可能有多个 NA。
  • 澄清一下:当我说连续不止一个 NA 时,我的意思是连续不止一个 NA。例如,是否有可能在序列中有1 NA NA 1?在这种情况下,NA应该算作1吗?
  • 有可能依次出现1 NA NA NA 1。在这种情况下,NA 应计为 1。
  • 太棒了。我在下面的回答(以及Colonel Beauvel's)处理这个

标签: r dataframe duplicates na


【解决方案1】:

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

【讨论】:

  • 这会将值向前传递,即使它们后面跟着不同的值,这违反了here 描述的行为。例如,用a &lt;- data.frame(ia = c(1, NA, 2), time = 1) 试试这个
【解决方案2】:

您首先需要将 NA 序列替换为它们周围的值(如果它们相同)。 This answer 显示了 zoo 的 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)

【讨论】:

  • 您好,再次感谢您的帮助。我想知道如何处理额外的列 - 比如说我在数据框 z
  • @LaNeu 你可以添加z = z[1] 作为总结的参数
  • 当我运行这个例子时,我没有得到相应的输出。我只得到一个值:汇总时间。我做错了什么?
  • @team17 这很奇怪,我无法重现。您使用的是什么版本的 dplyr? (如果它是来自 GitHub 的开发版本,你是什么时候安装的?)
【解决方案3】:
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,则此解决方案不起作用。
  • @DavidRobinson 我在第 4 行用两个 NA 值测试了你的函数。对于值 2 NA 返回。根据 OP 的期望输出,这不会发生。使用我的解决方案 4.8 返回。
  • 我对“行”这个词的误解。我的意思不是数据框的一行中有两个以上的 NA。我的意思是ia 列中连续两个以上的 NA,例如,如果 a$ia[4] 和 a$ia[5] 都是 NA。 (即the idiom "in a row")
  • 非常感谢您的帮助!!但是,如果我有ia&lt;-c(1,1,2,NA,2,1,NA,NA,1,2,1,2),然后在同一时间,它不会正确计算第二组连续 NA 的总和 - 在这个特定的例子中,它计算 1+NA,删除第二个 NA 然后去到下一个数字。
  • 已更新。我知道已选择了一个答案,但我很想知道这是否适合您。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-21
  • 2021-01-28
  • 2010-09-27
  • 2019-11-14
  • 1970-01-01
  • 2013-03-23
  • 1970-01-01
相关资源
最近更新 更多