#r #dplyr
#r #dplyr
Вопрос:
У меня есть набор данных, в котором каждые две строки являются частью набора выбора, который будет использоваться для дискретного анализа выбора в mlogit. Я хочу удалить все строки, связанные с набором выбора, на основе значений в столбце.
Например, с помощью этого простого набора данных, допустим, я хотел удалить все пары, в которых в одной из строк пары было желтое значение (пары, определенные здесь с помощью «Set»).
Я предполагаю, что должен быть простой способ сказать, соответствует ли это значение = «x» , и это значение этого другого столбца соответствует значению этой строки, удалите оба. Я полагаю, что это должно быть как-то связано с ifelse или case_when в dplyr, но это часть с соответствующим значением, в которой я не уверен. В Excel я бы использовал ссылку на ячейку для выполнения простого if_then, но не уверен, что лучший способ сделать это в R. Спасибо!
data <- data.frame(Set = sort(rep(1:20,2)),
Choice = rep(c(T,F),20),
Color = sample(
rep(c("Red","Blue","Green","Yellow"),5)))
Ответ №1:
Вы можете выбрать те set
, которые имеют все значения в Color
столбце, которых нет 'Yellow'
.
library(dplyr)
data %>% group_by(Set) %>% filter(all(Color != 'Yellow'))
Или другой способ написать это было бы :
data %>% group_by(Set) %>% filter(!any(Color == 'Yellow'))
Это также может быть записано в базе R
subset(data, ave(Color != 'Yellow', Set, FUN = all))
и data.table
:
library(data.table)
setDT(df)[, .SD[all(Color != 'Yellow')], Set]
Комментарии:
1. Удивительное дополнение, если бы я хотел фильтровать по двум переменным, сработало бы это
data %>% group_by(Set) %>% filter(!any(Color == 'Yellow'| Color == 'Blue"))
2. Да, это сработало бы. Также вы можете использовать
%in%
:data %>% group_by(Set) %>% filter(!any(Color %in% c('Yellow', 'Blue')))
3. Блестяще — даже лучше, на практике я буду отфильтровывать несколько значений, так что это будет еще более лаконично, спасибо
Ответ №2:
Не должно быть необходимости выполнять вычисления для каждой группы как таковой. Вы можете найти Set
содержащие s "Yellow"
, а затем сохранить только те, которых нет в этих Set
s. Поскольку мы говорим о множествах, давайте воспользуемся некоторой теорией множеств:
data[data$Set %in% setdiff(data$Set, data$Set[data$Color == "Yellow"]),]
Вы можете легко расширить это до многих цветов:
data[data$Set %in% setdiff(data$Set, data$Set[data$Color %in% c("Yellow","Green")]),]
И почему вас это должно волновать? Потому что, если вы когда-либо работали с большими наборами данных со многими группами, выполнение всех вычислений за один проход намного быстрее, чем повторять все для каждой группы:
## one million groups!
data <- data[rep(1:20, each=1e5),]
data$Set <- rep(1:1e6, each=2)
library(dplyr)
system.time({
data %>% group_by(Set) %>% filter(all(Color != 'Yellow'))
})
## i'm still waiting for this to finish 10 minutes later
system.time({
data[data$Set %in% setdiff(data$Set, data$Set[data$Color == "Yellow"]),]
})
# user system elapsed
# 0.301 0.000 0.302
Комментарии:
1. Спасибо за добавленное обоснование того, почему этот метод используется вместо метода dplyr. В случаях, когда данных меньше, а код предоставляется пользователям, которые в противном случае не знакомы с процессом (и не должны быть) — мне нравится dplyr из-за простоты чтения. Но на практике, когда используются большие наборы данных, ваш метод явно превосходит.
Ответ №3:
df[!(df$Set %in% with(df, Set[which(Color == "Yellow")])),]