Ma question porte sur l'attribution par référence par rapport à la copie data.table
. Je veux savoir si on peut supprimer des lignes par référence, similaire à
DT[ , someCol := NULL]
Je veux savoir
DT[someRow := NULL, ]
Je suppose qu'il y a une bonne raison pour laquelle cette fonction n'existe pas, alors peut-être pourriez-vous simplement indiquer une bonne alternative à l'approche de copie habituelle, comme ci-dessous. En particulier, en allant avec mon exemple préféré (data.table),
DT = data.table(x = rep(c("a", "b", "c"), each = 3), y = c(1, 3, 6), v = 1:9)
# x y v
# [1,] a 1 1
# [2,] a 3 2
# [3,] a 6 3
# [4,] b 1 4
# [5,] b 3 5
# [6,] b 6 6
# [7,] c 1 7
# [8,] c 3 8
# [9,] c 6 9
Dites que je veux supprimer la première ligne de cette table data.table. Je sais que je peux le faire:
DT <- DT[-1, ]
mais souvent, nous voulons éviter cela, car nous copions l'objet (et cela nécessite environ 3 * N de mémoire, si N object.size(DT)
, comme indiqué ici . Maintenant, j'ai trouvé set(DT, i, j, value)
. Je sais comment définir des valeurs spécifiques (comme ici: définir tout valeurs des lignes 1 et 2 et des colonnes 2 et 3 à zéro)
set(DT, 1:2, 2:3, 0)
DT
# x y v
# [1,] a 0 0
# [2,] a 0 0
# [3,] a 6 3
# [4,] b 1 4
# [5,] b 3 5
# [6,] b 6 6
# [7,] c 1 7
# [8,] c 3 8
# [9,] c 6 9
Mais comment puis-je effacer les deux premières lignes, par exemple? Faire
set(DT, 1:2, 1:3, NULL)
définit le DT entier sur NULL.
Mes connaissances SQL sont très limitées, alors vous me dites: donnée data.table utilise la technologie SQL, y a-t-il un équivalent à la commande SQL
DELETE FROM table_name
WHERE some_column=some_value
dans data.table?
la source
data.table()
utilise autant la technologie SQL que l'on puisse établir un parallèle entre les différentes opérations en SQL et les différents arguments d'undata.table
. Pour moi, la référence à la «technologie» implique quelque part qu'elle sedata.table
trouve quelque part au-dessus d'une base de données SQL, ce qui n'est pas le cas d'AFAIK.DT[ , keep := .I > 1]
, puis un sous-ensemble pour des opérations ultérieures :,DT[(keep), ...]
peut-être mêmesetindex(DT, keep)
la vitesse de ce sous-ensemble. Ce n'est pas une panacée, mais cela vaut la peine d'être considéré comme un choix de conception dans votre flux de travail - voulez-vous vraiment supprimer toutes ces lignes de la mémoire ou préférez-vous les exclure? La réponse diffère selon le cas d'utilisation.Réponses:
Bonne question.
data.table
impossible de supprimer des lignes par référence pour le moment.data.table
peut ajouter et supprimer des colonnes par référence car il suralloue le vecteur des pointeurs de colonne, comme vous le savez. Le plan est de faire quelque chose de similaire pour les lignes et de permettre rapidementinsert
etdelete
. Une suppression de ligne utiliseraitmemmove
en C pour déplacer les éléments (dans chaque colonne) après les lignes supprimées. La suppression d'une ligne au milieu de la table serait encore assez inefficace par rapport à une base de données de stockage de lignes telle que SQL, qui est plus adaptée pour une insertion et une suppression rapides de lignes où que ces lignes se trouvent dans la table. Mais encore, ce serait beaucoup plus rapide que de copier un nouvel objet volumineux sans les lignes supprimées.D'un autre côté, comme les vecteurs de colonne seraient suralloués, les lignes pourraient être insérées (et supprimées) à la fin , instantanément; par exemple, une série chronologique croissante.
C'est classé comme un problème: supprimez les lignes par référence .
la source
fread
premier. Après cela, c'est assez élevé.DT[b<8 & a>3]
renvoie une nouvelle table data.table. Nous aimerions ajouterdelete(DT, b>=8 | a<=3)
etDT[b>=8 | a<=8, .ROW:=NULL]
. L'avantage de ce dernier serait de se combiner avec d'autres fonctionnalités[]
telles que les numéros de lignei
, la participationi
et leroll
bénéfice de l'[i,j,by]
optimisation.l'approche que j'ai adoptée pour rendre l'utilisation de la mémoire similaire à la suppression sur place consiste à sous-définir une colonne à la fois et à la supprimer. pas aussi rapide qu'une solution memmove C appropriée, mais l'utilisation de la mémoire est tout ce qui me préoccupe ici. quelque chose comme ça:
la source
memmove
s pour combler les lacunes, mais ce n'est pas grave.DT[, col:= NULL, with = F]
deset(DT, NULL, col, NULL)
Voici une fonction de travail basée sur la réponse de @ vc273 et les commentaires de @ Frank.
Et exemple de son utilisation:
Où "dat" est une table de données. La suppression de 14000 lignes de 1,4 million de lignes prend 0,25 seconde sur mon ordinateur portable.
PS. Puisque je suis nouveau dans SO, je ne pourrais pas ajouter de commentaire au fil de discussion de @ vc273 :-(
la source
À la place ou en essayant de définir sur NULL, essayez de définir sur NA (correspondant au type NA pour la première colonne)
la source
Le sujet intéresse encore beaucoup de monde (moi compris).
Que dire de cela? J'avais l'habitude
assign
de remplacer leglovalenv
et le code décrit précédemment. Il serait préférable de capturer l'environnement d'origine, mais au moins,globalenv
il est efficace en mémoire et agit comme un changement par ref.la source
address(DT); delete(DT, 3); address(DT)
), bien que cela puisse être efficace dans un certain sens.Voici quelques stratégies que j'ai utilisées. Je crois qu'une fonction .ROW pourrait arriver. Aucune de ces approches ci-dessous n'est rapide. Ce sont des stratégies un peu au-delà des sous-ensembles ou du filtrage. J'ai essayé de penser comme dba en essayant simplement de nettoyer les données. Comme indiqué ci-dessus, vous pouvez sélectionner ou supprimer des lignes dans data.table:
Remarque: .SD crée un sous-ensemble des données d'origine et vous permet de faire un peu de travail dans j ou data.table ultérieur. Voir https://stackoverflow.com/a/47406952/305675 . Ici, j'ai commandé mes iris par Sepal Length, prenez une Sepal.Length spécifiée comme minimum, sélectionnez les trois premiers (par Sepal Length) de toutes les espèces et renvoyez toutes les données d'accompagnement:
Les approches avant tout réorganisent une data.table de manière séquentielle lors de la suppression de lignes. Vous pouvez transposer une data.table et supprimer ou remplacer les anciennes lignes qui sont maintenant des colonnes transposées. Lorsque vous utilisez ': = NULL' pour supprimer une ligne transposée, le nom de la colonne suivante est également supprimé:
Lorsque vous transposez le data.frame à un data.table, vous souhaiterez peut-être renommer à partir du data.table d'origine et restaurer les attributs de classe en cas de suppression. L'application de ": = NULL" à une table de données maintenant transposée crée toutes les classes de caractères.
Vous pouvez simplement supprimer les lignes en double que vous pouvez faire avec ou sans clé:
Il est également possible d'ajouter un compteur incrémentiel avec '.I'. Vous pouvez ensuite rechercher des clés ou des champs dupliqués et les supprimer en supprimant l'enregistrement avec le compteur. Ceci est coûteux en calcul, mais présente certains avantages car vous pouvez imprimer les lignes à supprimer.
Vous pouvez également simplement remplir une ligne avec des 0 ou des NA, puis utiliser une requête i pour les supprimer:
la source
t
sur un data.frame n'est généralement pas une bonne idée; vérifiezstr(m_iris)
que toutes les données sont devenues chaîne / caractère. Btw, vous pouvez également obtenir des numéros de ligne en utilisantd_iris[duplicated(Key), which = TRUE]
sans créer de colonne de compteur.