使用 mapply 向量化函数
Vectorizing a function with mapply
我在 R 中有一个函数,它接受表示商业折扣结构的字符串并将它们转换为数字乘数。例如,字符串“50/20/15”仅表示原价优惠 50%,然后再优惠 20%,然后再优惠 15%。这相当于将原始价格乘以 (1 - 0.50)*(1 - 0.20)(1 - 0.15),等于 0.34。
我的函数如下
disc_str_to_num <- function(string){
numstrings <- strsplit(string,"/")
nums <- mapply(as.numeric, numstrings)
prod(1 - nums/100)
}
在单个字符串上按需要工作。
> disc_str_to_num("50/20/15")
[1] 0.34
不幸的是,这对字符串向量失败了。
discount_vec <- c("50/10",
"50/10/10",
"50/10/15",
"50/10/20")
> disc_str_to_num(discount_vec)
Error in nums/100 : non-numeric argument to binary operator
我尝试了 Vectorize
函数的各种应用,但都没有成功。
如何修改我的函数以适用于字符串向量?预期输出是字符串向量的分量值的数值向量。
prod
也应该在循环内
sapply(strsplit(discount_vec, "/"), \(x) prod(1 - as.numeric(x)/100))
[1] 0.4500 0.4050 0.3825 0.3600
对于单个元素,mapply
使用 SIMPLIFY = TRUE
因此我们没有任何问题,但是对于多个元素,它 returns a list
因此最后一步不起作用
> list(c(1, 3), c(2, 4))/100
Error in list(c(1, 3), c(2, 4))/100 :
non-numeric argument to binary operator
如果我们使用 OP 的代码,则用另一个 mapply
包装(或者可以在与 sapply
所示的相同 mapply
中执行此操作)
> disc_str_to_num <- function(string){
+ numstrings <- strsplit(string,"/")
+ nums <- mapply(as.numeric, numstrings)
+ mapply(\(x) prod(1 - x/100), nums)
+ }
>
> disc_str_to_num(discount_vec)
[1] 0.4500 0.4050 0.3825 0.3600
另一种选择是将 data.frame
读作 read.table
,然后使用 matrixStats
中的 rowProds
library(matrixStats)
rowProds(as.matrix(1- read.table(text = discount_vec,
header = FALSE, sep = "/", fill = TRUE)/100), na.rm = TRUE)
[1] 0.4500 0.4050 0.3825 0.3600
像这样使用矢量化:
Vectorize(disc_str_to_num)(discount_vec)
## 50/10 50/10/10 50/10/15 50/10/20
## 0.4500 0.4050 0.3825 0.3600
或者创建一个新的函数名然后调用它:
disc_str_to_num_vec <- Vectorize(disc_str_to_num)
disc_str_to_num_vec(discount_vec)
## 50/10 50/10/10 50/10/15 50/10/20
## 0.4500 0.4050 0.3825 0.3600
或者重写函数如图所示。请注意,strsplit 在此函数中创建了一个元素列表,[[1]] 获取内容。
disc_str_to_num_vec2 <-
Vectorize(function(x) prod(1 - as.numeric(strsplit(x, "/")[[1]]) / 100))
disc_str_to_num_vec2(discount_vec)
## 50/10 50/10/10 50/10/15 50/10/20
## 0.4500 0.4050 0.3825 0.3600
我在 R 中有一个函数,它接受表示商业折扣结构的字符串并将它们转换为数字乘数。例如,字符串“50/20/15”仅表示原价优惠 50%,然后再优惠 20%,然后再优惠 15%。这相当于将原始价格乘以 (1 - 0.50)*(1 - 0.20)(1 - 0.15),等于 0.34。
我的函数如下
disc_str_to_num <- function(string){
numstrings <- strsplit(string,"/")
nums <- mapply(as.numeric, numstrings)
prod(1 - nums/100)
}
在单个字符串上按需要工作。
> disc_str_to_num("50/20/15")
[1] 0.34
不幸的是,这对字符串向量失败了。
discount_vec <- c("50/10",
"50/10/10",
"50/10/15",
"50/10/20")
> disc_str_to_num(discount_vec)
Error in nums/100 : non-numeric argument to binary operator
我尝试了 Vectorize
函数的各种应用,但都没有成功。
如何修改我的函数以适用于字符串向量?预期输出是字符串向量的分量值的数值向量。
prod
也应该在循环内
sapply(strsplit(discount_vec, "/"), \(x) prod(1 - as.numeric(x)/100))
[1] 0.4500 0.4050 0.3825 0.3600
对于单个元素,mapply
使用 SIMPLIFY = TRUE
因此我们没有任何问题,但是对于多个元素,它 returns a list
因此最后一步不起作用
> list(c(1, 3), c(2, 4))/100
Error in list(c(1, 3), c(2, 4))/100 :
non-numeric argument to binary operator
如果我们使用 OP 的代码,则用另一个 mapply
包装(或者可以在与 sapply
所示的相同 mapply
中执行此操作)
> disc_str_to_num <- function(string){
+ numstrings <- strsplit(string,"/")
+ nums <- mapply(as.numeric, numstrings)
+ mapply(\(x) prod(1 - x/100), nums)
+ }
>
> disc_str_to_num(discount_vec)
[1] 0.4500 0.4050 0.3825 0.3600
另一种选择是将 data.frame
读作 read.table
,然后使用 matrixStats
rowProds
library(matrixStats)
rowProds(as.matrix(1- read.table(text = discount_vec,
header = FALSE, sep = "/", fill = TRUE)/100), na.rm = TRUE)
[1] 0.4500 0.4050 0.3825 0.3600
像这样使用矢量化:
Vectorize(disc_str_to_num)(discount_vec)
## 50/10 50/10/10 50/10/15 50/10/20
## 0.4500 0.4050 0.3825 0.3600
或者创建一个新的函数名然后调用它:
disc_str_to_num_vec <- Vectorize(disc_str_to_num)
disc_str_to_num_vec(discount_vec)
## 50/10 50/10/10 50/10/15 50/10/20
## 0.4500 0.4050 0.3825 0.3600
或者重写函数如图所示。请注意,strsplit 在此函数中创建了一个元素列表,[[1]] 获取内容。
disc_str_to_num_vec2 <-
Vectorize(function(x) prod(1 - as.numeric(strsplit(x, "/")[[1]]) / 100))
disc_str_to_num_vec2(discount_vec)
## 50/10 50/10/10 50/10/15 50/10/20
## 0.4500 0.4050 0.3825 0.3600