web-dev-qa-db-fra.com

Sous-ensemble avec des cas uniques, basé sur plusieurs colonnes

J'aimerais sous-définir un cadre de données pour inclure uniquement les lignes qui ont des combinaisons uniques de trois colonnes. Ma situation est similaire à celle présentée dans la question this , mais je voudrais également conserver les autres colonnes dans mes données. Voici mon exemple:

> df
  v1  v2  v3   v4  v5
1  7   1   A  100  98 
2  7   2   A   98  97
3  8   1   C   NA  80
4  8   1   C   78  75
5  8   1   C   50  62
6  9   3   C   75  75

La sortie demandée serait quelque chose comme ceci, où je recherche des cas uniques basés uniquement sur v1, v2 et v3:

> df.new
  v1  v2  v3   v4  v5
1  7   1   A  100  98 
2  7   2   A   98  97
3  8   1   C   NA  80
6  9   3   C   75  75

Si je pouvais récupérer les lignes non uniques, ce serait bien aussi:

> df.dupes
  v1  v2  v3   v4  v5
3  8   1   C   NA  80
4  8   1   C   78  75
5  8   1   C   50  62

J'ai vu une question connexe sur la façon de faire cela dans sql ( ici ), mais je ne peux pas obtenir cela dans R. Je suis sûr que c'est simple mais en jouant avec hasn unique () et subset () pas été fructueux. Merci d'avance.

38
user1202761

Vous pouvez utiliser la fonction duplicated() pour trouver les combinaisons uniques:

> df[!duplicated(df[1:3]),]
  v1 v2 v3  v4 v5
1  7  1  A 100 98
2  7  2  A  98 97
3  8  1  C  NA 80
6  9  3  C  75 75

Pour obtenir uniquement les doublons, vous pouvez le vérifier dans les deux sens:

> df[duplicated(df[1:3]) | duplicated(df[1:3], fromLast=TRUE),]
  v1 v2 v3 v4 v5
3  8  1  C NA 80
4  8  1  C 78 75
5  8  1  C 50 62
54
Ken Williams

En utilisant dplyr, vous pourriez faire:

library(dplyr)

# distinct
df %>% 
  distinct(v1, v2, v3, .keep_all = T)

# non-distinct only
df %>% 
  group_by(v1, v2, v3) %>% 
  filter(n() > 1)

# exclude any non-distinct
df %>% 
  group_by(v1, v2, v3) %>% 
  filter(n() == 1)
4
sbha

Vous pouvez utiliser le package plyr:

library(plyr)

ddply(df, c("v1","v2","v3"), head, 1)
#   v1 v2 v3  v4 v5
# 1  7  1  A 100 98
# 2  7  2  A  98 97
# 3  8  1  C  NA 80
# 4  9  3  C  75 75

ddply(df, c("v1","v2","v3"), function(x) if(nrow(x)>1) x else NULL)
#   v1 v2 v3 v4 v5
# 1  8  1  C NA 80
# 2  8  1  C 78 75
# 3  8  1  C 50 62
4
flodel

oui mais utiliser plyr et ddply est très très lent si vous avez trop de données.

vous devriez essayer quelque chose de ce genre:

df[ cbind( which(duplicated(df[1:3])), which(duplicated(df[1:3], fromLast=TRUE))),]

ou::

from = which(duplicated(df[1:3])
to = which(duplicated(df[1:3], fromLast=TRUE))
df[cbind(from,to),]

shd être plus rapide pour la plupart.

testez-le et faites-nous savoir

il y a des erreurs, mais je suppose que vous pouvez les corriger tant que vous en avez l'idée.

essayez aussi unique et tout cela

2
monis rahman

Une manière non élégante mais fonctionnelle consiste à coller les entrées d'une ligne donnée et à trouver celles qui sont uniques (ou non uniques), quelque chose comme:

df.vector=apply(df,1,FUN=function(x) {paste(x,collapse="")})
df.table=table(df.vector)

puis récupérez les index des doublons avec quelque chose comme:

which(df.vector%in%names(which(df.table>1)))
1
nullalleles