2017-09-14 6 views
1

Cette question peut sembler similaire à d'autres, mais j'espère que c'est assez différent. Je veux prendre une liste spécifique de valeurs et compter à quelle fréquence elles apparaissent dans une autre liste de valeurs où les valeurs non-apparentes sont renvoyées à '0'.Obtenir le nombre de valeurs spécifiques dans un bloc de données qui apparaissent dans un autre

J'ai une trame de données (DF1) avec les valeurs suivantes:

Items <- c('Carrots','Plums','Pineapple','Turkey') 
df1<-data.frame(Items) 

>df1 
Items 
1 Carrots 
2  Plums 
3 Pineapple 
4 Turkey 

et une seconde trame de données (DF2) qui contient une colonne appelée 'chose':

> head(df2,n=10) 
    ID  Date  Thing 
1 58150 2012-09-12 Potatoes 
2 12357 2012-09-28 Turnips 
3 50788 2012-10-04 Oranges 
4 66038 2012-10-11 Potatoes 
5 18119 2012-10-11 Oranges 
6 48349 2012-10-14 Carrots 
7 23328 2012-10-16 Peppers 
8 66038 2012-10-26 Pineapple 
9 32717 2012-10-28 Turnips 
10 11345 2012-11-08 Oranges 

Je sais le mot 'Turquie' n'apparaît que dans df1 PAS dans df2. Je veux retourner une table de fréquence ou le compte des éléments dans df1 qui apparaît dans df2 et retourner '0' pour le compte de la Turquie.

Comment puis-je récapituler les valeurs de la colonne Data Frame en utilisant les valeurs d'une autre? Le plus proche je suis arrivé était:

df2%>% count (Thing) %>% filter(Thing %in% df1$Items,) 

Mais ce retour une liste d'éléments filtrés entre DF1 et DF2 si la Turquie revisité exclus. Tellement proche!

> df2%>% count (Thing) %>% filter(Thing %in% df1$Items,) 
# A tibble: 3 x 2 
     Thing  n 
    <fctr> <int> 
1 Carrots 30 
2 Pineapple 30 
3  Plums 38 

Je veux que ma sortie ressemble à ceci:

1 Carrots 30 
2 Pineapple 30 
3  Plums 38 
4 Turkey  0 

Je suis assez nouveau à R et complètement nouveau pour dplyr.

Répondre

0

J'utilise ce genre de chose tout le temps. Je suis sûr qu'il ya une façon plus avertis de coder, mais c'est ce que je suis:

item <- vector() 
count <- vector() 
items <- list(unique(df1$Items)) 

for (i in 1:length(items)){ 
    item[i] <- items[i] 
    count[i] <- sum(df2$Thing == item) 
} 

df3 <- data.frame(cbind(item, count)) 

Hope this helps!

+0

Merci Stephen, je reçu un avertissement de longueur: 'plus grande longueur de l'objet est pas un multiple de l'objet plus court length' – gzrcm

+0

Ahh Je pense que je sais pourquoi. Ainsi le code ci-dessus regarde chaque article, pas seulement des articles uniques. J'ai mis à jour mon commentaire pour l'essayer. –

+0

Je reçois toujours la même erreur, mais je vois ce que votre script essaie de réaliser. J'ai créé df1 vient d'un vecteur. Est-il possible de simplifier la boucle for en utilisant ce vecteur original? – gzrcm

0

La solution de Stephen a fonctionné avec une légère modification, en ajoutant le [i] à l'élément à la fin de la ligne [i]. Voir ci-dessous:

item <- vector() 
count <- vector() 

for (i in 1:length(unique(Items))){ 
    item[i] <- Items[i] 
    count[i]<- sum(df2$Thing == item[i]) 
} 

df3 <- data.frame(cbind(item, count)) 

> df3 
     item count 
1 Carrots 30 
2  Plums 38 
3 Pineapple 30 
4 Turkey  0 
0

dplyr gouttes 0 lignes de comptage, et vous avez la complication supplémentaire que les catégories possibles de Thing sont différentes entre vos deux ensembles de données.

Si vous ajoutez les niveaux de facteur df1-df2, vous pouvez utiliser complete de tidyr, ce qui est une façon courante de add 0 count rows.

J'ajoute les niveaux de facteur de df1-df2 en utilisant une fonction de commodité du package Forcatsfct_expand appelés.

library(dplyr) 
library(tidyr) 
library(forcats) 

df2 %>% 
    mutate(Thing = fct_expand(Thing, as.character(df1$Item))) %>% 
    count(Thing) %>% 
    complete(Thing, fill = list(n = 0)) %>% 
    filter(Thing %in% df1$Items,) 
+0

Merci aosmith! Cela a fonctionné aussi bien. – gzrcm

0

Une autre approche consiste à agréger df2 d'abord, à droite se joindre à df1 (choisir toutes les lignes de df1), et de le remplacer par zéro NA.

library(dplyr) 
df2 %>% 
    count(Thing) %>% 
    right_join(unique(df1), by = c("Thing" = "Items")) %>% 
    mutate(n = coalesce(n, 0L)) 
# A tibble: 4 x 2 
     Thing  n 
     <chr> <int> 
1 Carrots  1 
2  Plums  0 
3 Pineapple  1 
4 Turkey  0 
Warning message: 
Column `Thing`/`Items` joining factors with different levels, coercing to character vector 

La même approche dans data.table:

library(data.table) 
setDT(df2)[, .N, by = Thing][unique(setDT(df1)), on = .(Thing = Items)][is.na(N), N := 0L][] 
 Thing N 
1: Carrots 1 
2:  Plums 0 
3: Pineapple 1 
4: Turkey 0 

Notez que dans les deux implémentations unique(df1) est utilisé pour éviter double involontaire lignes après la jointure.


Si df2 est grand et df1 ne contient que quelques Items il pourrait être plus efficace de se joindre d'abord, puis à agréger:

library(dplyr) 
df2 %>% 
    right_join(unique(df1), by = c("Thing" = "Items")) %>% 
    group_by(Thing) %>% 
    summarise(n = sum(!is.na(ID))) 
# A tibble: 4 x 2 
     Thing  n 
     <chr> <int> 
1 Carrots  1 
2 Pineapple  1 
3  Plums  0 
4 Turkey  0 
Warning message: 
Column `Thing`/`Items` joining factors with different levels, coercing to character vector 

Le même en data.table syntax:

library(data.table) 
setDT(df2)[unique(setDT(df1)), on = .(Thing = Items)][, .(N = sum(!is.na(ID))), by = Thing][] 
 Thing N 
1: Carrots 1 
2:  Plums 0 
3: Pineapple 1 
4: Turkey 0 
+0

Merci Uwe! Votre solution a fonctionné! – gzrcm