[Résolu] Supprimer lignes d'un DF contenues dans un autre DF

Postez ici vos questions, réponses, commentaires ou suggestions - Les sujets seront ultérieurement répartis dans les archives par les modérateurs

Modérateur : Groupe des modérateurs

Laëtitia VIBERT
Messages : 42
Enregistré le : 16 Avr 2019, 10:13

[Résolu] Supprimer lignes d'un DF contenues dans un autre DF

Messagepar Laëtitia VIBERT » 14 Mai 2020, 10:04

Bonjour,

je cherche un moyen rapide pour supprimer des lignes de mon df (df1), lignes au préalables stockées dans un autre df (df2).

Code : Tout sélectionner

df1 <- structure(list(indiv = structure(c(1L, 1L, 2L, 2L, 2L, 3L, 3L), .Label = c("A", "B", "C"), class = "factor"), var1 = c(55L, 77L, 11L, 33L, 11L, 11L, 77L), var2 = c(66L, 88L, 22L, 55L, 66L, 55L, 88L), var3 = c(55L, 77L, 11L, 44L, 88L, 55L, 99L), var4 = c(66L, 88L, 22L, 66L, 55L, 11L, 0L)), .Names = c("indiv", "var1", "var2", "var3", "var4"), class = "data.frame", row.names = c(NA, -7L))

df2 <- structure(list(indiv = structure(c(1L, 2L, 2L, 3L), .Label = c("A", "B", "C"), class = "factor"), var1 = c(55L, 33L, 11L, 11L), var2 = c(66L, 55L, 66L, 55L), var3 = c(55L, 44L, 88L, 55L), var4 = c(66L, 66L, 55L, 11L)), .Names = c("indiv", "var1", "var2", "var3", "var4"), class = "data.frame", row.names = c(NA, -4L))


J'ai essayé sans succès

Code : Tout sélectionner

df3 <- df1[which(!df1[,] %in% df2[,]),]


J'ai ensuite essayé la méthode suivante, qui fonctionne bien, mais mon fichier étant de taille très considérable, je crains que rbind + supprimer les doublons ne prenne beaucoup trop de temps. Il y a sûrement une méthode bien plus simple !

Code : Tout sélectionner

df3 <-rbind(df1,df2)
df3 <- df3[!duplicated(df3,fromLast = FALSE) & !duplicated(df3,fromLast = TRUE),]


En vous remerciant chaleureusement par avance,
Laëtitia
L.

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: Supprimer lignes d'un DF contenues dans un autre DF

Messagepar Mickael Canouil » 14 Mai 2020, 11:36

Bonjour,

inutile de faire plusieurs messages pour deux "problèmes" complètement liés, d'autant plus que le second est exploitable puisqu'il n'y aucun contexte, données et code reproductible.

Code : Tout sélectionner

df1 <-
  structure(
    list(
      indiv = structure(
        c(1L, 1L, 2L, 2L, 2L, 3L, 3L),
        .Label = c("A", "B", "C"),
        class = "factor"
      ),
      var1 = c(55L, 77L, 11L, 33L, 11L, 11L, 77L),
      var2 = c(66L, 88L, 22L, 55L, 66L, 55L, 88L),
      var3 = c(55L, 77L, 11L, 44L, 88L, 55L, 99L),
      var4 = c(66L, 88L, 22L, 66L, 55L, 11L, 0L)
    ),
    .Names = c("indiv", "var1", "var2", "var3", "var4"),
    class = "data.frame",
    row.names = c(NA,-7L)
  )

df2 <-
  structure(
    list(
      indiv = structure(
        c(1L, 2L, 2L, 3L),
        .Label = c("A", "B", "C"),
        class = "factor"
      ),
      var1 = c(55L, 33L, 11L, 11L),
      var2 = c(66L, 55L, 66L, 55L),
      var3 = c(55L, 44L, 88L, 55L),
      var4 = c(66L, 66L, 55L, 11L)
    ),
    .Names = c("indiv", "var1", "var2", "var3", "var4"),
    class = "data.frame",
    row.names = c(NA,-4L)
  )
 

Code : Tout sélectionner

library("dplyr")
anti_join(df1, df2)
#> Joining, by = c("indiv", "var1", "var2", "var3", "var4")
#>   indiv var1 var2 var3 var4
#> 1     A   77   88   77   88
#> 2     B   11   22   11   22
#> 3     C   77   88   99    0       


Quand votre code ne fonctionne pas, il faut revenir aux bases et surtout à la documentation des opérateurs et fonctions que vous utilisez.
Savez-vous ce que fait l'opérateur %in% ? (voir documentation)

Code : Tout sélectionner

?'%in%' 

Savez-vous ce que sont df1[,] et df2[,] ? Est-ce vraiment compatible avec %in% ? (voir documentation)

Code : Tout sélectionner

class(df1[,])
class(
d21[,]) 

Faites-vous une distinction entre df1[,] et df1 ? (testez ces objets/variables dans votre console)

Code : Tout sélectionner

df1[,]
df1


Cordialement,
Mickaël
mickael.canouil.fr | rlille.fr

Laëtitia VIBERT
Messages : 42
Enregistré le : 16 Avr 2019, 10:13

Re: Supprimer lignes d'un DF contenues dans un autre DF

Messagepar Laëtitia VIBERT » 14 Mai 2020, 15:36

Re-bonjour,

Merci pour votre réponse ainsi que pour votre aide.
J'ai écrit 2 messages car on m'avait déjà fait la remarque de ne pas soulever 2 problèmes, même liés, dans le même post...

Vous avez tout à fait raison, il est important de se tourner en premier lieu vers la documentation. C'est pourtant ce que j'ai fait, mais celle-ci est parfois plus difficile à comprendre qu'une explication (et pas une réponse toute crue) par quelqu'un d'initié.

Pour répondre aux questions que vous soulevez, même si celles-ci ne sont que rhétoriques, pour moi il n'y a pas de différence entre df1 et df1[,], dans les 2 cas, on considère le dataframe dans son ensemble, non ?
J'utilise généralement la fonction %in% pour chercher des valeurs d'un df à un autre, et étant donné que je cherchais ici des lignes complètes, j'ai essayé plusieurs arrangements sans succès.

La fonction 'join' avec toutes ses possibilités me semble très intéressante, je ne connaissais pas du tout, merci. C'est aussi l'avantage de ce forum, non ? Si j'avais seulement épluché la documentation sur les fonctions que je connais, je n'aurais probablement pas trouvé celle-ci =)

En tout cas merci pour votre aide, et toutes mes excuses si ce post était maladroit.
Bonne soirée

Laëtitia
L.

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: Supprimer lignes d'un DF contenues dans un autre DF

Messagepar Mickael Canouil » 14 Mai 2020, 16:16

Ce que je voulais vous montrez, c'est qu'en regardant la documentation on constate que le %in% utilise des vecteurs (ou NULL).
Comme vous l'avez vu df1 ou df1[,] sont des data.frame, c'était donc impossible que !df1[,] %in% df2[,] fonctionne.
Image
Le type des arguments est très souvent indiqué dans la documentation, en particulier quand il s'agit des fonctions et opérateurs de base de R.

L'un des principes pour identifier le problème d'un code est de le décomposer en plus petit morceaux et consulter la documentation.

Maintenant, nous sommes bien d'accord que la fonction anti_join de dplyr ne serait pas apparue toute seule pour autant.
Mickaël
mickael.canouil.fr | rlille.fr

Logez Maxime
Messages : 3138
Enregistré le : 26 Sep 2006, 11:35

Re: Supprimer lignes d'un DF contenues dans un autre DF

Messagepar Logez Maxime » 15 Mai 2020, 13:40

Bonjour,

Même si Michaël à raison, je pense que les explications peuvent être moins 'professorales' :-).
Personnellement je ne savais pas au début de mon utilisation de R qu'il fallait entourer un opérateur par des guillemets simples pour obtenir l'aide correspondante.

Tu peux te servir du '%in%' en tranformant au préalable les deux data.frame en deux vecteurs de chaines de caractère

Code : Tout sélectionner

df1[!do.call(paste, c(df1, sep = "@")) %in% do.call(paste, c(df2, sep = "@")),]
Une autre possibilité c'est de comparer les colonnes deux à deux et d'en faire la synthèse avec des '&'.

Code : Tout sélectionner

comps <- mapply('%in%', df1, df2)
res <- apply(comps, 1, all)
df1[!res,]

Cordialement,
Maxime

Laëtitia VIBERT
Messages : 42
Enregistré le : 16 Avr 2019, 10:13

Re: Supprimer lignes d'un DF contenues dans un autre DF

Messagepar Laëtitia VIBERT » 16 Mai 2020, 14:53

Bonjour,

on constate que le %in% utilise des vecteurs (ou NULL).
Comme vous l'avez vu df1 ou df1[,] sont des data.frame, c'était donc impossible que !df1[,] %in% df2[,] fonctionne.

D'accord, je vois, Merci pour l'explication.
Merci aussi pour la fonction mais surtout pour dplyr, j'ai pu complètement reformuler mon code, et passer de plusieurs heures à quelques secondes de moulinage !
Merci aussi Maxime pour l'idée de transformer les df en vecteurs, je garde l'idée sous le coude, mais n'est-ce pas une perte de temps lorsqu'on joue avec des db de taille considérable ?
Anyway, merci, pour vos réponses =)
Laëtitia
L.


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Google [Bot] et 1 invité