Попытка избежать использования цикла for
в следующем коде, используя sapply
, если это вообще возможно. Решение с loop работает отлично для меня, я просто пытаюсь узнать больше R и изучить как можно больше методов.Пытается избежать цикла с помощью sapply (для gsub)
Цель: иметь вектор i
и два вектора sf
(поиск) и rp
(заменить). Для каждого i
необходимо зациклиться на sf
и заменить на rp
где матч.
i = c("1 6 5 4","7 4 3 1")
sf = c("1","2","3")
rp = c("one","two","three")
funn <- function(i) {
for (j in seq_along(sf)) i = gsub(sf[j],rp[j],i,fixed=T)
return(i)
}
print(funn(i))
Результат (правильный):
[1] "one 6 5 4" "7 4 three one"
Я хотел бы сделать тот же, но с sapply
#Trying to avoid a for loop in a fun
#funn1 <- function(i) {
# i = gsub(sf,rp,i,fixed=T)
# return(i)
#}
#print(sapply(i,funn1))
Видимо, выше прокомментировал код не будет работать, как я может получить только первый элемент sf
. Это мой первый раз с использованием sapply
, поэтому я не совсем уверен, как преобразовать «внутренний» неявный цикл в векторное решение. Любая помощь (даже заявление - это невозможно) оценивается!
(я знаю mgsub
, но это не решение здесь хотел бы сохранить gsub
.)
EDIT: Полный код с пакетами и belowoffered решения и сроки:
#timing
library(microbenchmark)
library(functional)
i = rep(c("1 6 5 4","7 4 3 1"),10000)
sf = rep(c("1","2","3"),100)
rp = rep(c("one","two","three"),100)
#Loop
funn <- function(i) {
for (j in seq_along(sf)) i = gsub(sf[j],rp[j],i,fixed=T)
return(i)
}
t1 = proc.time()
k = funn(i)
t2 = proc.time()
#print(k)
print(microbenchmark(funn(i),times=10))
#mapply
t3 = proc.time()
mapply(function(u,v) i<<-gsub(u,v,i), sf, rp)
t4 = proc.time()
#print(i)
print(microbenchmark(mapply(function(u,v) i<<-gsub(u,v,i), sf, rp),times=10))
#Curry
t5 = proc.time()
Reduce(Compose, Map(function(u,v) Curry(gsub, pattern=u, replacement=v), sf, rp))(i)
t6 = proc.time()
print(microbenchmark(Reduce(Compose, Map(function(u,v) Curry(gsub, pattern=u, replacement=v), sf, rp))(i), times=10))
#4th option
n <- length(sf)
sf <- setNames(sf,1:n)
rp <- setNames(rp,1:n)
t7 = proc.time()
Reduce(function(x,j) gsub(sf[j],rp[j],x,fixed=TRUE),c(list(i),as.list(1:n)))
t8 = proc.time()
print(microbenchmark(Reduce(function(x,j) gsub(sf[j],rp[j],x,fixed=TRUE),c(list(i),as.list(1:n))),times=10))
#Usual proc.time
print(t2-t1)
print(t4-t3)
print(t6-t5)
print(t8-t7)
раз:
Unit: milliseconds
expr min lq mean median uq max neval
funn(i) 143 143 149 145 147 165 10
Unit: seconds
expr min lq mean median uq max neval
mapply(function(u, v) i <<- gsub(u, v, i), sf, rp) 4.1 4.2 4.4 4.3 4.4 4.9 10
Unit: seconds
expr min lq mean median uq max neval
Reduce(Compose, Map(function(u, v) Curry(gsub, pattern = u, replacement = v), sf, rp))(i) 1.6 1.6 1.7 1.7 1.7 1.7 10
Unit: milliseconds
expr min lq mean median uq max neval
Reduce(function(x, j) gsub(sf[j], rp[j], x, fixed = TRUE), c(list(i), as.list(1:n))) 141 144 147 145 146 162 10
user system elapsed
0.15 0.00 0.15
user system elapsed
4.49 0.03 4.52
user system elapsed
1.68 0.02 1.68
user system elapsed
0.19 0.00 0.18
Таким образом, на самом деле в этом случае петля for
предлагает наилучшее время и (на мой взгляд) наиболее straightforwar d, простой и, возможно, элегантный. Приклеивание к петле.
Спасибо всем. Все предложения приняты и одобрены.
Обычно вы используете «microbenchmark» на всех вещах, которые вы тестируете одновременно.Кроме того, вы можете захотеть пометить «производительность» на будущие вопросы, если это снова будет проблемой. Кстати, ответ Шенглина на самом деле использует 'sapply'. – Frank
Моя цель состояла в том, чтобы оценить, как долго каждое решение выполняется отдельно, в случае, если альтернативное решение намного быстрее, чем цикл. Ответ на предыдущий ответ Шенглин тоже –