1
votes

Je veux vérifier si 2 colonnes de n'importe quelle ligne de df1 == les mêmes 2 colonnes de n'importe quelle ligne de df2

J'ai 2 dfs comme celui-ci

for (i in 1:5){
  if (for (j in 1:5){
    df[i,1:2] == df2[j,1:2]})
    print("true")
}

Je veux trouver s'il y a une ligne dans df 1 qui == une ligne dans df2 pour les colonnes A et B. Vous pouvez voir que df1 [4,1: 2] == df2 [2,1: 2]

J'ai essayé

df1 <- data.frame("A" = c(1,2,3,4,5), "B" = c(10,20,30,40,50), "C" = c(6,7,8,9,11))
df2 <- data.frame("A" = c(10,4,30,20,50), "B" = c(1,40,3,7,5)), "C" = c(12,13,14,15))

Mais cela me donne cette erreur: Erreur dans if (for (j in 1: 5) {: l'argument est de longueur zéro


1 commentaires

Votre syntaxe dans if (for (j in 1: 5) { est fausse, dans if (expression) l'expression doit renvoyer une valeur logique (ou s'il y en a plusieurs , seul le premier est utilisé)


4 Réponses :


2
votes

Vous pouvez lier les colonnes A et B en ligne et utiliser anyDuplicated():

anyDuplicated(rbind(unique(df1[1:2]), unique(df2[1:2]))) > 0

S'il y a des doublons potentiels dans les blocs de données, vous devrez les créer unique d'abord:

anyDuplicated(rbind(df1[1:2], df2[1:2])) > 0
[1] TRUE


0 commentaires

2
votes

Vous pouvez coller les valeurs par ligne et vérifier les doublons en utilisant % in% :

dplyr::semi_join(df1, df2, by = c('A', 'B'))

Si vous n'avez besoin que d'un seul TRUE / FALSE valeur

dplyr::anti_join(df1, df2, by = c('A', 'B'))
#  A  B  C
#1 1 10  6
#2 2 20  7
#3 3 30  8
#4 5 50 11

Si vous souhaitez supprimer des lignes dans df1 qui est présent dans df2 vous pouvez utiliser anti_join de dplyr.

any(do.call(paste, df1[1:2]) %in% do.call(paste, df2[1:2]))
#[1] TRUE

Pour obtenir lignes communes que vous pouvez utiliser semi_join / inner_join :

df1[do.call(paste, df1[1:2]) %in% do.call(paste, df2[1:2]),]
#  A  B C
#4 4 40 9


5 commentaires

Cela a parfaitement fonctionné! Pouvez-vous me dire comment je supprime ces lignes résultant de votre première ligne de code?


@ApoloReis Vous pouvez annuler la condition? df1 [! do.call (coller, df1 [1: 2])% dans% do.call (coller, df2 [1: 2]),]


Pardon. Mon vrai problème est que dans le csv original, j'ai des cas dans lesquels la ligne x a 4 40 comme valeurs dans les colonnes A et B respectivement et la ligne y a 40 4. Je suis désolé de ne pas l'afficher sous forme de tableau. Je ne sais pas comment faire ici. Ainsi, lorsque j'exécute cette ligne que vous avez suggérée, toutes les lignes de la table qui ont des valeurs de colonnes égales (juste inversées) sont supprimées. Je voulais juste supprimer les valeurs 40 4 sans supprimer les 4 40 celles. Désolé si l'explication n'est pas claire


expliquer mieux. J'ai créé une table (table 2) à partir de l'original (table1) et inversé les valeurs des colonnes A et B.Ainsi, lorsque j'exécute cette ligne que vous avez suggérée, non seulement les 40 4 sont supprimés, mais aussi les 4 40 . Je veux simplement supprimer les informations redondantes


@ApoloReis Pourquoi créez-vous alors une copie de la table originale? vous pouvez trier les deux colonnes de la table d'origine elle-même et en supprimer les valeurs dupliquées.



2
votes

Voici une solution renvoyant les lignes de df1 et df2 , colonnes A et B , qui correspondent .

res <- apply(df2[1:2], 1, function(y){
  apply(df1[1:2], 1, function(x) all(x == y))
})

which(res, arr.ind = TRUE)
#     row col
#[1,]   4   2

w <- which(res, arr.ind = TRUE)
colnames(w) <- c('df1', 'df2')
w
#     df1 df2
#[1,]   4   2


0 commentaires

0
votes

Une option avec data.table join

df1 <- data.frame("A" = c(1,2,3,4,5), "B" = c(10,20,30,40,50), "C" = c(6,7,8,9,11))
df2 <- data.frame("A" = c(10,4,30,20,50), "B" = c(1,40,3,7,5), "C" = c(12,13,14,15, 15))

data

library(data.table)
setDT(df1)[!df2, on = .(A, B)]
#   A  B  C
#1: 1 10  6
#2: 2 20  7
#3: 3 30  8
#4: 5 50 11


0 commentaires