dplyr мутировать с условными значениями
В большом фрейме данных ("myfile") с четырьмя столбцами мне нужно добавить пятый столбец со значениями, условно основанными на первых четырех столбцах.
Предпочитайте ответы с помощью dplyr
и mutate
, главным образом из-за его скорости в больших наборах данных.
Мой фрейм данных выглядит так:
V1 V2 V3 V4
1 1 2 3 5
2 2 4 4 1
3 1 4 1 1
4 4 5 1 3
5 5 5 5 4
...
Значения пятого столбца (V5) основаны на некоторых условных правилах:
if (V1==1 & V2!=4) {
V5 <- 1
} else if (V2==4 & V3!=1) {
V5 <- 2
} else {
V5 <- 0
}
Теперь я хочу использовать функцию mutate
чтобы использовать эти правила во всех строках (чтобы избежать медленных циклов). Примерно так (и да, я знаю, что так не работает!):
myfile <- mutate(myfile, if (V1==1 & V2!=4){V5 = 1}
else if (V2==4 & V3!=1){V5 = 2}
else {V5 = 0})
Это должно быть результатом:
V1 V2 V3 V4 V5
1 1 2 3 5 1
2 2 4 4 1 2
3 1 4 1 1 0
4 4 5 1 3 0
5 5 5 5 4 0
Как это сделать в dplyr
?
Ответы
Ответ 1
Попробуй это:
myfile %>% mutate(V5 = (V1 == 1 & V2 != 4) + 2 * (V2 == 4 & V3 != 1))
давая:
V1 V2 V3 V4 V5
1 1 2 3 5 1
2 2 4 4 1 2
3 1 4 1 1 0
4 4 5 1 3 0
5 5 5 5 4 0
или это:
myfile %>% mutate(V5 = ifelse(V1 == 1 & V2 != 4, 1, ifelse(V2 == 4 & V3 != 1, 2, 0)))
давая:
V1 V2 V3 V4 V5
1 1 2 3 5 1
2 2 4 4 1 2
3 1 4 1 1 0
4 4 5 1 3 0
5 5 5 5 4 0
Заметка
Предлагаю вам получить лучшее имя для вашего фрейма данных. myfile создает впечатление, что он содержит имя файла.
Выше использовали этот вход:
myfile <-
structure(list(V1 = c(1L, 2L, 1L, 4L, 5L), V2 = c(2L, 4L, 4L,
5L, 5L), V3 = c(3L, 4L, 1L, 1L, 5L), V4 = c(5L, 1L, 1L, 3L, 4L
)), .Names = c("V1", "V2", "V3", "V4"), class = "data.frame", row.names = c("1",
"2", "3", "4", "5"))
Обновление 1 Поскольку dplyr изначально опубликовал, изменил %.%
%>%
поэтому изменил ответ соответствующим образом.
Обновление 2 dplyr теперь имеет case_when
который предоставляет другое решение:
myfile %>%
mutate(V5 = case_when(V1 == 1 & V2 != 4 ~ 1,
V2 == 4 & V3 != 1 ~ 2,
TRUE ~ 0))
Ответ 2
С dplyr 0.7.2
вы можете использовать очень полезную функцию case_when
:
x=read.table(
text="V1 V2 V3 V4
1 1 2 3 5
2 2 4 4 1
3 1 4 1 1
4 4 5 1 3
5 5 5 5 4")
x$V5 = case_when(x$V1==1 & x$V2!=4 ~ 1,
x$V2==4 & x$V3!=1 ~ 2,
TRUE ~ 0)
Выраженный dplyr::mutate
, он дает:
x = x %>% mutate(
V5 = case_when(
V1==1 & V2!=4 ~ 1,
V2==4 & V3!=1 ~ 2,
TRUE ~ 0
)
)
Обратите внимание, что к NA
не обращаются специально, так как это может ввести в заблуждение. Функция вернет NA
только тогда, когда не найдено ни одного условия. Если вы поставите строку с TRUE ~...
, как я делал в моем примере, возвращаемое значение никогда не будет NA
.
Следовательно, вы должны выразительно сказать case_when
поместить NA
на место, добавив оператор, подобный is.na(x$V1) | is.na(x$V3) ~ NA_integer_
is.na(x$V1) | is.na(x$V3) ~ NA_integer_
. Подсказка: dplyr::coalesce()
иногда может быть очень полезна здесь!
Кроме того, обратите внимание, что одно только NA
обычно не будет работать, вы должны NA_integer_
специальные значения NA
: NA_integer_
, NA_character_
или NA_real_
.
Ответ 3
Похоже, что derivedFactor
из пакета mosaic
был разработан для этого. В этом примере это выглядит примерно так:
library(mosaic)
myfile <- mutate(myfile, V5 = derivedFactor(
"1" = (V1==1 & V2!=4),
"2" = (V2==4 & V3!=1),
.method = "first",
.default = 0
))
(Если вы хотите, чтобы результат был числовым вместо фактора, оберните derivedFactor
с помощью as.numeric
.)
Обратите внимание, что параметр .default
в сочетании с .method = "first"
устанавливает условие "else" - этот подход описан в файле справки для derivedFactor
.