4
votes

Comment effectuer "countif" pour plusieurs lignes dans la trame de données?

J'ai deux blocs de données, A et B. En BI, j'ai deux colonnes clés et pour chaque ligne de BI, je dois compter le nombre de lignes dans A correspondant à ces clés.

Je sais comment résoudre le problème en utilisant un for-loop mais cela prend une éternité et je me demandais s'il y avait une façon plus intelligente de le faire. Je suis encore assez nouveau sur R, vous devrez donc me pardonner si je manque une solution évidente.

Les blocs de données ont la structure suivante. Bien sûr, en réalité, les trames de données sont beaucoup plus grandes.

for (i in 1:nrow(B)) {
  B$count[i] <- sum(A$key1 == B$key1[i] & A$key2 == B$key2[i], na.rm = TRUE)
}

J'ai utilisé la boucle for suivante et j'ai obtenu le résultat correct.

A <- data.frame(c(1, 2, 1), c(2, 1, 2), c("alpha", "bravo", "charlie")) 
colnames(A) <- c("key1", "key2", "value")

B <- data.frame(c(1, 2, 3), c(2, 1, 3), NA)
colnames(B) <- c("key1", "key2", "count")


0 commentaires

3 Réponses :


3
votes

En utilisant la même logique que vous mais sans boucle en utilisant mapply

B$count <- mapply(function(x, y) 
      sum(x == A$key1 & y == A$key2, na.rm = TRUE), B$key1, B$key2)

B
#  key1 key2 count
#1    1    2     2
#2    2    1     1
#3    3    3     0


0 commentaires

3
votes

Voici une idée utilisant merge ,

library(data.table)

setDT(A)[setDT(B), on = c('key1', 'key2')][, 
          .(count = sum(!is.na(value))), by = c('key1', 'key2')]

#   key1 key2 count
#1:    1    2     2
#2:    2    1     1
#3:    3    3     0

qui donne,

# A tibble: 3 x 3
# Groups:   key1 [?]
   key1  key2 count
  <dbl> <dbl> <int>
1     1     2     2
2     2     1     1
3     3     3     0

Ajout de la solution data.table pour terminer,

library(tidyverse)

A %>% 
 full_join(B, by = c('key1', 'key2')) %>% 
 group_by(key1, key2) %>% 
 summarise(count = sum(!is.na(value)))


0 commentaires

4
votes

Une option en base R (similaire à l'option @Sotos tidyverse)

library(data.table)
setDT(A)[B, .(count = sum(!is.na(value))), on = .(key1, key2), by = .EACHI]
#   key1 key2 count
#1:    1    2     2
#2:    2    1     1
#3:    3    3     0

Ou avec data.table

aggregate(cbind(count = !is.na(value)) ~ key1 + key2, merge(A, B, all = TRUE), sum)
#    key1 key2 count
#1    2    1     1
#2    1    2     2
#3    3    3     0


3 commentaires

Hein ... donc pas besoin de convertir les deux cadres en tables de données avant de fusionner? Un seul suffit?


@Sotos Oui, l'un d'entre eux suffit surtout l'extérieur


Vous avez tout d'abord mis à jour. Je laisserai aux gens le soin de comparer la mauvaise syntaxe data.table à la bonne syntaxe :)