Можно ли использовать мутацию, если она является условной (в зависимости от значений определенных значений столбца)?
Этот пример помогает показать, что я имею в виду.
structure(list(a = c(1, 3, 4, 6, 3, 2, 5, 1), b = c(1, 3, 4,
2, 6, 7, 2, 6), c = c(6, 3, 6, 5, 3, 6, 5, 3), d = c(6, 2, 4,
5, 3, 7, 2, 6), e = c(1, 2, 4, 5, 6, 7, 6, 3), f = c(2, 3, 4,
2, 2, 7, 5, 2)), .Names = c("a", "b", "c", "d", "e", "f"), row.names = c(NA,
8L), class = "data.frame")
a b c d e f
1 1 1 6 6 1 2
2 3 3 3 2 2 3
3 4 4 6 4 4 4
4 6 2 5 5 5 2
5 3 6 3 3 6 2
6 2 7 6 7 7 7
7 5 2 5 2 6 5
8 1 6 3 6 3 2
Я надеялся найти решение моей проблемы с помощью пакета dplyr (и да, я знаю, что это не тот код, который должен работать, но я предполагаю, что это проясняет цель) для создания нового столбца g:
library(dplyr)
df <- mutate(df,
if (a == 2 | a == 5 | a == 7 | (a == 1 & b == 4)){g = 2},
if (a == 0 | a == 1 | a == 4 | a == 3 | c == 4) {g = 3})
Результат кода, который я ищу, должен иметь этот результат в этом конкретном примере:
a b c d e f g
1 1 1 6 6 1 2 3
2 3 3 3 2 2 3 3
3 4 4 6 4 4 4 3
4 6 2 5 5 5 2 NA
5 3 6 3 3 6 2 NA
6 2 7 6 7 7 7 2
7 5 2 5 2 6 5 2
8 1 6 3 6 3 2 3
У кого-нибудь есть идеи как это сделать в dplyr? Этот фрейм данных - только пример, фреймы данных, с которыми я имею дело, намного больше. Из-за его скорости я пытался использовать dplyr, но, возможно, есть и другие, более эффективные способы решения этой проблемы?
dplyr::case_when()
гораздо яснее , чемifelse
,Ответы:
использование
ifelse
Добавлено - if_else: Обратите внимание, что в dplyr 0.5 определена
if_else
функция, поэтому альтернативой будет заменаifelse
наif_else
; однако, обратите внимание, что посколькуif_else
он более строг, чемifelse
(обе части условия должны иметь одинаковый тип), тоNA
в этом случае его следует заменить наNA_real_
.Added - case_when Так как этот вопрос был опубликован, dplyr добавил
case_when
еще одну альтернативу:Добавлено - арифметика / na_if. Если значения являются числовыми, а условия (за исключением значения по умолчанию NA в конце) являются взаимоисключающими, как в случае с вопросом, то мы можем использовать арифметическое выражение так, чтобы каждый член умножался по желаемому результату, используя
na_if
в конце заменить 0 на NA.источник
NA
, чтобы я хотел, чтобы строки, которые не удовлетворяли условиям, оставались неизменными?mutate(g = ifelse(condition1, 2, ifelse(condition2, 3, g))
Поскольку вы просите другие более эффективные способы решения этой проблемы, используйте другой способ
data.table
:Обратите внимание, что порядок условных операторов меняется на
g
правильный. Сделанной копии нетg
даже во время второго задания - она заменяется на месте .На больших данных это будет иметь лучшую производительность, чем использование вложенных
if-else
, поскольку он может оценивать случаи как «да», так и «нет» , а вложение может усложнить чтение / поддержку IMHO.Вот эталон относительно больших данных:
Не уверен, что это альтернатива, которую вы просили, но я надеюсь, что это поможет.
источник
DT_fun
происходит изменение входных данных на месте, эталонный тест может быть не совсем справедливым - в дополнение к тому, что он не получает тот же входной сигнал от 2-й итерации вперед (что может повлиять на время, такDT$g
как он уже выделен?), Результат также распространяется обратноans1
и, следовательно, может ( если АиР оптимизатор сочтет это необходимым? Не уверен , что на этом ...) избежать другой копии,DPLYR_fun
иBASE_fun
нужно сделать?data.table
отличное решение, и я используюdata.table
везде, где мне действительно нужна скорость для операций с таблицами, и я не хочу переходить к C ++. Это действительно требует быть очень осторожным с изменениями на месте, хотя!У dplyr теперь есть функция,
case_when
которая предлагает векторизацию if. Синтаксис немного странный по сравнению с тем,mosaic:::derivedFactor
что вы не можете получить доступ к переменным стандартным способом dplyr, и вам нужно объявить режим NA, но он значительно быстрее, чемmosaic:::derivedFactor
.РЕДАКТИРОВАТЬ: Если вы используете
dplyr::case_when()
пакет до версии 0.7.0, то перед именами переменных должен стоять символ '.$
' (например, запись.$a == 1
внутриcase_when
).Тест : Для теста (повторное использование функций из поста Аруна) и уменьшение размера выборки:
Это дает:
источник
case_when
также можно записать как:df %>% mutate(g = with(., case_when(a %in% c(2,5,7) | (a==1 & b==4) ~ 2L, a %in% c(0,1,3,4) | c==4 ~ 3L, TRUE ~ NA_integer_)))
.$
больше в новой версии dplyrderivedFactor
Функция изmosaic
пакета , кажется, предназначена для обработки этого. Используя этот пример, это будет выглядеть так:(Если вы хотите, чтобы результат был числовым, а не коэффициентом, вы можете
derivedFactor
заключитьas.numeric
вызов.)derivedFactor
можно использовать и для произвольного числа условных выражений.источник
.asFactor = F
опцию или (аналогичную)derivedVariable
функцию в том же пакете.recode
из dplyr 0.5 это будет сделано. Я еще не исследовал это все же. См. Blog.rstudio.org/2016/06/27/dplyr-0-5-0case_when
теперь довольно чистая реализация случая в стиле SQL, когда:Использование dplyr 0.7.4
Руководство: http://dplyr.tidyverse.org/reference/case_when.html
источник