1
votes

Moyen élégant de filtrer les enregistrements en fonction de plusieurs critères à l'aide de R

J'ai un bloc de données comme indiqué ci-dessous

sorted <- test_df %>% arrange(date_1,group_by = subject_id) #Am I right in sorts the dates within group?
test_df$month = month(test_df$date_1)  #get the month
test_df$day = day(test_df$date_1)  #get the year
filter(test_df, month==12 and day == 31)  # doesn't work here

Ce que je voudrais faire, c'est

  1. Organisez les dates par ordre croissant pour chaque sujet (triez par ordre croissant dans les groupes)

  2. Supprimez les enregistrements de date pour chaque sujet en fonction des critères ci-dessous (l'année n'a pas d'importance):

    2a. supprimer uniquement les enregistrements du 31 décembre si le premier enregistrement du sujet est le 1er janvier ex: subject_id = 1

    2b. supprimer uniquement les enregistrements du 1er janvier si le premier enregistrement du sujet est le 31 décembre ex: subject_id = 2

    2c. supprimer uniquement les enregistrements du 31 décembre si le sujet a à la fois le 31 décembre et le 1er janvier dans ses autres enregistrements (c'est-à-dire du 2ème enregistrement jusqu'à la fin de ses enregistrements) ex: subject_id = 3

J'essayais ce qui suit

test_df <- data.frame("subject_id" = c(1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3), 
                      "date_1" = c("01/01/2003", "12/31/2007", "12/30/2008", "12/31/2005",
                                   "01/01/2007", "01/01/2013", "12/31/2008", "03/04/2006", 
                                   "12/31/2009", "01/01/2015", "01/01/2009"))

Pouvez-vous m'aider comment puis-je filtrer les enregistrements en fonction de mes critères?

Je m'attends à ce que ma sortie soit comme ci-dessous

 entrez la description de l'image ici


2 commentaires

que doit faire group_by = dans arrange ? Voulez-vous dire arrange (date_1)%>% group_by (subject_id) ? (Et non, l'arrangement se fait quel que soit le groupe (essayez mtcars%>% group_by (cyl)%>% arrange (mpg)%>% print (n = 99) et voyez qu'il y a un 8 au milieu de 6 s).


Oui, je voulais dire arrange (date_1)%>% group_by (subject_id)


3 Réponses :


1
votes

Ce n'est pas le plus joli code que j'ai jamais écrit, mais ça marche. J'ai supposé que les filtres étaient exécutés en séquence; sinon, les deuxième et troisième filtres éliminent tout le sujet 2.

    test_df %>%
      mutate(date_1 = as.Date(as.character(date_1), format = "%m/%d/%Y"),
      month = as.numeric(format(date_1, "%m")),
      day = as.numeric(format(date_1, "%d"))) %>%
      group_by(subject_id) %>%
      arrange(date_1) %>%
      filter(!(rep(month[1] == 1 & day[1] == 1, n()) & month == 12 & day == 31)) %>%
      filter(!(rep(month[1] == 12 & day[1] == 31, n()) & month == 1 & day == 1)) %>%
      filter(!(rep(sum(month[-1] == 1 & day[-1] == 1) > 0 & sum(month[-1] == 12 & day[-1] == 31) > 0, n()) & month == 12 & day == 31)) %>%
      ungroup() %>%
      arrange(subject_id, date_1)

      subject_id date_1     month   day
           <dbl> <date>     <dbl> <dbl>
    1          1 2003-01-01     1     1
    2          1 2008-12-30    12    30
    3          2 2005-12-31    12    31
    4          2 2008-12-31    12    31
    5          3 2006-03-04     3     4
    6          3 2009-01-01     1     1
    7          3 2015-01-01     1     1


0 commentaires

2
votes
# A tibble: 7 x 2
  subject_id date_1    
       <dbl> <date>    
1          1 2003-01-01
2          1 2008-12-30
3          2 2005-12-31
4          2 2008-12-31
5          3 2006-03-04
6          3 2015-01-01
7          3 2009-01-01

13 commentaires

Puis-je savoir pourquoi obtenez-vous last_date pour chaque sujet? car 12-31 pourrait également être au milieu en fonction de l'ordre des dates (les années pourraient faire une différence) comme pour subject = 1


Une autre question: pourquoi excluons-nous le premier enregistrement de la trame de données pour vérifier has_both ? all (c ("01-01", "12-31")% in% tail (without_year, -1))


@The Great car c'est le mois-jour du dernier rendez-vous en groupe. J'ai traduit record = row si la définition de l'enregistrement pour vous est différente, fournissez cette définition.


IIUC, si vous essayez d'obtenir le mois-jour de la dernière date dans le groupe, puis-je vérifier comment il est utilisé plus loin dans le code? Qu'essayons-nous de faire avec la dernière date ?


@The Great for 1st filtering I need to know month-day of first row in group. Similaire pour le deuxième filtrage, j'ai besoin de connaître le dernier mois-jour en groupe. Pour le troisième filtrage, j'ai besoin de savoir s'il y a "01-01" et "31-12" comme mois-jour avec le groupe (à l'exclusion de la première ligne).


Ici dans le 2ème filtre, filter (! (First_date == "12-31" & without_year == "01-01")) , je vois que vous avez déjà utilisé 12-31 n'est-ce pas? Nous n'utilisons donc pas vraiment la variable last_date ici. Ai-je bien compris?


Ce que j'essaie de dire, c'est que la variable last_date n'est utilisée nulle part dans le code pour un traitement ultérieur. Ai-je raison?


@The Great Votre propre deuxième condition de filtrage dit: si la première date (sans année) dans le groupe est "12-31", supprimez toutes les lignes du groupe qui ont la date (sans année) "01-01". C'est exactement ce que fait le deuxième filtrage.


@The Great vous avez tout à fait raison à ce sujet, il semble que je n'utilise pas du tout last_date , donc c'est redondant.


Merci d'avoir clarifié mes doutes. Très appréciée


continuons cette discussion dans le chat .


Essayez avec date_1 = lubridate :: dmy_hm (date_1) dans la première mutation.


Salut @det - une petite question. Lorsque vous utilisez arrange () dans le code, puis-je savoir comment il trie par colonne date_1 sans mentionner explicitement date_1 dans arrange (date_1) ? Pouvez-vous m'aider avec ça s'il vous plaît?



2
votes

Vous pouvez peut-être aussi essayer une solution de base avec un peu de lubrifiant:

# split as list
listed <- split(test_df, test_df$subject_id)

# order each df: requested and fundamental for the function
listed <- lapply(listed, function(df){df[order(df$date_1),]})

# here the function: it's a nested if else statement on the field
filtering <- function(x){if
                        (head(x,1)$cntrl == "11") { x[x$cntrl != '1231', ] }
                        else if
                        (head(x,1)$cntrl == "1231") { x[x$cntrl != '11', ] }
                        else if
                        ( "11" %in% tail(x,nrow(x)-1)$cntrl & "1231" %in% tail(x,nrow(x)-1)$cntrl) { x[x$cntrl != '1231', ] }
                        else(x)}

# lapply it!
listed  <- lapply(listed, function(x)filtering(x))

# now as a dataframe, removing the useless column:
res <- do.call(rbind, listed)[,-3]

# lastly you can rename the rownames
rownames(res) <- 1:nrow(res)

res
 subject_id     date_1
1          1 2003-01-01
2          1 2008-12-30
3          2 2005-12-31
4          2 2008-12-31
5          3 2006-03-04
6          3 2009-01-01
7          3 2015-01-01

Maintenant, l'idée est de diviser votre df dans une liste par groupe subject_id , puis lapply une fonction qui filtre en utilisant votre condition:

library(lubridate)
# put date_1 as date
test_df$date_1 <- lubridate::mdy(test_df$date_1)
# create the field that's going to be the filter
test_df$cntrl <- paste0(month(test_df$date_1),day(test_df$date_1))


0 commentaires