在R中编写向量化函数

5

我已经编写了以下函数:

asteriks = function(pvalue){
  if(pvalue > 0.05){
    output = "NS"
  }else if (pvalue <=0.05 & pvalue >0.01){
    output = "*"
  }else if (pvalue <=0.01 & pvalue >0.001){
    output = "**"
  }else if (pvalue <=0.001 & pvalue >0.0001){
    output = "***"
  }else if (pvalue <=0.0001){
    output = "****"
  }
  return(output)
}

当我提供长度为1的参数时,它可以正常工作,但我希望该函数接受长度>1的向量作为输入并返回相同长度的向量。

我想要实现的示例:

vector_pvals = c(0.1, 0.05, 0.001, 0.0001)
asteriks(vector_pvals)

输出应该是这样的字符向量:
[1] "NS" "*" "***" "****"

我当然可以在使用for循环的函数中实现这一目标,但实际上我想在一个dplyr管道内使用它,因此只需将整个向量输入即可。 答案是在函数内使用for循环逐一处理每个元素,还是有更简单的方法?

4个回答

7

在这里,你不需要编写自己的函数。cut正是你正在寻找的功能(这是迄今为止最简单的方法)

pvalues <- seq(0, 0.1, by = 0.0001)
cut(pvalues,
    breaks = c(-Inf, 0.0001, 0.001, 0.01, 0.05, Inf), 
    include.lowest = TRUE, 
    right = FALSE, 
    labels = c('****', '***', '**', '*', 'NS'))

如果您想将此转换为“向量化”练习,可以通过多种方式将函数转换,包括使用另一个答案建议的 ifelse、创建与每个组匹配的索引或使用多个索引。其中 ifelse 是最简单的方法。


3

使用 ifelse 来代替 if。它被设计为可向量化的。你的函数可以写成:

asteriks = function(pvalue){
  ifelse(pvalue > 0.05, "NS",
  ifelse(pvalue > 0.01, "*",
  ifelse(pvalue > 0.001, "**",
  ifelse(pvalue >0.0001, "***", "****"))))
}

对于更复杂的计算过程,无法使用此方法简化的其他函数,您可以使用Vectorize()函数将函数转换为向量化形式(通过内部运行循环)。例如:

asteriksV <- Vectorize(asteriks)

现在,即使使用您原始定义的 asteriksasteriksV 也能正常工作。

谢谢,这两个解决方案都完美地解决了问题,vectorize()选项也是一个很好的通用解决方案。如果有更多的嵌套ifelse语句,可能会变得混乱,此时上面建议使用cut的解决方案可能更容易些。 - Annick

3

使用10的次幂作为间隔strrep

asteriks <- function(pvalue) {
  ifelse(pvalue > 0.05, "NS", strrep("*", pmin(-log10(pvalue), 4)))
}

asteriks(c(0.1, 0.05, 0.001, 0.0001))
#> [1] "NS"   "*"    "***"  "****"

-1

仅仅是补充一下不同方法的练习。

asteriks <- function(p) {
  v <- c("*" = 0.05, "**" = 0.01, "***" = 0.001, "****" = 0.0001)
  ifelse(p > max(v), "NS", names(v[v <= p][1]))
}

vector_pvals = c(0.1, 0.05, 0.001, 0.0001)

unlist(lapply(vector_pvals, asteriks))

[1] "NS"   "*"    "***"  "****"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接