J'ai une grande table data.table , avec de nombreuses valeurs manquantes dispersées dans ses ~ 200k lignes et 200 colonnes. Je voudrais recoder ces valeurs NA en zéros aussi efficacement que possible.
Je vois deux options:
1: Convertir en data.frame et utiliser quelque chose comme ceci
2: Une sorte de commande de sous-paramétrage data.table cool
Je serai satisfait d'une solution de type 1 assez efficace. La conversion en data.frame puis en data.table ne prendra pas trop de temps.
data.table
en undata.frame
? Adata.table
est undata.frame
. Toute opération data.frame fonctionnera.data.table
en spécifiant le numéro de colonne. doncDT[,3]
ne donnera pas la troisième colonne. Je pense que cela rend la solution proposée dans le lien non viable ici. je suis sûr qu'il existe une approche élégante utilisant une certainedata.table
magie!DT[, 3, with=FALSE]
renvoie la troisième colonne.mydf[is.na(mydf) == TRUE]
fait le travail sur les trames de données, alorsmydt[is.na(mydt) == TRUE]
que ça me donne quelque chose d'étrange même si j'utilisewith=FALSE
Réponses:
Voici une solution utilisant l' opérateur de data.table
:=
, s'appuyant sur les réponses d'Andrie et Ramnath.Notez que f_dowle a mis à jour dt1 par référence. Si une copie locale est requise, un appel explicite à la
copy
fonction est nécessaire pour créer une copie locale de l'ensemble de données. de data.tablesetkey
,key<-
et:=
ne pas copier-on-write.Ensuite, voyons où f_dowle passe son temps.
Là, je me concentrerais sur
na.replace
etis.na
, où il y a quelques copies vectorielles et numérisations vectorielles. Ceux-ci peuvent être assez facilement éliminés en écrivant une petite fonction C na.replace qui se metNA
à jour par référence dans le vecteur. Cela réduirait au moins de moitié les 20 secondes, je pense. Une telle fonction existe-t-elle dans un package R?La raison
f_andrie
échoue peut être parce qu'il copie la totalité dedt1
, ou crée une matrice logique aussi grande que l'ensemble dedt1
, plusieurs fois. Les 2 autres méthodes fonctionnent sur une colonne à la fois (même si je n'ai regardé que brièvementNAToUnknown
).EDIT (solution plus élégante comme demandé par Ramnath dans les commentaires):
J'aurais aimé le faire de cette façon pour commencer!
EDIT2 (plus d'un an plus tard, maintenant)
Il y a aussi
set()
. Cela peut être plus rapide s'il y a beaucoup de colonnes en boucle, car cela évite la (petite) surcharge de l'appel[,:=,]
dans une boucle.set
est une boucle:=
. Voir?set
.la source
eval(parse)...
truc. sur une note plus large, je pense qu'il serait utile d'avoir des opérations qui fonctionnent sur tous les éléments dudata.table
.data.table
approprié de le faire. Merci!DT
des colonnes de typelogical
, contrairement à l'create_dt()
exemple de ce test. Changez le 4ème argument de l'set()
appel (qui est0
dans votre exemple et tapez double dans R) enFALSE
et cela devrait fonctionner sans avertissement.seq_along(DT)
aussi. Mais alors le lecteur doit savoir que ceseq_along
serait le long des colonnes et non les lignes.seq_len(col(DT))
un peu plus explicite pour cette raison.Voici le plus simple que je puisse proposer:
dt[is.na(dt)] <- 0
C'est efficace et pas besoin d'écrire des fonctions et autres codes de glue.
la source
[.data.table
(dt, is.na (dt)): i est un type invalide (matrice). Peut-être qu'à l'avenir une matrice à 2 colonnes pourrait renvoyer une liste d'éléments de DT (dans l'esprit de A [B] dans la FAQ 2.14). Veuillez faire savoir à datatable-help si vous le souhaitez, ou ajouter vos commentaires à FR # 657. >set
Des fonctions dédiées (
nafill
etsetnafill
) à cet effet sont disponibles dans ledata.table
package (version> = 1.12.4):Il traite les colonnes en parallèle si bien pour répondre aux repères précédemment publiés, en dessous de ses délais par rapport à l'approche la plus rapide jusqu'à présent, et également mis à l'échelle, en utilisant une machine à 40 cœurs.
la source
Juste pour référence, plus lent par rapport à gdata ou data.matrix, mais utilise uniquement le package data.table et peut traiter des entrées non numériques.
la source
ifelse
et mettre à jour par référence en faisantDT[, names(DT) := lapply(.SD, function(x) {x[is.na(x)] <- "0" ; x})]
. Et je doute que ce soit plus lent que les réponses que vous avez mentionnées.Voici une solution utilisant
NAToUnknown
dans legdata
package. J'ai utilisé la solution d'Andrie pour créer un énorme tableau de données et j'ai également inclus des comparaisons de temps avec la solution d'Andrie.la source
user
heure similaire mais une très grande différence deelapsed
temps.rbenchmark
des solutions de référence en utilisant plus de réplications, mais j'ai eu une erreur de mémoire insuffisante probablement en raison de la taille de la trame de données. si vous pouvez exécuterbenchmark
ces deux solutions avec plusieurs réplications, ces résultats seraient intéressants car je ne sais pas vraiment pourquoi j'obtiens une accélération 3xncol=5
je pense (devraient prendre beaucoup plus de temps) en raison du boguecreate_dt
.Par souci d'exhaustivité, une autre façon de remplacer les NA par 0 consiste à utiliser
Pour comparer les résultats et les temps, j'ai intégré toutes les approches mentionnées jusqu'à présent.
La nouvelle approche est donc légèrement plus lente
f_dowle3
mais plus rapide que toutes les autres approches. Mais pour être honnête, cela va à l'encontre de mon Intuition de la syntaxe data.table et je n'ai aucune idée de pourquoi cela fonctionne. Quelqu'un peut-il m'éclairer?la source
Je crois comprendre que le secret des opérations rapides dans R est d'utiliser des vecteurs (ou des tableaux, qui sont des vecteurs sous le capot.)
Dans cette solution, j'utilise un
data.matrix
qui est unarray
mais se comporte un peu comme undata.frame
. Comme il s'agit d'un tableau, vous pouvez utiliser une substitution vectorielle très simple pour remplacer leNA
s:Une petite fonction d'aide pour supprimer le
NA
s. L'essence est une seule ligne de code. Je ne fais cela que pour mesurer le temps d'exécution.Une petite fonction d'aide pour créer un
data.table
d'une taille donnée.Démonstration sur un petit échantillon:
la source
remove_na
. Ce timing de 21,57 s inclut lecreate_dt
(y comprisrunif
etsample
) ainsi que leremove_na
. Avez-vous une chance que vous puissiez modifier pour séparer les 2 fois?create_dt
? Il semble toujours créer une table de données à 5 colonnes, indépendamment de lancol
transmission.Pour généraliser à de nombreuses colonnes, vous pouvez utiliser cette approche (en utilisant des exemples de données précédents mais en ajoutant une colonne):
Je n'ai pas testé la vitesse
la source
la source
Utilisation de la
fifelse
fonction du plus récentdata.table
versions 1.12.6, il est même 10 fois plus rapide queNAToUnknown
dans legdata
package:la source
f_dowle3
sera toujours plus rapide: stackoverflow.com/a/7249454/345660