Ce que je voudrais faire
J'ai un cadre de données avec plusieurs facteurs de regroupement et d'autres données. J'aimerais regrouper les lignes en fonction de ces facteurs et marquer ou extraire toutes les lignes qui appartiennent à des groupes comptant plus d'un membre.
Le problème/la question
J'ai pu trouver une solution (voir l'exemple ci-dessous), mais elle n'est pas pratique en raison d'une inefficacité de interaction()
. Même si drop = TRUE
le temps d'exécution de interaction()
augmente considérablement lorsque le nombre de niveaux augmente. En fin de compte, j'aimerais traiter 10 à 20 facteurs avec jusqu'à 50 000 niveaux sur un data.frame de quelques centaines de milliers de lignes.
Questions : 1) Quelle est l'approche la plus efficace pour résoudre ce problème ? ("Efficace" est mesuré dans cet ordre par le temps d'exécution, la mémoire requise et la lisibilité du code)
Question 2) Quel est le problème avec interaction()
?
L'exemple
# number of rows
nobs <- 100000
# number of levels
nlvl <- 5000
#create two factors with a decent number of levels
fc1 <- factor(sample.int(nlvl, size = nobs, replace = TRUE))
fc2 <- factor(sample.int(nlvl, size = nobs, replace = TRUE))
#package in a data.frame together with some arbitrary data
wdf <- data.frame(fc1, fc2, vals = sample.int(2, size = nobs, replace = TRUE))
#just for information: number of unique combinations of factors, i.e. groups
ngroups <- nrow(unique(wdf[,1:2]))
print(ngroups)
#granular grouping, tt has nobs elements and ngroups levels
tt <- interaction(wdf[,1:2], drop = TRUE)
#grpidx contains for each row the corresponding group (i.e. level of tt)
#observe that length(grpidx) == nobs and max(grpidx) == ngroups
grpidx <- match(tt, levels(tt))
#split into list of groups (containing row indices)
grplst <- split(seq_along(grpidx), grpidx)
#flag groups with more than one member
flg_dup <- vapply(grplst, FUN = function(x)length(x)>1, FUN.VALUE = TRUE)
#collect all row indices of groups with more than one member
dupidx <- unlist(grplst[flg_dup])
#select the corresponding rows
nonunqdf <- cbind(grpidx[dupidx], wdf[dupidx,])
Moment de la ligne tt <- interaction(wdf[,1:2], drop = TRUE)
- nlvl == 500 : 82 millisecondes
- nlvl == 5000 : 28 secondes
- nlvl == 10000 : 233 secondes