вернуть значение ifelse из другого вектора через индекс - PullRequest
0 голосов
/ 16 февраля 2019

Я не могу разобраться с этой проблемой, касающейся 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 делает это?

Ответы [ 5 ]

0 голосов
/ 16 февраля 2019

x <- c (0, 1: 4, 1: 4) y <- буквы [1: 3] </p>

ifelse (x == 2, y [x], x)

в ifelse он будет проверять каждую позицию в x. Если это правда, то он будет печатать y [x] position, это означает позицию, которая была проверена в x, и эта позиция значения в Y будет напечатана .it проверит всезначения в X

0 голосов
/ 16 февраля 2019

Результат происходит в обратном направлении, потому что функция == возвращает вектор логики:

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

Это логический вектор, который имеет истину в третьей позиции, а не во второй, поэтому это третье значениеиз у, который выбран.Это также показывает, почему ответ, который ссылается на поведение which, является неправильным.

0 голосов
/ 16 февраля 2019

Вы используете 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] отличается от длины х.

То, что вы хотите, это

> 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, хотя х есть длина9.

Так что это вообще не имеет отношения к ifelse (), это действительно другая проблема с утилизацией.

0 голосов
/ 16 февраля 2019

Для объяснения этого странного поведения полезен исходный код 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являются NA, поэтому аргумент `yes´ становится

[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 для использования логического индекса для выбора "TRUE" -результатов из 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
}
0 голосов
/ 16 февраля 2019

Из комментария: Возвращает c, потому что: which(x==2) возвращает 3 и 7. Я не знаю, почему он не перерабатывает 7, а выбирает только 3. Возможно, потому что у меньшедлина 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...