Как извлечь уникальный элемент в соответствии с набором предпочтительных условий

Взяв кадр данных df, я хотел бы извлечь уникальное значение в соответствии со следующими предпочтительными условиями для каждого поля:

1 - если C1 существует, извлеките соответствующее значение и игнорируйте остальные

2- если C2 существует, извлеките соответствующее значение и игнорируйте остальные

... и так далее до C5

данные:

df <- data.frame (Field=rep(c("F1","F2","F3","F4","F5"),each=3),
              Cond=rep(c("C1","C2","C3","C4","C5"),3),
              Value=c(1:15))

желаемый вывод:

output <-  data.frame (F= c("F1","F2","F3","F4","F5"),
                   C= c("C1","C1","C2","C1","C3"),
                   Value= c(1,6,7,11,13))

(примечание 1: значения были установлены как таковые только для примера, реальные значения данных не упорядочены)

(примечание 2: реальный условный столбец не упорядочен по алфавиту вообще. Хотя я должен был иметь что-то вроде, если A существует, чем выбрал "значение", в противном случае переход к следующему условию "если B существует..." и т. д.)

2 ответа

Решение

Другой вариант использует data.table

library(data.table)
setDT(df)[order(Field, Cond), head(.SD, 1), by = Field]
#    Field Cond Value
#1:    F1   C1     1
#2:    F2   C1     6
#3:    F3   C2     7
#4:    F4   C1    11
#5:    F5   C3    13

Если вы можете отсортировать data.frame перед обработкой, это довольно просто. Обратите внимание, что это работает для этого конкретного случая. Если твой Cond значения меняются, алфавитная сортировка может выйти из окна.

library(dplyr)
df <- data.frame (Field=rep(c("F1","F2","F3","F4","F5"),each=3),
                  Cond=rep(c("C1","C2","C3","C4","C5"),3),
                  Value=c(1:15))

df <- df[with(df, order(Field, Cond)), ]
res <- df %>%
  group_by(Field) %>%
  filter(row_number() == 1)

Source: local data frame [5 x 3]
Groups: Field [5]

   Field   Cond Value
  <fctr> <fctr> <int>
1     F1     C1     1
2     F2     C1     6
3     F3     C2     7
4     F4     C1    11
5     F5     C3    13

Вот еще один, более общий способ сделать это. Порядок сортировки определяется в so (см. этот вопрос). Обратите внимание, как я исказил значения для Cond чтобы показать, что это не сортируется по алфавиту.

df <- data.frame (Field=rep(c("F1","F2","F3","F4","F5"),each=3),
                  Cond=rep(c("rg1","kl2","xy3","rq4","ab5"),3),
                  Value=c(1:15))

so <- c("rg1","kl2","xy3","rq4","ab5")

df %>%
  group_by(Field) %>%
  slice(match(so, Cond)) %>%
  filter(row_number() == 1)

   Field   Cond Value
  <fctr> <fctr> <int>
1     F1    rg1     1
2     F2    rg1     6
3     F3    kl2     7
4     F4    rg1    11
5     F5    xy3    13
Другие вопросы по тегам