【问题标题】:how to sum up specific cells of a column based on conditions from another column in R?如何根据R中另一列的条件总结一列的特定单元格?
【发布时间】:2016-12-30 18:00:22
【问题描述】:

我有一个小问题。我正在研究一个数据框。如下:

df1
Duration    Intensity
NA             NA
10           0.1016
10           0.0254
NA             NA
NA             NA
10           0.0508
10           0.0508
10           0.1016
NA             NA
10           0.0254

我想计算 10 分钟“持续时间”的每个事件的“强度”累积总和。或者换句话说,我想总结“强度”列中每个“NA”值之间的“强度”值。输出应如下所示:

df2

Duration    Intensity   Intensity_sum
NA             NA   
10           0.1016 
10           0.0254        0.127
NA             NA   
NA             NA   
10           0.0508 
10           0.0508 
10           0.1016        0.2032
NA             NA   
10           0.0254        0.0254

我尝试了以下代码:

library(dplyr)    
df2 <- as.data.frame(mutate(df1,Intensity_sum = with(df1,Duration==10,cumsum(Intensity))))

但我只收到 TRUE 或 FALSE 结果,而不是值。

【问题讨论】:

  • @nrussell 有点像,除了 OP 必须首先构建组 ID,并且还必须“合并”聚合总和到每个组的最终观察。
  • @nrussell 谢谢,但我的问题和那个不完全一样

标签: r sum dplyr


【解决方案1】:

我们可以使用data.table。将 'data.frame' 转换为 'data.table' (setDT(df1)),按逻辑向量 (!is.na(Duration)) 的 run-length-id 分组,我们分配 (:=) 'Intensity'的sum ' 作为带有 'NA' 的 'Intensity_sumand later replace theduplicated` 元素

library(data.table)
setDT(df1)[, Intensity_sum := sum(Intensity), rleid(!is.na(Duration))]
df1[duplicated(Intensity_sum, fromLast=TRUE), Intensity_sum := NA]
df1
#     Duration Intensity Intensity_sum
# 1:       NA        NA            NA
# 2:       10    0.1016            NA
# 3:       10    0.0254        0.1270
# 4:       NA        NA            NA
# 5:       NA        NA            NA
# 6:       10    0.0508            NA
# 7:       10    0.0508            NA
# 8:       10    0.1016        0.2032
# 9:       NA        NA            NA
#10:       10    0.0254        0.0254

或者在一行中,我们可以按rleid(如上所述)进行分组,并通过复制NA 以及“强度”的sum 来分配新列

setDT(df1)[, Intensity_sum := rep(c(NA,sum(Intensity)), c(.N-1, 1)), rleid(!is.na(Duration))]

【讨论】:

    【解决方案2】:

    使用下面我建议的第四个data.table方法,可以在base R中达到预期的结果。这个方法使用avereplace

    ave(df$Intensity, cumsum(is.na(df$Intensity)),
        FUN=function(x) replace(NA, (seq_along(x) == length(x) & length(x) > 1),
                                sum(x, na.rm=TRUE)))
     [1]     NA     NA 0.1270     NA     NA     NA     NA 0.2032     NA 0.0254
    

    这里有一些额外的data.table 选项

    df[, val := ifelse(is.na(shift(Intensity, type="lead")),
       sum(Intensity, na.rm=TRUE), NA), by=cumsum(is.na(Intensity))]
    

    在这种情况下,使用cumsum 函数执行分组,并使用ifelse 执行总和的放置,该shift 使用shift 检查NA 边界。

    这有点慢,如果有一个带有相邻数值的 NA 值,它将添加 0 而不是 NA。 ifelse 的第一个参数可以修改,这样就不会发生。

    第二,使用c 和子集而不是ifelse 的更快解决方案。我添加了逻辑,以便单行 NA 将接收和 NA 而不是 0。

    df[, val2 := c(NA, sum(Intensity, na.rm=TRUE))[(seq_len(.N) == .N &.N > 1) + 1],
       by=cumsum(is.na(Intensity))]
    

    稍微修改此方法以利用最喜欢的NA 操作。我们得到以下结果。

    df[, val3 := sum(Intensity, na.rm=TRUE) * NA^(seq_len(.N) != .N | .N == 1),
       by=cumsum(is.na(Intensity))]
    

    此方法利用了 NA^x 其中 x != 0 返回 NA,但 NA^0 返回 1 且 NA^FALSE 等效于 NA^0 的事实。

    第四个选择是使用replace。此函数用指定索引处的值替换向量。

    df[, val4 := replace(NA, (seq_len(.N) == .N & .N != 1),
                         sum(Intensity, na.rm=TRUE)),
       by=cumsum(is.na(Intensity))]
    

    三种方法的结果如下所示。

    df
        Duration Intensity   val3    val   val2   val4
     1:       NA        NA     NA     NA     NA     NA
     2:       10    0.1016     NA     NA     NA     NA
     3:       10    0.0254 0.1270 0.1270 0.1270 0.1270
     4:       NA        NA     NA 0.0000     NA     NA
     5:       NA        NA     NA     NA     NA     NA
     6:       10    0.0508     NA     NA     NA     NA
     7:       10    0.0508     NA     NA     NA     NA
     8:       10    0.1016 0.2032 0.2032 0.2032 0.2032
     9:       NA        NA     NA     NA     NA     NA
    10:       10    0.0254 0.0254 0.0254 0.0254 0.0254
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-10
      • 2021-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多