R: заменить значение вектора несколькими значениями - PullRequest
0 голосов
/ 05 декабря 2018

Допустим, у меня есть вектор 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".

Спасибо!

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

Вот простое векторизованное решение с базой 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"
0 голосов
/ 05 декабря 2018

Здесь есть опция, использующая for loop

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)

enter image description here

#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)
}
...