web-dev-qa-db-fra.com

Comment exécuter Apply sur une table de données?

J'ai un data.table Avec les colonnes 2 à 20 sous forme de chaînes avec des espaces (par exemple, "Nom de l'espèce"). Je veux exécuter str_replace() sur toutes ces colonnes simultanément afin que tous les "Nom de l'espèce" deviennent "Nom_espèce". Je peux soit faire:

data.table(apply(as.data.frame(dt[,2:dim(dt)[2], with=F]), 2, 
                               function(x){ str_replace(x," ","_") }))

ou si je le garde en tant qu'objet data.table, alors je peux faire cette colonne à la fois:

dt[,SpeciesName := str_replace(SpeciesName, " ", "_")

Comment puis-je faire cela pour toutes les colonnes 2 jusqu'à la fin, similaire à celle ci-dessus?

33
Maiasaura

Complètement réécrit le 2015-11-24, pour corriger une erreur dans les versions précédentes.

Vous avez quelques options.

  1. Traitez toutes les colonnes cibles avec un appel incorporé à lapply(), en utilisant := Pour affecter les valeurs modifiées en place. Cela repose sur le support très pratique de := Pour l'affectation simultanée à plusieurs colonnes nommées sur son LHS.

  2. Utilisez une boucle for pour parcourir les colonnes cibles une par une, en utilisant set() pour modifier tour à tour la valeur de chacune.

  3. Utilisez une boucle for pour parcourir plusieurs appels "naïfs" à [.data.table(), chacun modifiant une seule colonne.

Ces méthodes semblent toutes à peu près aussi rapides, donc celle que vous utiliserez sera principalement une question de goût. (1) est joliment compact et expressif. C'est ce que j'utilise le plus souvent, bien que vous puissiez trouver (2) plus facile à lire. Parce qu'ils traitent et modifient les colonnes une par une, (2) ou (3) auront un avantage dans la rare situation où votre table de données est si grande que vous risquez de vous heurter aux limites imposées par votre R mémoire disponible de la session.

library(data.table)

## Create three identical 1000000-by-20 data.tables
DT1 <- data.table(1:1e6,
           as.data.table(replicate(1e6, paste(sample(letters, nr, TRUE),
                                             sample(letters, nr, TRUE)))))
cnames <- c("ID", paste0("X", 1:19))
setnames(DT1, cnames)
DT2 <- copy(DT1); DT3 <- copy(DT1)

## Method 1
system.time({
DT1[, cnames[-1] := lapply(DT1[,cnames[-1],with=FALSE],
                      function(x) gsub(" ", "_", x))]
})
##   user  system elapsed 
##  10.90    0.11   11.06 

## Method 2
system.time({
    for(cname in cnames[-1]) {
        set(DT2, j=cname, value=gsub(" ", "_", DT2[[cname]]))
    }
})
##   user  system elapsed 
##  10.65    0.05   10.70 

## Method 3
system.time({
    for(cname in cnames[-1]) {
        DT3[ , cname := gsub(" ", "_", DT3[[cname]]), with=FALSE]
    }
})
##   user  system elapsed 
##  10.33    0.03   10.37 

Pour plus de détails sur set() et :=, Lisez leur page d'aide, obtenue en tapant ?set Ou ?":=".

32
Josh O'Brien

Tu peux le faire:

library("stringr")
dt[, -1] <- lapply(dt[, -1], function(x) str_replace(x," ","_"))
7
flodel