2017-09-29 2 views
0

J'ai un quadrillage de données de levé. Chaque rangée représente une entrevue avec un «répondant». Certains répondants ont été interviewés une fois; d'autres ont été interviewés plusieurs fois. Je veux sélectionner, à partir de ce fichier, seulement la dernière interview pour chaque répondant.tidyverse: suppression des rangées de la trame de données sur la base des valeurs des autres rangées

Voici un exemple minimal:

tmp <- tribble(
    ~YYYYMM, ~ID, ~DATEPR, ~IDPREV, 
    198001, 1,  NA,  NA, 
    198001, 2,  NA,  NA, 
    198001, 3,  NA,  NA, 
    198002, 1,  198001, 1, 
    198002, 2,  NA,  NA, 
    198002, 3,  NA,  NA, 
    198003, 1,  198002, 1, 
    198003, 2,  NA,  NA, 
    198003, 3,  198002, 3) 

  • YYYYMM est la date d'une entrevue.

  • DATEPR est la date de l'interview précédente du répondant, s'il y en avait une.

  • ID est unique seulement dans les vagues d'interview. Cela signifie, par exemple, que le répondant pour lequel ID==2 et YYYMM==198001 n'a pas besoin d'être le répondant pour qui ID==2 et YYYMM==198002.

  • IDPREV est l'ID de l'interview précédente du répondant, s'il y en avait une.

Il y a neuf rangées dans le quadrilatère ci-dessus. Mais un répondant a été interviewé trois fois, et un autre a été interviewé deux fois. Je ne veux que la dernière interview pour chaque répondant, donc je veux un pépin avec seulement six rangées. Ce code fait le travail:

for (i in 1:nrow(tmp)) { 
    if (!is.na(tmp$DATEPR[i])) { 
    ind <- which(tmp$YYYYMM == tmp$DATEPR[i] & tmp$ID == tmp$IDPREV[i]) 
    tmp <- tmp[-ind, ] 
    } 
} 

Mais il semble un peu difficile à analyser. Existe-t-il un moyen plus clair d'atteindre le même but avec les fonctions tidyverse? J'ai en tête une fonction en deux étapes: d'abord, obtenir les indices de toutes les lignes à supprimer; Deuxièmement, supprimez les lignes. Mais je n'ai pas été en mesure d'implémenter cette solution avec map ou avec les fonctions dplyr.

Répondre

2

Si tous précédemment interrogés ID sont répertoriés sur les 3e et colonnes 4e, vous pouvez faire une anti_join gauche du cadre de données avec lui-même en utilisant dplyr::anti_join, ici vous correspondez DATEPR et IDPREV avec les respectivement YYYYMM et ID, seules les lignes de temp dont YYYYMM et ID qui n'ont pas un match sera laissé:

anti_join(tmp, tmp, by = c("YYYYMM" = "DATEPR", "ID" = "IDPREV")) %>% 
    arrange(YYYYMM, ID) 

# A tibble: 6 x 4 
# YYYYMM ID DATEPR IDPREV 
# <dbl> <dbl> <dbl> <dbl> 
#1 198001  2  NA  NA 
#2 198001  3  NA  NA 
#3 198002  2  NA  NA 
#4 198003  1 198002  1 
#5 198003  2  NA  NA 
#6 198003  3 198002  3 

Après l'exécution de votre code:

for (i in 1:nrow(tmp)) { 
    if (!is.na(tmp$DATEPR[i])) { 
     ind <- which(tmp$YYYYMM == tmp$DATEPR[i] & tmp$ID == tmp$IDPREV[i]) 
     tmp <- tmp[-ind, ] 
    } 
} 
tmp %>% arrange(YYYYMM, ID) 
# A tibble: 6 x 4 
# YYYYMM ID DATEPR IDPREV 
# <dbl> <dbl> <dbl> <dbl> 
#1 198001  2  NA  NA 
#2 198001  3  NA  NA 
#3 198002  2  NA  NA 
#4 198003  1 198002  1 
#5 198003  2  NA  NA 
#6 198003  3 198002  3 
+0

Merci. Je n'avais pas pensé à utiliser 'anti_join' avec seulement une trame de données. – user697473