логическое сравнение с любыми по dplyr фильтрованным данным - PullRequest
0 голосов
/ 14 февраля 2019

Логическое сравнение с функцией any не возвращает все комбинации

Я хотел бы отфильтровать студентов, которые улучшили класс от "C" до "A" без других оценок между ними.Я хотел бы сохранить список открытым, чтобы включить в него дополнительные значения.например, от "C" и "D" до "A".Даты не всегда могут быть последовательными и иногда повторяться.

Мой второй вопрос: почему Боб отсутствует в фильтре?

library(dplyr)
library(lubridate)
name <- c(rep("adam",5), rep("bob",5), rep("charlie",5), rep("dave",5))
date <- lubridate::date(rep(seq.Date(as.Date("2015-01-01"),as.Date("2019-01-01"),"years"),4))
score <- c("C","B","A","C","A",
       "A","B","A","B","C",
       "C","A","B","A","C",
       "B","A","A","A","C")
df <- data.frame(name,date,score)

df %>%
  group_by(name) %>%
  filter(any(date[score %in% c("A")] > date[score %in% c("C")]))%>%
  filter(!any(date[score %in% c("B")] > date[score %in% c("C")] &
              date[score %in% c("B")] < date[score %in% c("A")]))

# Charlie...

df %>%
  group_by(name) %>%
  filter(any(date[score %in% c("B")] < date[score %in% c("A")])) %>%
  summarize
# 1 adam   
# 2 charlie
# 3 dave   

Первый блок должен был включать Адама.Очки «С» и «А» находятся в последовательности.

Боб отсутствует во втором блоке.

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

Благодаря @Gregor

lead и lag - это именно то, что я искал.Я подтверждаю, что lead и lag не работают, если даты повторяются, и мне нужно сначала договориться по дате.grepl удалось решить вопрос о повторении дат.Теперь я должен выяснить, как свернуть счеты.Вот коды для интересующихся

name <- c(rep("adam",3), rep("bob",3), rep("charlie",3), rep("dave",3))
date <- lubridate::date(rep(c(as.Date("2014-01-01"),as.Date("2015-01-01"),as.Date("2015-01-01")),4))
score <- c("C","B","A",
           "C","A","B",
           "C","A","A",
           "C","B","B")
df <- data.frame(name,date,score)

df %>% group_by(name) %>%
  filter(any(score %in% c("C") & lead(score %in% c("A")))) %>%
  summarize

# A tibble: 2 x 1
#  name   
#  <fct>  
# 1 bob    
# 2 charlie

df %>% group_by(name, date) %>%
  summarize(scores = paste(score, collapse = "")) %>%
  group_by(name) %>%
  filter(any(grepl("C", scores) & lead(grepl("A", scores))))

# # A tibble: 6 x 3
# # Groups:   name [3]
# name    date       scores
# <fct>   <date>     <chr> 
#   1 adam    2014-01-01 C     
# 2 adam    2015-01-01 BA    
# 3 bob     2014-01-01 C     
# 4 bob     2015-01-01 AB    
# 5 charlie 2014-01-01 C     
# 6 charlie 2015-01-01 AA  

Относительно второго вопроса по парному сравнению.

Я пришел к тому же выводу, что > не делает парное сравнение.Эти вопросы стали ясны, когда я исследовал, почему функция any не работает должным образом.

1:3 > 2:4
FALSE FALSE FALSE

Я думаю, что expand.grid может помочь, но мне нужно больше узнать о функциональном программировании, пакете purrr и научиться связывать их вместе.

filter(min(date[score %in% "B"]) < max(date[score %in% "A"]))
отлично подходит для моих целей.

0 голосов
/ 14 февраля 2019

Ваша проблема в том, что < выполняет парные сравнения.Используя ваш второй пример:

df %>%
  group_by(name) %>%
  filter(any(date[score %in% c("B")] < date[score %in% c("A")])) %>%
  summarize

## let's look at bob
# 6      bob 2015-01-01     A
# 7      bob 2016-01-01     B
# 8      bob 2017-01-01     A
# 9      bob 2018-01-01     B
# 10     bob 2019-01-01     C

## call this X
date[score %in% c("B")] # corresponds to two dates:
# 2016-01-01
# 2018-01-01

## and this Y
date[score %in% c("A")] # also two dates
# 2015-01-01
# 2017-01-01

X < Y ## returns FALSE FALSE
# because X[1] > Y[1] and X[2] > Y[2]

Вы можете обойти это, выполнив что-то вроде:

df %>%
  group_by(name) %>%
  # is the first B before the last A
  filter(min(date[score %in% "B"]) < max(date[score %in% "A"])) %>%
  summarize
#   name   
#   <fct>  
# 1 adam   
# 2 bob    
# 3 charlie
# 4 dave   

Для последовательных изменений я бы предложил использовать lead или lag,Если даты не в последовательности, сначала используйте arrange, чтобы поместить их в последовательность:

df %>% group_by(name) %>%
  filter(any(score %in% c("A") & lead(score) %in% c("C"))) %>%
  summarize
#   name   
#   <fct>  
# 1 adam   
# 2 charlie
# 3 dave

Но это не сработает, если даты повторятся.Самым простым способом учета повторяющихся дат, который я могу придумать, является сведение их в одну строку, что-то вроде

df %>% group_by(name, date) %>%
  summarize(scores = paste(score, collapse = "")) %>%
  group_by(name) %>%
  filter(grepl("A", scores) & lead(grepl("C", scores)) %>% 
  summarize
# # A tibble: 3 x 1
#   name   
#   <fct>  
# 1 adam   
# 2 charlie
# 3 dave  

Я не проверял данные с несколькими датами, но это должно сработать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...