我正在做這個練習題,希望我撰寫一個函式,用現有向量創建一個向量。示例是如果向量a<-c(4, 0, 1, -2, 3),則輸出向量應該是4 5 -1 2 1。規則是:如果現有向量a有length = n,則新向量b應設為length = n,并且每個元素的計算方式為b[i] = a[i-1] a[i] a[i 1]。如果這些a[i-1] a[i] a[i 1]元素中的任何一個不存在,則應將其設定為等于0。
z <- c(4, 0, 1, -2, 3)
solution <- function(n, a) {
b <- c()
for (i in 1:n) {
if (is.na(a[i - 1])) {
a[i - 1] <- 0
}
else if (is.na(a[i])) {
a[i] <- 0
}
else if (is.na(a[i 1])) {
a[i 1] <- 0
}
b[i] <- a[i - 1] a[i] a[i 1]
}
return(b)
}
solution(5, z)
有了這個,我得到了這個: Error in if (is.na(a[i - 1])) { : argument is of length zero
然后我把它改成
solution <- function(n, a) {
b <- c()
for (i in 1:n) {
if (is.null(a[i - 1])) {
a[i - 1] <- 0
}
else if (is.na(a[i])) {
a[i] <- 0
}
else if (is.na(a[i 1])) {
a[i 1] <- 0
}
b[i] <- a[i - 1] a[i] a[i 1]
}
return(b)
}
但這次我得到了:
solution(5, z)
# [1] NA 5 -1 2 1
新向量的第一個元素變為NA。我怎么了?
順便說一句,我也嘗試設定 n = 12
solution(12, z)
# [1] NA 5 -1 2 1 3 0 0 0 0 0 0
通過5后結果還可以。
uj5u.com熱心網友回復:
因為您正在進行練習,所以我將嘗試解釋每個步驟并得出一個簡單的解決方案(這可能不一定是最好的)。我們看到除了第一個元素外,一切都在作業,所以我們知道問題出在i = 1. 我們可以做的是遍歷這個值的回圈i,看看會發生什么。
i = 1
is.null(a[i - 1])
#> FALSE
即使我們認為這應該是真的(因為之前沒有元素i = 1),但條件仍然是FALSE。我們可以直接看到發生了什么:
a[i - 1]
#> numeric(0)
numeric(0)表示一個空的數字向量(不同于NULL)。當您通過索引 0 對向量進行子集化時會發生這種情況。請注意,您可以numeric(0)通過檢查其長度是否等于 0來識別(和任何空向量):
length(a[i - 1]) == 0
#> TRUE
但是,出現了不同的問題。即使發現條件為TRUE,請注意將向量的第 0 個元素設定為值不會做任何事情:
x = c(1, 2, 3)
x[0] = 10
x
#> [1] 1 2 3
不幸的是還有另一個問題!您使用了ifandelse if陳述句,因此無論何時到達這些分支之一,其余的都不會被執行。這意味著,如果有不止一個的問題a[i - 1],a[i]和a[i 1],只有第一個發現問題將是固定的。
我想引導我們走向一個不同的方向,以解決所有這些問題。首先,我們需要解決向量的開始和結束問題。這可以通過在向量的開頭和結尾附加 0 來完成:
a = c(0, a, 0)
接下來,我們需要將任何NA內a設定為 0:
a[is.na(a)] = 0
現在我們已經準備好像您一樣使用回圈來解決問題,但這一次非常簡單:
for (i in 1:n) {
b[i] = a[i] a[i 1] a[i 2]
}
最后一件事 - 而不是n成為函式的引數,我們可以通過使用length(a). 但最好的方法是簡單地使用seq_along(a),我將在下面展示。把它們放在一起:
solution = function(a) {
x = c(0, a, 0)
x[is.na(x)] = 0
b = c()
for (i in seq_along(a)) {
b[i] = x[i] x[i 1] x[i 2]
}
b
}
隨著您繼續學習 R,您會發現有許多很好的方法可以解決問題,例如其他答案中給出的解決方案。
uj5u.com熱心網友回復:
這適用于用于索引 a 的向量
sapply(seq(length(a)), function(i) sum(a[(i-1):(i 1)], na.rm=TRUE))
如果你想把它作為一個功能
solution <- function(x) {
sapply(seq(length(x)), function(i) sum(x[(i-1):(i 1)],
na.rm=TRUE))
}
uj5u.com熱心網友回復:
我認為您的困惑在于numeric(0)which 而不是NULL實際上是長度為零的向量。
is.null(numeric(0))
# [1] FALSE
length(numeric(0)) == 0
# [1] TRUE
您可以將這三個a[.]放在 a 中list A,如果它們的長度為零或為零則替換它們NA,然后使用串列元素進行計算。b可以使用vector更有效的特定長度(因為它是已知的)來初始化向量。我不知道為什么n需要在所有的,當我們遍歷沿著序列a使用seq_along()。
solutionA <- function(a) {
b <- vector('numeric', length(a))
for (i in seq_along(a)) {
A <- list(a[i - 1], a[i], a[i 1])
for (j in seq_along(A)) {
if (length(A[[j]]) == 0 || is.na(A[[j]])) {
A[[j]] <- 0
}
}
b[i] <- A[[1]] A[[2]] A[[3]]
}
return(b)
}
solutionA(z)
# [1] 4 5 -1 2 1
為了速度,我們可以使用vapply(),這類似于@rg255的解決方案,除了初始化型別"numeric"為0.
solutionC <- function(x) {
vapply(seq_along(x), \(i) sum(x[(i - 1):(i 1)], na.rm=TRUE), 0)
}
solutionC(z)
# [1] 4 5 -1 2 1
這是一個基準:
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# for 103.0531 110.3464 119.5067 115.9603 126.5834 167.9031 100 b
# sapply 107.2445 118.2517 127.2979 124.0168 131.2903 192.3599 100 c
# vapply 102.2778 109.1570 114.6262 113.8659 119.3710 135.1884 100 a
代碼:
z1 <- rep(z, 1e5)
microbenchmark::microbenchmark('for'=solution_jayFor(z1),
sapply=solution_rg255(z1),
vapply=solution_jayVapply(z1),
times=10L, control=list(warmup=10L))
uj5u.com熱心網友回復:
由于這是一個向量,您可以在沒有任何回圈的情況下執行此操作,只需對滯后、值和領先進行求和。這為您提供了第一個和最后一個值的 NA 值的向量,您將其轉換為 0。
z <- c(4, 0, 1, -2, 3)
solution <- function(z) {
z <- lag(z) z lead(z)
z[is.na(z)] <- 0
z
}
solution(z)
# [1] 0 5 -1 2 0
編輯,因為不清楚如何解釋 OP 的“如果這些 a[i-1] a[i] a[i 1] 元素中的任何一個不存在,則應將其設定為等于 0。” 具有上述預期輸出的解決方案。
solution <- function(z) {
z <- c(0, z, 0)
z <- lag(z) z lead(z)
z[!is.na(z)]
}
solution(z)
# [1] 4 5 -1 2 1
甚至更短的單線
solution <- function(z) {
c(0, na.omit(lag(z))) z c(na.omit(lead(z)), 0)
}
solution(z)
# [1] 4 5 -1 2 1
所有答案的基準
好吧,讓我們做一些基準測驗,看看為什么要防止任何回圈,甚至在不是 100% 需要時應用函式。當然,我為此增加了矢量大小。
set.seed(42)
z <- sample(-5:5, 100000L, replace = TRUE)
solution1 <- function(z) {
z <- c(0, z, 0)
z <- lag(z) z lead(z)
z[!is.na(z)]
}
solution2 <- function(z) {
c(0, na.omit(lag(z))) z c(na.omit(lead(z)), 0)
}
solution3 <- function(x) {
sapply(seq(length(x)), function(i) sum(x[(i-1):(i 1)], na.rm=TRUE))
}
solution4 <- function(a) {
b <- vector('numeric', length(a))
for (i in seq.int(a)) {
A <- list(a[i - 1], a[i], a[i 1])
for (j in seq.int(A)) {
if (length(A[[j]]) == 0 || is.na(A[[j]])) {
A[[j]] <- 0
}
}
b[i] <- A[[1]] A[[2]] A[[3]]
}
return(b)
}
solution5 = function(a) {
a = c(0, a, 0)
a[is.na(a)] = 0
b = c()
for (i in seq_along(a)) {
b[i] = a[i - 1] a[i] a[i 1]
}
b
}
library(rbenchmark)
benchmark(
"solution1" = {
solution1(z)
},
"solution2" = {
solution2(z)
},
"solution3" = {
solution3(z)
},
"solution4" = {
solution4(z)
},
"solution5" = {
solution5(z)
},
replications = 50,
columns = c("test", "replications", "elapsed", "relative")
)
test replications elapsed relative
1 solution1 50 0.27 1.35
2 solution2 50 0.20 1.00
3 solution3 50 10.82 54.10
4 solution4 50 12.15 60.75
5 solution5 50 1.73 8.65
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/393466.html
標籤:r
