使用 NA 计算列表元素的最小值

Compute minima across list elements with NA

我得到了一个笨拙的解决方案,但觉得为看似简单的东西编写这么多代码很愚蠢。这对于几十 MB 的列表来说非常快,所以我不需要提高效率。但我仍然需要帮助。

我有一个很大的列表(n 个元素,每个元素都是一个长度为 m 的向量)。我需要获得所有 n 个元素的 m 个最小值(如果这令人困惑,我的意思在代码中很明显)。有 NA,在某些情况下有 0 个完整案例,在大多数情况下有 >=1 个完整案例。我写了一些工作正常的代码,但感觉应该有一种更简单的方法可以到达这里。你能精简这段代码吗?

具体来说,有没有办法避免最小函数的条件,有没有应用系列函数可以让我避免第一个 cbind

# make data
rawval<-replicate(10, sample(c(1:10, NA), size = 10, replace =T)
     , simplify = F)

# this seems clunky, does this function have a name?
mymin<-function(x)ifelse(all(is.na(x)), NA, min(x, na.rm =T))

# I don't see why I should need two apply family functions here
tomin<-sapply(rawval, cbind) %>%  apply(MARGIN = 1, FUN = mymin)

抱歉,我怀疑这是一个重复的问题:(

您可以使用 do.callcbind 数据集,并使用 apply 按行应用 hablar::min_ 函数。 hablar::min_ returns NA 如果所有值都是 NA.

apply(do.call(cbind, rawval), 1, hablar::min_)

不想用的话也可以用自己的函数hablar::min_

custom_min <- function(x) if(all(is.na(x))) NA else min(x, na.rm = TRUE)
apply(do.call(cbind, rawval), 1, custom_min)

你要的是mapply。它将函数应用于多个列表的每个元素。请参阅其帮助页面。

我给你推荐一个函数。我不太确定总和部分,但如果我做对了,你只想找到总和为正的行的最小值。

我将 my_functionyour_function 进行了基准测试,得到了以下结果:

UPDATE:我还在基准测试中包含了一个 my_updated_function,我只是使用了 pmin.int。我现在明白你的意思了,如果所有值都是 NA,则将 NA 保留为“最小值”。我之前以为会有负值。

我包含了您建议的 pmin 解决方案(使用 ifelse)和 @jay.sf 解决方案。

rawval <- replicate(
    1000,
    sample(c(1:10, NA), size = 1000, replace =T),
    simplify = F
)

my_function <- function(values) {
    sums <- mapply(sum, values, na.rm=TRUE)
    mins <- mapply(min, values, na.rm=TRUE)
    mins[sums <= 0] <- NA
    return(mins)
}

my_updated_function <- function(values) {
    mins <- do.call(pmin.int, c(values, na.rm=TRUE))
    # if min is zero, all values are NA. NOTE: this only works like this
    # because I'm assuming numbers will always be positive integers
    # like the example you provided.
    mins[mins == 0] <- NA
    return(mins)
}

your_function <- function(values) {
    mymin<-function(x)ifelse(sum(x, na.rm=T)>0, min(x, na.rm =T), NA)
    
    # I don't see why I should need two apply family functions here
    tomin<- apply(sapply(values, cbind), MARGIN = 1, FUN = mymin)
    return(tomin)
}

pmin_function <- function(values) {
    sums <- mapply(sum, values, na.rm=TRUE)
    mins <- do.call(pmin, c(values, na.rm = TRUE))
    mins[sums <= 0] <- NA
    return(mins)
}

jay_sf_function <- function(values) {
    return(sapply(values, \(x) ifelse(!all(is.na(x)), min(x, na.rm=TRUE), NA)))
}

microbenchmark::microbenchmark(
    your_function(rawval),
    my_function(rawval),
    my_updated_function(rawval),
    pmin_function(rawval),
    jay_sf_function(rawval)
)
Unit: milliseconds
                        expr     min       lq      mean   median       uq     max neval
       your_function(rawval) 29.0871 32.77735 34.676408 34.37340 35.91040 77.6884   100
         my_function(rawval)  4.8762  5.16365  5.376355  5.37335  5.52475  7.3706   100
 my_updated_function(rawval)  2.6481  2.72655  2.872085  2.78275  2.92460  4.0724   100
       pmin_function(rawval)  5.7140  5.95945  6.268012  6.13110  6.35375  9.4198   100
     jay_sf_function(rawval)  4.8583  5.13700  6.839790  5.43480  6.45270 47.6075   100

你在找这个吗?这更多是基于您的描述而不是您的代码。

rawval2
# [[1]]
# [1] 2 5 4 2 1 3
# 
# [[2]]
# [1]  5 NA  4  1  5  2
# 
# [[3]]
# [1]  1 NA  3 NA  2  1
# 
# [[4]]
# [1] NA NA NA  5 NA NA
# 
# [[5]]
# [1] NA NA NA NA NA NA

sapply(rawval2, \(x) ifelse(!all(is.na(x)), min(x, na.rm=TRUE), NA))
# [1]  1  1  1  5 NA

数据

rawval2 <- list(c(2L, 5L, 4L, 2L, 1L, 3L), c(5L, NA, 4L, 1L, 5L, 2L), c(1L, 
NA, 3L, NA, 2L, 1L), c(NA, NA, NA, 5L, NA, NA), c(NA_integer_, 
NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_
))