比方说,我有一个a
和length(a) = l
的向量l >= 1
。
元素"x"
在a
中至少发生一次,但我们不知道确切位置。
我想用值"x"
替换a
中的每个c(1,2,3)
例如:a = ("y","x","z")
,那么我希望替换后的结果为a = ("y",1,2,3,"z")
。
我想这样做:
l <- length(a)
pos.x <- which(a == "x")
if(l == 1L & pos.x == 1L) {
a <- c(1,2,3)
} else if (l > 1L & pos.x == 1) {
a <- c(1,2,3,a[-1])
} else if (l > 1L & pos.x == l) {
a <- c(a[-l],1,2,3)
} else if (l >= 3 & pos.x != 1 & pos.x != l) {
a <- c(a[1:(pos.x - 1)],1,2,3,a[(pos.x + 1):l])
}
虽然此代码确实有效,但我的问题是,是否存在一种更“优雅”的方法来解决此问题,需要更少的处理能力并且可以替换多个"x"
。
谢谢!
答案 0 :(得分:4)
这是一个以R为底的简单向量化解决方案-
a <- c("y","x","z","y","x","z") # vector to search
b <- 1:3 # replacement values
a <- rep(a, 1 + (length(b) - 1)*(a == "x")) # repeat only "x" length(b) times
a[a == "x"] <- b # replace "x" with replacement values i.e. b
[1] "y" "1" "2" "3" "z" "y" "1" "2" "3" "z"
答案 1 :(得分:3)
这里是使用for
循环的选项
a <- c("y","x","z","y","x","z")
b <- c(1,2,3)
“技巧”是先创建一个列表,然后将所有"x"
替换为b
,最后调用unlist
。
a_list <- as.list(a)
for(i in which(a_list == "x")) {
a_list[[i]] <- b
}
结果
unlist(a_list)
#[1] "y" "1" "2" "3" "z" "y" "1" "2" "3" "z"
请考虑@Shree的答案!
这是原因:
n <- 1e6
set.seed(1)
a <- sample(c("x", "y", "z"), size = n, replace = TRUE)
b <- 1:3
library(microbenchmark)
benchmark <- microbenchmark(
markus = markus(a, b),
IceCreamToucan = IceCreamToucan(a, b),
Shree = Shree(a, b)
)
autoplot(benchmark)
#Unit: milliseconds
# expr min lq mean median uq max neval
# markus 403.38464 467.03277 615.8078 556.74067 754.5117 1095.7035 100
#IceCreamToucan 401.34614 462.92680 602.1556 526.08280 687.8436 1422.0629 100
# Shree 52.33867 65.32323 157.6680 97.34066 162.0638 650.2571 100
功能
markus <- function(a, b) {
a_list <- as.list(a)
for(i in which(a_list == "x")) {
a_list[[i]] <- b
}
unlist(a_list)
}
Shree <- function(a, b) {
a <- rep(a, 1 + (length(b) - 1)*(a == "x"))
a[a == "x"] <- b
a
}
# from the comments
IceCreamToucan <- function(a, b) {
a_list <- as.list(a)
w <- which(a_list == "x")
a_list[w] <- rep(list(b), length(w)) # changed your answer slightly here
unlist(a_list)
}