Я не могу понять эту проблему относительно ifelse:
Скажем, у меня есть два вектора:
x <- c(0, 1:4, 1:4)
y <- letters[1:3]
Когда я делаю
ifelse(x==2, y[x], x)
я получил
"0" "1" "c" "3" "4" "1" "c" "3" "4"
Однако он должен вернуть "b" в позицию 2 вектора y.
Почему ifelse это делает?
спасибо, но это просто простой пример для иллюстрации. Я хочу, чтобы индекс возврата был динамическим. плюс я действительно хотел бы понять, что здесь происходит
Он возвращает c, потому что: which(x==2) возвращает 3 and 7. Я не знаю, почему он не перерабатывает 7, а выбирает только 3. Возможно, потому, что длина y меньше 7.
y[x] возвращает это: "a" "b" "c" NA "a" "b" "c" NA, я полагаю, что с 0 в качестве индекса R преобразует x из числового в множитель, а возврат 2 становится третий элемент. Я не могу найти никаких документов, подтверждающих эту теорию.
Однако это не фактор, это вектор символов (проверено на результат).





Из комментария: Он возвращает c, потому что: which(x==2) возвращает 3 и 7. Я не знаю, почему он не перерабатывает 7, а выбирает только 3. Возможно, потому что y меньше длины 7
Пытаться:
ind<-which(x==2)
ind1<-ind[1]-1
ifelse(x==2,y[ind1],x)
[1] "0" "1" "b" "3" "4" "1" "b" "3" "4"
Вот попытка сделать функцию:
dynamic_index<-function(ind,x,y){
x<-x
y<-y
ind1<-which(x==ind)
ind2<-ind1[1]-1
ifelse(x==ind,y[ind2],x)
}
dynamic_index(2,x,y)
Вы используете 0 в качестве индекса в первом элементе, поэтому выравнивание испорчено.
y[x]
[1] "a" "b" "c" NA "a" "b" "c" NA
Так
> y[0]
character(0)
> y[1]
[1] "a"
> y[2]
[1] "b"
> y[3]
[1] "c"
Таким образом, длина y[x] отличается от длины x.
То, что вы хотите, это
> ifelse(x==2, y[x+1], x)
[1] "0" "1" "c" "3" "4" "1" "c" "3" "4"
но только если первый элемент всегда равен 0.
Старый ответ Так как
x <- c(0, 1:4, 1:4)
возвращается
[1] 0 1 2 3 4 1 2 3 4
так x==2
возвращается
1] FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE
так для y = letters[1:3]
ifelse(x==2, y[x], x)
Вы получите буквы на третьей и седьмой позициях.
В документации для ifelse говорится, что если один вектор слишком короткий, он будет переработан, что вы и ожидаете.
c("a","b","c","a","b","c","a").
Однако, когда я пытаюсь
ifelse(x==3, y[x], x)
я получил
[1] "0" "1" "2" NA "4" "1" "2" NA "4"
Что говорит мне о том, что переработка работает не так, как я ожидал.
Так что это номинальная причина, по которой вы получаете результат. Причина, по которой это работает, - это то, чего я сейчас не знаю, но если я выясню это, я добавлю к этому ответу. Я подозреваю, что это связано с преобразованием в строку.
Просто глядя на y[x] я понимаю
[1] "a" "b" "c" NA "a" "b" "c" NA
Что, кстати, имеет длину всего 8, хотя x имеет длину 9.
Так что на самом деле это вообще не имеет отношения к ifelse(), это действительно другая проблема с переработкой.
Для объяснения этого странного поведения полезен исходный код ifelse (см. ниже).
Как только вы вызываете ifelse, выражения, переданные в качестве аргументов test, yes и no, оцениваются, что приводит к:
Browse[2]> test
[1] FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE
Browse[2]> yes
[1] "a" "b" "c" NA "a" "b" "c" NA
Browse[2]> no
[1] 0 1 2 3 4 1 2 3 4
Обратите внимание, что y[x] использует значения x для выбора значений из y.
и значение 0 пусто (= игнорируется), значения выше 3 - нет данных,
вот почему аргумент «да» становится
[1] "a" "b" "c" NA "a" "b" "c" NA
Строка кода
ans[test & ok] <- rep(yes, length.out = length(ans))[test & ok]
затем применяется в конце и эффективно обновляет все TRUE-элементы, используя логический вектор test:
yes[test]
что приводит к:
[1] "c" "c"
хранится в результирующих индексах 3 и 7
ans[test & ok]
Таким образом, проблема заключается в использовании y[x] в качестве второго аргумента для ifelse + неинтуитивное поведение ifelse для использования логического индекса для выбора «ИСТИННЫХ» результатов из y[x]...
Извлеченный урок: избегайте сложной логики ifelse, она имеет много побочных эффектов (например, вы можете потерять правильный тип данных или атрибуты).
# ifelse function
function (test, yes, no)
{
if (is.atomic(test)) {
if (typeof(test) != "logical")
storage.mode(test) <- "logical"
if (length(test) == 1 && is.null(attributes(test))) {
if (is.na(test))
return(NA)
else if (test) {
if (length(yes) == 1) {
yat <- attributes(yes)
if (is.null(yat) || (is.function(yes) && identical(names(yat),
"srcref")))
return(yes)
}
}
else if (length(no) == 1) {
nat <- attributes(no)
if (is.null(nat) || (is.function(no) && identical(names(nat),
"srcref")))
return(no)
}
}
}
else test <- if (isS4(test))
methods::as(test, "logical")
else as.logical(test)
ans <- test
ok <- !(nas <- is.na(test))
if (any(test[ok]))
ans[test & ok] <- rep(yes, length.out = length(ans))[test &
ok]
if (any(!test[ok]))
ans[!test & ok] <- rep(no, length.out = length(ans))[!test &
ok]
ans[nas] <- NA
ans
}
Ваше использование выражения x[y], вероятно, следует исправить на y[x]
Результат получается латентным, потому что функция == возвращает вектор логики:
x <- c(0, 1:4, 1:4)
y <- letters[1:3]
ifelse(x==2, y[x], x)
#look at x==2
x==2
[1] FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE
Это логический вектор, который имеет true в третьей позиции, а не во второй, поэтому выбирается третье значение y. Это также показывает, почему ответ, который ссылается на поведение which, неверен.
Почему же поведение which некорректно? Мы видим, что x==2 имеет значение TRUE дважды, то есть в позициях 3 и 7.
Ответ which неверен, потому что исходный код ifelse не использует which, но ИМХО косвенно верен, потому что логический вектор все равно выбирает значения этих индексов ;-)
Ах, да, но это все тот же результат, независимо от того, какой код использует ifelse (по моему скромному и менее опытному мнению). which — это просто вспомогательная функция (imhleo)
Это было утверждение «Я не знаю, почему он не перерабатывает 7», которое заставило меня подумать, что использование которого привело к определенному недоумению.
х <- с(0, 1:4, 1:4) у <- буквы [1:3]
если иначе (х == 2, у [х], х)
в ifelse он проверит каждую позицию в x. Если это правда, то он напечатает позицию y[x], это означает, что позиция, которая была проверена в x, и эта позиция значения в Y будет напечатана. он проверит все значения в Икс
Не совсем уверен, что происходит с
ifelse, но если вы всегда хотите 2-е местоy, почему бы и нетifelse(x == 2, y[2], x)?