作为一个新手,我试图定义自己的函数来计算阶乘。我设法构造了最适合数字的函数。
fact1 = function(x){
a=1
for(i in 1:x){
a = a*i
}
return(a)
}
factorial = function(x){
ifelse(x>=0 & round(x) == x , fact1(as.integer(x)),"NA")
}
但是,我该如何改进它才能将向量输入其中并计算每个元素的阶乘?
答案 0 :(得分:2)
除了上面的b
注释之外,您还可以使用b = List.copyOf(a);
System.out.println("A start:" + b.get(2).getSeating());
System.out.println("B start:" + b.get(2).getSeating());
a.get(2).setSeating(27);
System.out.println("Hi there" );
System.out.println("A end:" + a.get(2).getSeating());
System.out.println("B end:" + b.get(2).getSeating());
或lapply
返回向量而不是列表:
vapply
答案 1 :(得分:2)
对于Vectorize
来说,这似乎是一个完美的例子:只需在Vectorize
函数的定义周围使用factorial
,使其在输入上进行矢量化即可。
fact1 = function(x){
a=1
for(i in 1:x){
a = a*i
}
return(a)
}
factorial = Vectorize(function(x){
ifelse(x>=0 & round(x) == x , fact1(as.integer(x)),"NA")
})
factorial(c(1,2,3))
#> [1] 1 2 6
答案 2 :(得分:2)
问题答案似乎有些复杂。
阶乘已经是一个存在的函数,可以向量化这样,如果您有一些数据,则可以将其简单地放入函数中。如果要定义负数以返回0,也可以使用逻辑语句将其合并。请注意,我正在使用下面的内置函数factorial
,而不是问题中的那个。
dat <- round(runif(1000, -10, 10))
dat_over_zero <- dat > 0
fact_vector <- numeric(1000)
fact_vector <- factorial(dat[dat_over_zero])
现在,如果您只是创建一个要学习的练习,则可以使用相同的思想非常简单地将函数向量化,避免不必要的循环。只需使用一个循环,并在此循环中迭代向量中的每个元素。
R_factorial <- function(x){
if(!is.numeric(x) || length(dim(x)))
stop("X must be a numeric vector!")
#create an output vector
output <- numeric(NROW(x))
#set initial value
output[x >= 1] <- 1
output[x < 1] <- NA
#Find the max factor (using only integer values, not gamma approximations)
mx <- max(round(x))
#Increment each output by multiplying the next factor (only on those which needs to be incremented)
for(i in seq(2, mx)){
output[x >= i] <- output[x >= i] * i
}
#return output
output
}
一些注意事项:
output <- numeric(length)
分配整个矢量,其中length是输出的数量(例如,此处是length(x)
或更普遍地是NROW(x)
)。NA
代替"NA"
而不使用任何数值。第一个被识别为数字,而第二个将更改字符向量中的向量。现在,替代答案表明是lapply还是vapply。这与遍历向量中的每个值并在每个值上使用函数大致相同。因此,对函数进行矢量化通常是一种缓慢的方法(但很容易理解!)。如果可以避免这种情况,则通常可以提高速度。 For循环和apply不一定是坏事,但与矢量化函数相比,它通常要慢得多。参见this stackoverflow page,它以一种非常容易理解的方式解释了原因。
另一个替代方法是使用建议的Vectorize
函数。这是一个肮脏的解决方案。以我的经验,它通常比执行一个简单的循环要慢,并且它可能会对多个参数函数产生一些意想不到的副作用。它不一定很糟糕,因为人们经常会获得底层代码的可读性。
速度比较
现在,矢量版本比其他答案要快得多。使用microbenchmark
包中的microbenchmark
函数,我们可以确切地看到速度有多快。下面显示了多少(请注意,我在问题描述中使用阶乘函数):
microbenchmark::microbenchmark(R_factorial = R_factorial(x),
Vapply = vapply(x,
factorial,
FUN.VALUE = numeric(1)),
Lapply = lapply(x, factorial),
Vfactorial = Vfactorial(x))
Unit: microseconds
expr min lq mean median uq max neval
R_factorial 186.525 197.287 232.2394 212.9565 241.464 395.706 100
Vapply 2209.982 2354.596 3004.9264 2428.7905 3842.265 6165.144 100
Lapply 2182.041 2299.092 2584.3881 2374.9855 2430.867 5061.852 100
Vfactorial(x) 2381.027 2505.4395 2842.9820 2595.3040 2669.310 5920.094 100
正如人们所看到的,R_factorial比vapply或lapply快11-12倍(2428.8 / 212.96 = 11.4)。这是一个巨大的速度提升。可以做进一步的改进以进一步提高速度(例如使用阶乘近似算法,Rcpp和其他选项),但对于本示例来说,就足够了。
答案 3 :(得分:0)
使用lapply函数
lapply(c(1,2,3),factorial)
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 6
答案 4 :(得分:0)
您还可以使用类型safe purrr :: map_dbl-function:
purrr::map_dbl(c(1,2,3), fact1)
[1] 1 2 6