【问题标题】:Calculate cumsum() while ignoring NA values在忽略 NA 值的同时计算 cumsum()
【发布时间】:2014-08-29 21:14:28
【问题描述】:

考虑以下命名向量x

( x <- setNames(c(1, 2, 0, NA, 4, NA, NA, 6), letters[1:8]) )
# a  b  c  d  e  f  g  h 
# 1  2  0 NA  4 NA NA  6 

我想计算x 的累积总和,同时忽略NA 值。许多 R 函数都有一个参数 na.rm,它会在计算之前删除 NA 元素。 cumsum() 不是其中之一,这使得这个操作有点棘手。

我可以这样做。

y <- setNames(numeric(length(x)), names(x))
z <- cumsum(na.omit(x))
y[names(y) %in% names(z)] <- z
y[!names(y) %in% names(z)] <- x[is.na(x)]
y
# a  b  c  d  e  f  g  h 
# 1  3  3 NA  7 NA NA 13 

但这似乎太过分了,并且做了很多新的任务/副本。我相信有更好的方法。

有什么更好的方法可以在有效忽略NA值的情况下返回累积和?

【问题讨论】:

    标签: r


    【解决方案1】:

    你可以在一行中做到这一点:

    cumsum(ifelse(is.na(x), 0, x)) + x*0
    #  a  b  c  d  e  f  g  h 
    #  1  3  3 NA  7 NA NA 13
    

    或者,类似地:

    library(dplyr)
    cumsum(coalesce(x, 0)) + x*0
    #  a  b  c  d  e  f  g  h 
    #  1  3  3 NA  7 NA NA 13 
    

    【讨论】:

    • x*0 在这里做什么?
    • @Denis x*0 如果x 中的值缺失,则取值NA,否则取值为0。因此,添加x*0 基本上只是用NA 替换原始值时不见了。
    【解决方案2】:

    你想要这样的东西吗:

    x2 <- x
    x2[!is.na(x)] <- cumsum(x2[!is.na(x)])
    
    x2
    

    [编辑] 或者,正如上面评论所建议的,您可以将 NA 更改为 0 -

    miss <- is.na(x)
    x[miss] <- 0
    cs <- cumsum(x)
    cs[miss] <- NA
    # cs is the requested cumsum
    

    【讨论】:

    • 单线做同样的事情:"[&lt;-"(x, !is.na(x), cumsum(na.omit(x)))
    • 同一件事的可读性更高的版本不是x[!is.na(x)] &lt;- cumsum(na.omit(x))吗?
    • 它更具可读性,但不是一回事。 "[&lt;-"(x, bla... 执行 OP 所要求的不更改 x,您的版本对 x 进行子集分配并返回 cumsum(na.omit(x))。所以这远远不是一回事。 - 一个更易读的单线版本,做同样的事情,是这样的:replace(x, !is.na(x), cumsum(na.omit(x)))
    【解决方案3】:

    这是一个老问题,但tidyr 提供了一个新的解决方案。 基于将NA 替换为零的想法。

    require(tidyr)
    
    cumsum(replace_na(x, 0))
    
     a  b  c  d  e  f  g  h 
     1  3  3  3  7  7  7 13 
    

    【讨论】:

    • 这包括计算平均值的零,但我认为帖子说他想在计算中忽略这些值。两者都不一样。
    【解决方案4】:

    这是我从这个问题的答案中得出的一个函数。以为我会分享它,因为到目前为止它似乎运作良好。它计算x 的累积FUNC,同时忽略NAFUNC 可以是 sum()prod()min()max() 中的任何一个,x 是一个数值向量。

    cumSkipNA <- function(x, FUNC)
    {
        d <- deparse(substitute(FUNC))
        funs <- c("max", "min", "prod", "sum")
        stopifnot(is.vector(x), is.numeric(x), d %in% funs)
        FUNC <- match.fun(paste0("cum", d))
        x[!is.na(x)] <- FUNC(x[!is.na(x)])
        x
    }
    
    set.seed(1)
    x <- sample(15, 10, TRUE)
    x[c(2,7,5)] <- NA
    x
    # [1]  4 NA  9 14 NA 14 NA 10 10  1
    cumSkipNA(x, sum)
    # [1]  4 NA 13 27 NA 41 NA 51 61 62
    cumSkipNA(x, prod)
    # [1]      4     NA     36    504     NA   7056     NA
    # [8]  70560 705600 705600
    cumSkipNA(x, min)
    # [1]  4 NA  4  4 NA  4 NA  4  4  1
    cumSkipNA(x, max)
    # [1]  4 NA  9 14 NA 14 NA 14 14 14 
    

    绝对没有什么新鲜事,但可能对某人有用。

    【讨论】:

    • 拥有这样一个通用的使用功能非常有用——太好了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-28
    • 1970-01-01
    • 1970-01-01
    • 2020-03-27
    • 1970-01-01
    • 2019-08-19
    • 2020-08-02
    相关资源
    最近更新 更多