【问题标题】:Conditional cumsum based on the next value of a vector基于向量的下一个值的条件 cumsum
【发布时间】:2015-06-21 14:11:06
【问题描述】:

我正在尝试根据以下条件计算包含元素 0,1,NA 的向量的累积和:

1) 只计算 NA 值之间的 cumsums

2) 如果 0 在 1 之后,那么我想要 cumsum+1

Out 是原始向量:

out[1:100]
  [1] NA NA NA NA  0  1  1 NA NA NA  1 NA  0 NA  0  1 NA NA  0 NA  0  1  0  0  0 NA  0  1  0  1  0  0  1  0  1  1  0  0  0  0
 [41]  1  0 NA  0  0 NA  1 NA  0  1 NA  0 NA  0  1  1 NA  1 NA  0  0  0  1  1 NA NA NA  0  0 NA  0  0  0  1  0 NA  1  0 NA  0
 [81]  1  1  0  1  1  0  1  0 NA  0  1  0  1  0 NA  0  1  0  0  1

我使用此代码计算 NA 值之间的累积和:

g <- cumsum(is.na(head(c(0, out), -1)))
out1 <- ave(out, g, FUN = cumsum)

我明白了

out1[1:100]
  [1] NA NA NA NA  0  1  2 NA NA NA  1 NA  0 NA  0  1 NA NA  0 NA  0  1  1  1  1 NA  0  1  1  2  2  2  3  3  4  5  5  5  5  5
 [41]  6  6 NA  0  0 NA  1 NA  0  1 NA  0 NA  0  1  2 NA  1 NA  0  0  0  1  2 NA NA NA  0  0 NA  0  0  0  1  1 NA  1  1 NA  0
 [81]  1  2  2  3  4  4  5  5 NA  0  1  1  2  2 NA  0  1  1  1  2

现在我有一个问题,如果 1 后跟一个零(这里只是第一个零),我想得到 cumsum+1

例如

0 1 1 0 0 0 1 0 1 1 不适用

使用我现在拥有的功能,我会得到

0 1 2 2 2 2 3 3 4 5 不适用,但我想要的是:

0 1 2 3 3 3 4 5 6 7 不适用

有人可以帮忙吗?谢谢。

【问题讨论】:

    标签: r conditional na cumsum


    【解决方案1】:

    应该有更简单的方法,但你可以试试这个:

    temp1 <- out
    temp1[is.na(temp1)] <- 0
    
    temp2 <- (temp1[2:length(temp1)] == 0) * (temp1[1:length(temp1)-1]==1)
    temp2 <- c(0, temp2)
    
    out1 <- cumsum(temp1+temp2)- cummax(cumsum((temp1+temp2))*is.na(out))
    out1[is.na(out)] <- NA
    
    rm(temp1, temp2)
    
    out1
    

    【讨论】:

    • 我只是用这个函数在 NA 之间得到了正常的 cumsum,它不会在一个之后为零添加 +1。但是感谢您的努力。
    • lag 存在问题。它现在应该可以工作了。
    【解决方案2】:

    试试这个

    out <- c(NA, NA, NA, NA, 0, 1, 1, NA, NA, NA, 1, NA, 0, NA, 0, 1, NA, 
        NA, 0, NA, 0, 1, 0, 0, 0, NA, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 
        0, 0, 0, 1, 0, NA, 0, 0, NA, 1, NA, 0, 1, NA, 0, NA, 0, 1, 1, 
        NA, 1, NA, 0, 0, 0, 1, 1, NA, NA, NA, 0, 0, NA, 0, 0, 0, 1, 0, 
        NA, 1, 0, NA, 0, 1, 1, 0, 1, 1, 0, 1, 0, NA, 0, 1, 0, 1, 0, NA, 
        0, 1, 0, 0, 1, NA, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, NA)
    
    as.numeric(unlist(lapply(split(out, cumsum(is.na(out))),
        function(x) {
            if (length(x) == 1) return(x)
            idx <- which(x[-length(x)] == 1 & x[-1] == 0)
            res <- cumsum(x[-1])
            for (i in seq_along(idx)) {
                if (i == length(idx))
                    res[seq(idx[i], length(res))] <- res[seq(idx[i], length(res))] + i
                else
                    res[seq(idx[i], idx[i + 1] - 1)] <- res[seq(idx[i], idx[i + 1] - 1)] + i
            }
            c(NA, res)
        }
    )))
    #  [1] NA NA NA NA  0  1  2 NA NA NA  1 NA  0 NA  0  1 NA NA  0 NA  0  1  2  2  2
    # [26] NA  0  1  2  3  4  4  5  6  7  8  9  9  9  9 10 11 NA  0  0 NA  1 NA  0  1
    # [51] NA  0 NA  0  1  2 NA  1 NA  0  0  0  1  2 NA NA NA  0  0 NA  0  0  0  1  2
    # [76] NA  1  2 NA  0  1  2  3  4  5  6  7  8 NA  0  1  2  3  4 NA  0  1  2  2  3
    #[101] NA  0  1  2  3  3  3  4  5  6  7 NA
    

    或者,您可以计算out1,保持现有方法(使用ave),然后通过识别需要添加的序列来“添加”缺失的位

    na.pos <- which(is.na(out))
    idx <- which(out[-length(out)] == 1 & out[-1] == 0)
    idx2 <- which(is.na(out[-1]) | (out[-length(out)] == 1 & out[-1] == 0))
    
    beg <- idx + 1
    end <- idx2[findInterval(idx, idx2) + 1]
    to.add <- as.numeric(unlist(sapply(rle(findInterval(idx, na.pos))$lengths, seq, from = 1)))
    
    for(i in seq_along(beg))
        out1[seq(beg[i], end[i])] <- out1[seq(beg[i], end[i])] + to.add[i]
    

    【讨论】:

    • 我还有一个问题:我想根据 out1 向量(与我的 df 长度相同)对数据帧进行子集化,但前提是我有一个最小 0-4 的序列。我以为我已经有了这方面的代码,但我不明白。
    • @Pat Happy 它可以工作并进一步提供帮助,但我不明白您到底想要完成什么(主要是“最小 0-4 的序列”部分)。您能否使用示例/预期输出修改 OP?
    猜你喜欢
    • 1970-01-01
    • 2019-04-04
    • 2018-09-08
    • 2011-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-16
    • 1970-01-01
    相关资源
    最近更新 更多