如何根据R中另一列的条件总结列的特定单元格?

时间:2016-12-30 18:00:23

标签: r sum dplyr

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

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结果,而不是值。

2 个答案:

答案 0 :(得分:2)

我们可以使用data.table。转换&#39; data.frame&#39;到&#39; data.table&#39; (setDT(df1)),按逻辑向量(!is.na(Duration))的游程长度ID分组,我们指定(:=)强度为sum&#39 ; as&#39; Intensity_sum and later replace the重复的元素与&#39; NA&#39;

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以及强度&#39的sum来分配新列。 ;

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

答案 1 :(得分:0)

使用我在下面建议的第四种data.table方法,可以在基数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检查NA边界的shift执行求和的放置。

这有点慢,如果有一个带有相邻数值的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