Как вы проверяете порядок набора действий, учитывая ранги для каждого из них?

#r

#r

Вопрос:

У меня есть этот фрейм данных.

 user    action    date        rank
AAA     jump      2018-01-01  1
AAA     climb     2018-01-02  2
AAA     leap      2018-01-03  3
BBB     jump      2018-01-01  1
BBB     climb     2018-01-03  2
BBB     leap      2018-01-05  3
BBB     gallop    2018-01-08  4
CCC     leap      2018-01-01  1
CCC     climb     2018-01-02  2
CCC     gallop    2018-01-04  3
  

Он выполняет действия и добавляет ранг для каждого пользователя в соответствии с датой в порядке возрастания.

Я хочу найти всех пользователей, которые выполняли действия в неправильном порядке. Порядок должен быть jump -> climb -> leap -> gallop .

Результатом будет CCC , поскольку этот пользователь совершил прыжок перед подъемом.

 user   
CCC
  

Как вы делаете ссылку на конкретную строку? Я использую dplyr и могу сгруппировать его по каждому пользователю и добавить ранг для каждого пользователя с помощью row_number() , но я не знаю, как создать правила, которые проверяют, выполняются ли действия в правильном порядке.

Примечание — Я понял, что это было неясно. Не каждый пользователь выполняет все действия, но порядок все равно имеет значение.

Это то, над чем я работаю до сих пор

 badData <- NULL
for (i in df$user){
  filtered <- filter(df, user == i)

  first <- ifelse(filtered[filtered$action == "jump",]$rank > 1, TRUE, FALSE)
  second <- ifelse(filtered[filtered$action == "climb",]$rank < filtered[filtered$action == "jump",]$rank, TRUE, FALSE)
  #and so on for the rest of the rules

  if(first   second > 0) badData <- c(badData, i)   
}
  

Ответ №1:

Если вы создаете action коэффициент и используете levels аргумент для задания порядка, вы можете сгруппировать по пользователю, а затем проверить, не отсортированы ли действия с помощью is.unsorted :

 library(dplyr)

df %>%
  mutate(action = factor(action, levels = c("jump", "climb", "leap", "gallop"))) %>%
  group_by(user) %>%
  filter(is.unsorted(action)) %>%
  pull(user) %>%
  unique

[1] "CCC"
  

Комментарии:

1. Это чертовски радикально. Действительно классная штука, такого раньше не видел.

2. Извините, я откатил ‘принятый ответ’, потому что не у каждого пользователя есть все действия. Некоторые пользователи могут просто прыгать и скакать, но порядок все еще имеет значение. Я должен был упомянуть об этом.

3. ХОРОШО — это все равно будет работать, даже если набор действий неполон. Или вы хотите отметить тех, у кого неправильный порядок или неполный набор действий?

4. Вы правы, это все еще работает. Итак, is.unsorted() не возражает, если есть значения, которых у него нет, он просто проверяет, что значения, которые у него есть, находятся в правильном порядке?

5. Да, pull() делает именно это. Это также причина, по которой я использовал unique() вместо distinct() , поскольку distinct() это не работает с векторами.

Ответ №2:

Вот небольшой пример, на котором вы можете этого добиться. Сначала вы создаете фрейм данных refrence ( refdata ), который содержит правильный порядок. Тогда вы сможете легко работать с tidyverse пакетом:

 mydata <- tibble(id = rep(c("aaa", "bbb", "ccc"), each = 4), action = letters[c(1:4, 1,2 ,4, 3, 4,1,2,3)],
       date = rep(1:3, 4)) 

refdata <- tibble(action = letters[1:4], right_order = 1:4)


mydata %>% left_join(refdata, by = "action") %>% group_by(id) %>% 
  summarise(test = identical(right_order, sort(right_order)))