将自定义函数应用于现有列以在 R 中的数据框中创建新列的最佳方法

Best way to apply a custom function to existing column to create a new column in data frame in R

我有一个数据框,其字符类型列包含以逗号分隔的数字字符串,即 1, 2, 3, 4 。我有一个自定义函数,我想将其应用于列中的每个值行,以便获得一个新值,我可以将其存储到数据框的新列中 df.

初始数据帧

A B str
1 1 1, 2, 5
1 2 NA
2 1 NA
2 2 1, 3

最终数据帧

A B str      res
1 1 1, 2, 5  2
1 2 NA       0
2 1 NA       0
2 2 1, 3     1

这是我的自定义函数 getCounts

getCounts <- function(str, x, y){
  if (is.na(str)){
    return(as.integer(0))
  }
  vec <- as.integer(unlist(strsplit(str, ',')))
  count <- 0
  for (i in vec) {
    if (i >= x & i <= y){
      count <- count + 1
    }
  }
  return(as.integer(count))
}


我最初尝试使用 lapply,因为根据其他帖子,它似乎最适合,但一直出现错误,例如:

df <- df %>% mutate(res = lapply(df$str, getCounts(df$str, 0, 2)))
Error: Problem with `mutate()` input `res`. x missing value where TRUE/FALSE needed i Input `res` is `lapply(df$str, getCounts(df$str, 0, 2))`

唯一似乎有效的是当我使用 mapply 时,但我真的不明白为什么以及是否有更好的方法来做到这一点。

df <- df %>%mutate(res = mapply(getCounts, df$str, 0, 2))

如果我没看错,你应该可以使用 rowwise():

df %>%
  rowwise() %>%
  mutate(res = getCounts(str, 0, 2)) %>%
  ungroup()

你的数据:

data.frame(
    A = c(1,1,2,2),
    B = c(1,2,1,2),
    str = c('1, 2, 5', NA, NA, '1, 3')
) -> df

getCounts <- function(str, x, y){
    if (is.na(str)){
        return(as.integer(0))
    }
    vec <- as.integer(unlist(strsplit(str, ',')))
    count <- 0
    for (i in vec) {
        if (i >= x & i <= y){
            count <- count + 1
        }
    }
    return(as.integer(count))
}

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

df %>%
    rowwise() %>%
    mutate(res = getCounts(str, 0, 2)) %>%
    ungroup()
#> # A tibble: 4 x 4
#>       A     B str       res
#>   <dbl> <dbl> <chr>   <int>
#> 1     1     1 1, 2, 5     2
#> 2     1     2 <NA>        0
#> 3     2     1 <NA>        0
#> 4     2     2 1, 3        1

reprex package (v1.0.0)

于 2021 年 3 月 17 日创建

你可以试试Vectorize

df %>%
  mutate(res = Vectorize(getCounts)(str, 0, 2))

sapply

df %>%
  mutate(res = sapply(str, getCounts, x = 0, y = 2))