作为题目,我想知道如何在R中定义一个向量化函数。
w8rqjzmb1#
R级别的循环不是矢量化的。R循环将为矢量的每个元素调用相同的R代码,这将是低效的。矢量化的函数通常指那些获取矢量并以高效的方式对整个矢量进行操作的函数。最终,这将涉及某种形式的循环,但是由于该循环是以诸如C之类的低级语言执行的,因此它可以是高效的并且适合于特定任务。把这个愚蠢的函数看作是两个向量元素的两两相加
sillyplus <- function(x, y) { out <- numeric(length = length(x)) for(i in seq_along(x)) { out[i] <- x[i] + y[i] } out }
它给出了正确的结果
R> sillyplus(1:10, 1:10) [1] 2 4 6 8 10 12 14 16 18 20
并且在它可以一次对整个向量进行操作的意义上被向量化,但是在我上面描述的意义上,它不是 * 向量化 * 的,因为它是异常低效的。+在R中在C级别被向量化,所以我们实际上只需要1:10 + 1:10,而不需要R中的显式循环。通常写矢量化函数的方法是使用已经矢量化的现有R函数,如果你想从头开始,而你想用这个函数做的事情在R中并不存在(奇怪,但有可能)那么您需要亲自动手,用C编写函数的核心部分,并在R中准备一个小 Package 器来调用您用你想要它处理的数据的向量。有一些方法可以用像Vectorize()这样的函数来伪造没有向量化的R函数的向量化。C不是唯一的选择,FORTRAN和C++都是可能的,多亏了Dirk Eddelbuettel和Romain Francois,后者现在用Rcpp包更容易做到。
+
1:10 + 1:10
Vectorize()
Rcpp
lo8azlld2#
一个向量化函数将返回一个长度与其参数相同的向量。通常情况下,可以通过使用内置函数的组合来获得这样的函数,如“+"、cos或exp,这些函数也是向量化的。
cos
exp
vecexpcos <- function(x) exp(cos(x)) vecexpcos( (1:10)*pi ) > vecexpcos( (1:10)*pi ) # [1] 0.3678794 2.7182818 0.3678794 2.7182818 0.3678794 2.7182818 0.3678794 2.7182818 0.3678794 2.7182818
如果需要使用sum这样的非矢量化函数,则可能需要调用mapply或Vectorize以获得所需的行为。
sum
mapply
Vectorize
dfty9e193#
虽然晚了点,但是我认为这个问题仍然是非常相关的,而且最近有一些新的方法流行起来,所以这里有另一种方法来向量化R中的函数,使用tidyverse方法。首先,定义一些数据:
tidyverse
x <- c(1,2,3) y <- c(1,2,4)
现在,假设我们要对这两个向量执行一些元素级的计算,使得f(x,y)。例如,计算x和y的每个(一对)元素的和应得到:2,4,7.让我们使用purrr中的map2_dbl(tidyverse生态系统中的一个包):
f(x,y)
purrr
map2_dbl
x <- c(1,2,3) y <- c(1,2,4) library(tidyverse) map2_dbl(.x = x, .y = y, .f = sum) #> [1] 2 4 7
如图所示,结果是矢量化的,因为总和是针对来自x和y的每对元素计算的。总之,至少在某些情况下,使用map()及其变体是对函数进行矢量化的一种方便方法。
map()
eyh26e7m4#
Vectorize函数的目的是增强常规函数考虑R中矢量化概念的能力。例如,考虑下面的减法函数:
difftemp <- function(x){ if(x > 10) return(x*10 - x) else return(x) }
这是一个简单的函数,如果输入值大于10,则返回小于输入值10倍的值。如果输入值小于10,则返回相同的值。
> difftemp(100) # [1] 900
但是当你将同样的函数应用到向量上时,它就会失败。
> difftemp(mtcars$mpg) # Error in if (x > 10) return(x * 10 - x) else return(x) : # the condition has length > 1
这是因为该函数不支持矢量化,要使该函数矢量化,需要使用R中的Vectorize函数,例如:
# Vectorize difftemp function > difftemp_v <- Vectorize(difftemp) > difftemp_v(mtcars$mpg) # [1] 189.0 189.0 205.2 192.6 168.3 162.9 128.7 219.6 205.2 172.8 160.2 147.6 155.7 136.8 93.6 93.6 132.3 291.6 273.6 305.1 193.5 139.5 # [23] 136.8 119.7 172.8 245.7 234.0 273.6 142.2 177.3 135.0 192.6
继续编码!
4条答案
按热度按时间w8rqjzmb1#
R级别的循环不是矢量化的。R循环将为矢量的每个元素调用相同的R代码,这将是低效的。矢量化的函数通常指那些获取矢量并以高效的方式对整个矢量进行操作的函数。最终,这将涉及某种形式的循环,但是由于该循环是以诸如C之类的低级语言执行的,因此它可以是高效的并且适合于特定任务。
把这个愚蠢的函数看作是两个向量元素的两两相加
它给出了正确的结果
并且在它可以一次对整个向量进行操作的意义上被向量化,但是在我上面描述的意义上,它不是 * 向量化 * 的,因为它是异常低效的。
+
在R中在C级别被向量化,所以我们实际上只需要1:10 + 1:10
,而不需要R中的显式循环。通常写矢量化函数的方法是使用已经矢量化的现有R函数,如果你想从头开始,而你想用这个函数做的事情在R中并不存在(奇怪,但有可能)那么您需要亲自动手,用C编写函数的核心部分,并在R中准备一个小 Package 器来调用您用你想要它处理的数据的向量。有一些方法可以用像
Vectorize()
这样的函数来伪造没有向量化的R函数的向量化。C不是唯一的选择,FORTRAN和C++都是可能的,多亏了Dirk Eddelbuettel和Romain Francois,后者现在用
Rcpp
包更容易做到。lo8azlld2#
一个向量化函数将返回一个长度与其参数相同的向量。通常情况下,可以通过使用内置函数的组合来获得这样的函数,如“+"、
cos
或exp
,这些函数也是向量化的。如果需要使用
sum
这样的非矢量化函数,则可能需要调用mapply
或Vectorize
以获得所需的行为。dfty9e193#
虽然晚了点,但是我认为这个问题仍然是非常相关的,而且最近有一些新的方法流行起来,所以这里有另一种方法来向量化R中的函数,使用
tidyverse
方法。首先,定义一些数据:
现在,假设我们要对这两个向量执行一些元素级的计算,使得
f(x,y)
。例如,计算x和y的每个(一对)元素的和应得到:2,4,7.
让我们使用
purrr
中的map2_dbl
(tidyverse生态系统中的一个包):如图所示,结果是矢量化的,因为总和是针对来自x和y的每对元素计算的。
总之,至少在某些情况下,使用
map()
及其变体是对函数进行矢量化的一种方便方法。eyh26e7m4#
Vectorize
函数的目的是增强常规函数考虑R中矢量化概念的能力。例如,考虑下面的减法函数:
这是一个简单的函数,如果输入值大于10,则返回小于输入值10倍的值。如果输入值小于10,则返回相同的值。
但是当你将同样的函数应用到向量上时,它就会失败。
这是因为该函数不支持矢量化,要使该函数矢量化,需要使用R中的
Vectorize
函数,例如:继续编码!