【问题标题】:How to vectorize a subsetting function in R?如何矢量化 R 中的子集函数?
【发布时间】:2019-04-08 08:35:54
【问题描述】:

我很幸运地将某些函数矢量化,这对于干净的代码、避免循环和速度非常有用。

但是,我无法向量化任何基于函数输入对数据帧进行子集化的函数

示例

例如这个函数在接收元素时效果很好

test_funct <- function(sep_wid, sep_len) {
    iris %>% filter(Sepal.Width > sep_wid & Sepal.Length < sep_len) %>% .$Petal.Width %>% sum
}

test_funct(4, 6)

# [1] 0.7 # This works nicely

但是当试图提供向量作为这个函数的输入时:

sep_wid_vector <- c(4, 3.5, 3)
sep_len_vector <- c(6, 6, 6.5)


test_funct(sep_wid_vector, sep_len_vector)

[1] 9.1 

但所需的输出是一个与输入向量长度相同的向量,就好像该函数在每个向量的第一个元素上运行,然后是第二个,然后是第三个。即

# 0.7    4.2     28.5 

为了方便,这里的输出好像这些都是单独运行的

test_funct(4, 6) # 0.7
test_funct(3.5, 6) # 4.2
test_funct(3, 6.5) # 28.5

如何向量化一个基于其输入对数据进行子集化的函数,以便它可以接收向量输入?

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    问题在于filter 接受向量输入,因此它将在Sepal.widthSepal.length 比较中回收向量。

    一种方法是使用map2 包中的purrr

    map2_dbl(sep_wid_vector, sep_len_vector, test_funct)
    

    当然,您可以将其包装在一个函数中。您可能还需要考虑将数据框作为函数参数传入。

    【讨论】:

    • @thothal 与purrr::map2_dbl 一起发现很棒。为了完整起见,mapply(test_funct, sep_wid_vector, sep_len_vector) 也可以使用
    【解决方案2】:

    你可以使用Vectorize:

    tv <- Vectorize(test_funct)
    
    tv(sep_wid_vector, sep_len_vector)
    # [1]  0.7  4.2 28.5
    

    这基本上是mapply 的包装。请注意,您正在运行 *apply 函数,这也是一个循环

    【讨论】:

      【解决方案3】:

      这是使用sapply的一种方法

      # function using sapply
      test_funct <- function(sep_wid, sep_len) {
        sapply(seq_along(sep_wid), function(x) {
          sum(iris$Petal.Width[iris$Sepal.Width > sep_wid[x] & iris$Sepal.Length < sep_len[x]])
        })
      }
      
      # testing with single value
      test_funct(4,6)
      [1] 0.7
      
      # testing with vectors
      test_funct(sep_wid_vector, sep_len_vector)
      [1]  0.7  4.2 28.5
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多