【问题标题】:Making a custom function apply rowise in dplyr mutate使自定义函数在 dplyr mutate 中应用 rowise
【发布时间】:2019-07-16 17:28:59
【问题描述】:

我有一个自定义布尔函数来检查一个字符串(我的实际函数比下面提供的要多,这只是作为说明性示例提供的)。

如果我将第一个版本与 dplyr::mutate() 一起使用,它只会应用于第一个值,然后将所有行设置为该答案。

我可以将函数包装在 purr::map() 中,但是在较大的数据集上这似乎很慢。它似乎也不是 mutate 正常工作的方式。

library(tidyverse)

valid_string <- function(string) {
  # Check the length
  if (stringr::str_length(string) != 10) {
    return(FALSE)
  }
  return(TRUE)
}

# Create a tibble to test on
test_tib <- tibble::tibble(string = c("1504915593", "1504915594", "9999999999", "123"),
                           known_valid = c(TRUE, TRUE, TRUE, FALSE))

# Apply the function
test_tib <- dplyr::mutate(test_tib, check_valid = valid_string(string))
test_tib

valid_string2 <- function(string) {
  purrr::map_lgl(string, function(string) {
    # Check the length
    if (stringr::str_length(string) != 10) {
      return(FALSE)
    }
    return(TRUE)
  })
}

# Apply the function
test_tib <- dplyr::mutate(test_tib, check_valid2 = valid_string2(string))
test_tib

【问题讨论】:

    标签: r function dplyr tidyverse


    【解决方案1】:

    我建议你将你的函数重写为vectorized 函数,如下所示:

    valid_string <- function(string) {
      # Check the length
      ifelse(stringr::str_length(string) != 10, FALSE, TRUE)
    }
    

    另一个选项是 base 中的 Vectorize 函数,它的工作原理如下:

    valid_string2 <- function(string) {
      # Check the length
      if(stringr::str_length(string) != 10) {
        return(FALSE)
      }
      return(TRUE)
    }
    valid_string2 <- Vectorize(valid_string2)    
    

    两者都工作得很好,但是我建议使用ifelse 的解决方案。

    # Create a tibble to test on
    test_tib <- tibble::tibble(string = c("1504915593", "1504915594", "9999999999", "123"),
                               known_valid = c(TRUE, TRUE, TRUE, FALSE))
    
    # Apply the function
    test_tib <- dplyr::mutate(test_tib, check_valid = valid_string(string))
    test_tib <- dplyr::mutate(test_tib, check_valid2 = valid_string2(string))
    test_tib
    
    
      string     known_valid check_valid check_valid2
      <chr>      <lgl>       <lgl>       <lgl>       
    1 1504915593 TRUE        TRUE        TRUE        
    2 1504915594 TRUE        TRUE        TRUE        
    3 9999999999 TRUE        TRUE        TRUE        
    4 123        FALSE       FALSE       FALSE
    

    【讨论】:

    • 谢谢,Vectorize 似乎可以工作,只是运行一些测试看看使用 purr::map、sapply 或 Vectorize 之间的速度是否有任何不同。我不认为我可以使用 ifelse 或 dplyr::if_else 因为我的实际功能比提供的要复杂得多。
    • 好的,请告诉我们。如果一切都按预期工作,接受答案会很好:-)
    • 速度似乎在 3 种方法之间相当,但我认为 Vectorized 是最干净的并且最大限度地减少依赖关系......通过分析和微基准测试,我设法将速度提高了 20 倍......我可能应该这样做首先!
    【解决方案2】:

    这是你要找的吗?

    test_tib <- dplyr::mutate(test_tib, checkval = ifelse(nchar(string)!=10,FALSE,TRUE))
    

    【讨论】:

    • 不,抱歉,正如我在问题中所说,实际功能比上面提供的要复杂得多。但本质上它接受一个字符串并返回一个 TRUE 或 FALSE。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    • 2023-03-10
    • 2015-02-05
    • 2020-05-31
    相关资源
    最近更新 更多