将多个参数套用到用户定义的函数

时间:2020-09-08 14:23:52

标签: r dplyr sapply

我有一个数据帧df,并且想使用函数range_frac来执行操作。

set.seed(137)
df <- data.frame(col1 = sample(LETTERS, 100, TRUE), 
                 col2 = sample(-75:75, 100, TRUE), 
                 col3 = sample(-75:75, 100, TRUE))

df$col2[c(23, 48, 78)] <- NA
df$col3[c(37, 68, 81)] <- NA


range_frac <- function(n, my_df, my_var) {

  len = sum(my_df[my_var] < n, na.rm = TRUE)
  len
}

我想分别知道满足col2col3中提到的条件的行数。由于无法成功传递列名,因此我传递了列索引(23)。但是,当我尝试传递my_var的向量时,它会汇总各个值的输出。这是怎么发生的?

sapply(1:3, range_frac, my_df = df, my_var = 2) 
[1] 57 57 57

sapply(1:3, range_frac, my_df = df, my_var = 3) 
[1] 51 51 52

sapply(1:3, range_frac, my_df = df, my_var = 2:3) 
[1] 108 108 109

有人可以在第三次操作(即57 + 51、57 + 51、57 + 52)的结果后面提供解释吗?

(基本上,我正在尝试以dyplr-summarise的方式实现以下输出,但现在停留在这一点,并认为我会清除对这一概念的理解)。

n col2 col3
1 57 51
2 57 51
3 57 52

更新: 我问了一个不清楚的问题,因此请使用更多信息进行更新。解决方法如下:

对于每个n,解决方案都可以理解为对表达式的求值 sum(df[,2:3] < n, na.rm = TRUE),而不是23列的单独记录。

2 个答案:

答案 0 :(得分:1)

让我们以以下代码为例

sapply(1:3, range_frac, my_df = df, my_var = 2:3) 

此处,1:3作为第一个参数传递给range_frac,它等效于迭代,例如,

for (i in 1:3) {
     range_frac(...)
}

sapply中,my_df = dfmy_var = 2:3是传递给range_frac的第二个和第三个参数。因此,整个sapply行可以解释为

res <- c()
for (i in 1:3) {
     res[i] <- range_frac(i, df, 2:3)
}

一些解决方法

sapply(1:3,Vectorize(range_frac,"my_var"),my_df = df, my_var = 2:3)

sapply(1:3,function(k) sapply(2:3,function(v) range_frac(k,df,v)))

答案 1 :(得分:1)

如果您向2:3输入my_var,则range_frac()实际上会执行

sum(df[2:3] < n, na.rm = TRUE)
对于每个n

。当然,您在第二和第三列中得到的元素数少于n。一种解决方案是将参数my_var向量化,即

sapply(1:3, Vectorize(range_frac, "my_var"), my_df = df, my_var = 2:3)

#      [,1] [,2] [,3]
# [1,]   48   48   48
# [2,]   49   51   51