Как получить доступ к элементу вектора при использовании lapply над списком - PullRequest
1 голос
/ 01 ноября 2019

Я хочу добавить строки во фрейм данных таким образом, чтобы первый столбец содержал все числа от 1 до 10, а во втором столбце должен быть определенный вывод.

Я могу сделать это, используяцикл for, как показано ниже:

Dt <- data.frame(ID = c(1,2,5,7,8), Value = "x", stringsAsFactors = FALSE)
Special_cases <- c(3,4)

for (i in 1:10){

  if( i %in% Dt$ID){

    Dt <- Dt

  } else if (i %in% Special_cases){

    Dt <- rbind(Dt, c(i,"y"))

  } else {

    Dt <- rbind(Dt, c(i,"z"))

  }

}

 ID Value
1   1     x
2   2     x
3   5     x
4   7     x
5   8     x
6   3     y
7   4     y
8   6     z
9   9     z
10 10     z

Хотя это работает, я хочу избавиться от этой вредной привычки использовать циклы for, но я изо всех сил пытался переписать это с помощью lapply. Я не уверен, что делать с первым оператором if, когда я вызываю i.

Так как же я могу преобразовать этот цикл for в lapply? Я также не уверен, каким будет первый аргумент Лаппли.

Ответы [ 2 ]

1 голос
/ 06 ноября 2019

Здесь был бы другой способ использования слияний из dplyr

library(dplyr)
data.frame(ID=1:10) %>% left_join(Dt) %>% 
  left_join(tibble(ID=Special_cases, Value2="y")) %>% 
  mutate(Value=coalesce(Value, Value2, "z"), Value2=NULL)

Или другой способ, который не включает циклы или лапы. Просто посмотрите, чего не хватает, и добавьте все это за один раз.

if (any(!Special_cases %in% Dt$ID)) {
  Dt <- rbind(Dt, data.frame(ID = setdiff(Special_cases, Dt$ID), Value = "y", stringsAsFactors = FALSE))
}
if (any(!1:10 %in% Dt$ID)) {
  Dt <- rbind(Dt, data.frame(ID = setdiff(1:10, Dt$ID), Value = "z", stringsAsFactors = FALSE))
}
1 голос
/ 01 ноября 2019

Я уверен, что есть более элегантное решение, но оно работает. Сначала запустите lapply над вашим вектором нужных идентификаторов, создав список фреймов данных из одной строки в соответствии с вашими спецификациями.

results <- lapply(seq(10), function(i) {

    if (i %in% Dt$ID) {

        Dt[which(Dt$ID==i),]

    } else if (i %in% c(3,4)) {

        data.frame(ID = i, Value = "y")        

    } else {

        data.frame(ID = i, Value = "z") 

    }

})

Затем сверните этот список в фрейм данных. Вы также можете свернуть это на предыдущем шаге, вложив вызов в lapply, где здесь появляется results.

Dt2 <- do.call(rbind.data.frame, results)

Если вы не возражаете ввести зависимость от tidyverse 'или purrr в частности, вы также можете заменить map_dfr на lapply в блоке кода выше, и это приведет к сворачиванию результирующего списка в один фрейм данных на том же шаге. Обратите внимание, что он также выдаст предупреждения о преобразовании фактора в символ, чтобы сделать это, даже если все эти идентификаторы были символами в первую очередь.

Вот результат. Обратите внимание, что вам все равно придется сортировать в соответствии с Value, если вы заботитесь о группировке объектов по этой функции.

   ID Value
1   1     x
2   2     x
11  3     y
12  4     y
3   5     x
13  6     z
4   7     x
5   8     x
14  9     z
15 10     z
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...