л / саппли игнорирует условную замену - PullRequest
0 голосов
/ 01 июля 2018

У меня довольно сложная структура данных со списком списков, каждый из которых, в свою очередь, имеет числовые векторы различной длины. Мне нужно заменить некоторые значения в векторах на NA, основываясь на отдельном векторе той же длины, что и основной список. Но вместо того, чтобы заменять только определенные значения, R заменяет весь вектор. Сильфон, пример:

> ## Minimal example with a list of vectors
> # Creating list
> mylist = rep(list(1:3), 3)
> 
> # Vector on which I will base the replacement
> myvec = 1:3
> 
> # Replacing 1s by NA
> for(i in 1:length(mylist)){
+   mylist[[i]] = sapply(mylist[[i]], function(x) x[x ==myvec[i]] = NA)
+ }
> 
> # But I get NAs for every observation
> mylist
[[1]]
[1] NA NA NA

[[2]]
[1] NA NA NA

[[3]]
[1] NA NA NA

> 
> # This is what I wanted:
> list(c(NA, 2, 3), c(1, NA, 3), c(1, 2, NA))
[[1]]
[1] NA  2  3

[[2]]
[1]  1 NA  3

[[3]]
[1]  1  2 NA

> 
> 
> ## More complex example, with a list of lists of vectors that more closely approximates my data structure
> # Creating list of lists
> mynewlist = rep(list(rep(list(1:3), 3)), 3)
> 
> # Replacing 1s by NAs
> for(i in 1:length(mynewlist)){
+   mynewlist[[i]] = lapply(mynewlist[[i]], function(x) x[x ==myvec[i]] = NA)
+ }
> 
> # But now each vector becomes a single NA
> mynewlist
[[1]]
[[1]][[1]]
[1] NA

[[1]][[2]]
[1] NA

[[1]][[3]]
[1] NA


[[2]]
[[2]][[1]]
[1] NA

[[2]][[2]]
[1] NA

[[2]][[3]]
[1] NA


[[3]]
[[3]][[1]]
[1] NA

[[3]][[2]]
[1] NA

[[3]][[3]]
[1] NA


> 
> # What I wanted:
> list(rep(list(c(NA, 2, 3)), 3), rep(list(c(1, NA, 3)), 3), rep(list(c(1, 2, NA)), 3))
[[1]]
[[1]][[1]]
[1] NA  2  3

[[1]][[2]]
[1] NA  2  3

[[1]][[3]]
[1] NA  2  3


[[2]]
[[2]][[1]]
[1]  1 NA  3

[[2]][[2]]
[1]  1 NA  3

[[2]][[3]]
[1]  1 NA  3


[[3]]
[[3]][[1]]
[1]  1  2 NA

[[3]][[2]]
[1]  1  2 NA

[[3]][[3]]
[1]  1  2 NA

Обратите внимание, что то же самое происходит независимо от конкретного значения замещения (если вместо NA я заменяю замену, например, на 0, тогда 0 заменяет все значения, независимо от условия).

Что происходит? Почему lapply / sapply игнорирует условие?

Кстати, я приветствую предложения сделать это без циклов for.

Редактировать: в дополнение к редактированию кода выше, чтобы прояснить, что я основываю замену на отдельном векторе (отсюда цикл for), я смог получить то, что я хочу, с помощью ifelse. Я до сих пор не понимаю, почему l / sapply не распознает выбор и замену в скобках. Буду признателен за любое объяснение этого, а также о том, как сделать это без цикла.

Код с ifelse:

> # Creating list of lists
> mynewestlist = rep(list(rep(list(1:3), 3)), 3)
> 
> # Replacing 1s by NAs
> for(i in 1:length(mynewestlist)){
+   mynewestlist[[i]] = lapply(mynewestlist[[i]], function(x) ifelse(x ==myvec[i], NA, x))
+ }
> 
> # That's better:
> mynewestlist
[[1]]
[[1]][[1]]
[1] NA  2  3

[[1]][[2]]
[1] NA  2  3

[[1]][[3]]
[1] NA  2  3


[[2]]
[[2]][[1]]
[1]  1 NA  3

[[2]][[2]]
[1]  1 NA  3

[[2]][[3]]
[1]  1 NA  3


[[3]]
[[3]][[1]]
[1]  1  2 NA

[[3]][[2]]
[1]  1  2 NA

[[3]][[3]]
[1]  1  2 NA


> list(rep(list(c(NA, 2, 3), 3), rep(list(1, NA, 3), 3), rep(list(1, 2, NA), 3))

1 Ответ

0 голосов
/ 02 июля 2018

Нет необходимости иметь sapply для запуска на каждом элементе list элемента, поскольку мы можем сделать это в векторизованной форме.

lapply(mylist, function(x) replace(x, x <=1, NA))

или с for петлей

for(i in seq_along(mylist)) mylist[[i]] <- replace(mylist[[i]], 
                          mylist[[i]] <=1, NA)

Обратите внимание, что OP изменил условие, то есть создал вектор ('myvec') такой же длины, что и 'mylist', и хочет заменить те значения, которые соответствуют соответствующим элементам 'mylist', на NA. Это можно сделать разными способами. Одним из вариантов является Map для циклического прохождения каждого из элементов list и vector и replace значения, соответствующего NA.

Map(function(x, y) replace(x, x == y, NA), mylist, myvec)
#[[1]]
#[1] NA  2  3

#[[2]]
#[1]  1 NA  3

#[[3]]
#[1]  1  2 NA

или с for петлей

for(i in seq_along(mylist)) mylist[[i]] <- replace(mylist[[i]], 
                      mylist[[i]] == myvec[i], NA)

Или используя lapply, просматривая последовательность

lapply(seq_along(mylist) function(i) 
          replace(mylist[[i]], mylist[[i]] == myvec[i], NA))

Что касается того, почему OP получает только NA, в sapply возвращаемое значение является присваиванием NA, а не самим объектом. Проверьте вывод lapply/sapply здесь

lapply(mylist[[1]], function(x) x[x==myvec[1]] <- NA)
#[[1]]
#[1] NA

#[[2]]
#[1] NA

#[[3]]
#[1] NA

Это значение присваивания вместо 'x'. Вернуть 'x', чтобы получить вывод 'x' (как прокомментировал @ user20650)

lapply(mylist[[1]], function(x) {x[x==myvec[1]] <- NA; x})
#[[1]]
#[1] NA

#[[2]]
#[1] 2

#[[3]]
#[1] 3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...