Je souhaite réorganiser les lignes d'une data.table en fonction d'une séquence d'indices donnée, ce que fait setcolorder pour les colonnes. Y a-t-il une fonction pour cela?
Voici un exemple reproductible, avec le résultat attendu.
> DT = data.table(mtcars, keep.rownames=TRUE)[1:3]
> DT
rn mpg cyl disp hp drat wt qsec vs am gear carb
1: Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
2: Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
3: Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
> ord = c(3,1,2)
> setroworder(DT, ord)
> DT
rn mpg cyl disp hp drat wt qsec vs am gear carb
1: Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
2: Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
3: Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
3 Réponses :
Si votre vecteur entier n'est pas inhérent à la table, alors je ne vois pas de fonction pour le faire automatiquement (j'espère que d'autres interviendront, je ne suis pas un data.table - gourou). En l'absence de cela, voici une fonction rapide, avec des appels message ennuyeux pour afficher l'adresse mémoire de l'objet, pour montrer que cela est fait en interne (et ne change pas l'emplacement mémoire):
x <- data.table(a = 1:10) setroworder(x, c(3,1,2,4:10))[] # # 0000000012EFF1A8 # # 0000000012EFF1A8 # # 0000000012EFF1A8 # # 0000000012EFF1A8 # # 0000000012EFF1A8 # a # 1: 3 # 2: 1 # 3: 2 # 4: 4 # 5: 5 # 6: 6 # 7: 7 # 8: 8 # 9: 9 # 10: 10
En action:
setroworder <- function(DT, vec, verbose = TRUE, vecname = NA) {
if (is.logical(verbose)) verbose <- if (verbose) message else c
verbose("# ", data.table::address(DT))
if (is.na(vecname)) {
# find an unused name
vecname <- make.unique(c(colnames(DT), "vec"))[ ncol(DT) + 1L ]
}
verbose("# ", data.table::address(DT))
set(DT, i = NULL, j = vecname, value = order(vec))
verbose("# ", data.table::address(DT))
setorderv(DT, vecname)
verbose("# ", data.table::address(DT))
set(DT, j = vecname, value = NULL)
verbose("# ", data.table::address(DT))
invisible(DT) # convenience only, this function operates in side-effect
}
En fait, cette réponse (ainsi que ma réponse d'origine) est fausse en ce qu'elle ne donne pas le même comportement que setcolorder (voir ma modification).
Point intéressant. Bien que je ne sois pas familier avec sort.int (..., index.return = TRUE) , je pense que order suffit également.
Bon, je vois que vous avez édité votre solution pour qu'elle donne maintenant le comportement "correct".
Modifier . La réponse d'origine n'a pas donné un comportement équivalent à secolorder . neworder doit être "l'index de recherche" de la nouvelle commande, par exemple neworder = c (3, 1, 2) donne la 3ème ligne comme nouvelle première ligne, la 1ère ligne comme nouvelle deuxième ligne, etc ...
Voici ma solution: p>
> x <- as.data.table(mtcars)
> head(x)
mpg cyl disp hp drat wt qsec vs am gear carb
1: 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
2: 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
3: 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
4: 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
5: 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
6: 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
> set.seed(42)
> head(setroworder(x, sample(32)))
mpg cyl disp hp drat wt qsec vs am gear carb
1: 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
2: 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
3: 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
4: 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
5: 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
6: 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
Test:
setroworder <- function(x, neworder) {
# This is assumes that there is some convention that colnames do not start with '.'.
# I don't know if there is any such convention though.
x[, .indexcol := sort.int(neworder, index.return = TRUE)$ix]
setorder(x, .indexcol)
x[, .indexcol := NULL]
}
Il semble que vous ayez trouvé une réponse fonctionnelle, les seules différences étant: le nom de la variable dynamique et la verbosité facultative. Bon travail. (J'ai dû supprimer temporairement la recherche d'un problème de non-reproductibilité causé par l'empoisonnement de ma source mtcars .)
neworder doit être l '"index de recherche" du nouvel ordre, par exemple neworder = c (3, 1, 2) donne la 3ème ligne comme nouvelle première ligne, la 1ère ligne comme nouvelle deuxième ligne, etc ...
# example DT = data.table(mtcars, keep.rownames=TRUE)[1:3] ord = c(3,1,2) DT rn mpg cyl disp hp drat wt qsec vs am gear carb 1: Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 2: Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 3: Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 # use DT[ord, do_stuff]: setorderv(DT[ord, .rn := .I], ".rn")[] rn mpg cyl disp hp drat wt qsec vs am gear carb .rn 1: Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 1 2: Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 2 3: Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 3Comme indiqué dans un commentaire, je pense que ce serait une mauvaise idée de se débarrasser de la colonne capturant l'ordre des lignes, mais vous pouvez créer un wrapper pour vous en débarrasser comme dans le d'autres réponses.
Il peut être nécessaire d'utiliser
1: .Ndans une future version si le comportement de.Ichange comme indiqué ici: https://github.com/Rdatatable/data.table/issues/2598
Merci pour le lien vers la discussion, Frank. Le prospect si vous utilisez .I / .i (et .N / .n ) comme global / local semble assez intuitif une fois que vous vous êtes habitué aux variables fixes «arcanes» de data.table (leur mot, pas le mien) ... mais probablement trop tard pour le .N change (pour compatibilité descendante). Cela explique pourquoi tant de mes apprentissages sur data.table ont été interrompus en essayant d'utiliser .I . Merci!
C'est la réponse la plus astucieuse. Il semble que vous ayez obtenu une version non réassignante de DT [ord,] que @ r2evans avait initialement demandée. Mais je doute de l'intérêt de conserver .rn , qui sera toujours 1: .N .
@JamesHirschorn, je ne suis pas en désaccord avec la suggestion de Frank de ne pas rejeter la variable ... mais en même temps, il semble qu'elle "encombre mes données". S'il s'agit d'une commande et / ou d'une commande unique, autrement ne changera jamais (c.-à-d. Pas de jointures, d'ajouts, de suppressions), peut-être que la suppression n'a aucun effet. Je suis d'accord, c'est la plus simple des réponses (jusqu'à présent).
@JamesHirschorn Ouais, je suppose que je ne me fais pas confiance pour ne pas réorganiser les tables plus tard (par exemple, en lier plusieurs ou un autre setkey) et j'aime la transparence (donc moi et n'importe qui d'autre pouvons voir "hé, cette table est indexée, donc Réfléchissez à deux fois avant de modifier la commande ») et la possibilité de réorganiser puis de revenir en arrière. Je suppose que si la table est très grande, je pourrais supprimer la colonne pour économiser de la RAM et de l'espace horizontal lors de l'impression de la table; ou si j'étais très proche de la fin de mon code (par exemple, sur le point d'imprimer le résultat dans R markdown).
@JamesH Merci pour la modification. Concernant votre message sur github, vous voudrez peut-être le modifier pour qu'il soit un FR clair plutôt que d'obliger les gens à cliquer (lorsqu'ils lisent peut-être des notifications par e-mail), puis à analyser quelle partie de nos questions et réponses StackOverflow est la FR. Voici quelques lignes directrices / attentes pour data.table: github.com/Rdatatable/data. table / wiki / Assistance
@Frank J'ai eu "Demande de fonctionnalité" dans le titre, mais un développeur a changé cela en une étiquette de demande de fonctionnalité (je ne savais pas comment ajouter des étiquettes). Il a également dit que ma question SO était "mal posée", j'ai donc édité ma question pour donner un exemple reproductible avec le résultat attendu.
@JamesHirschorn Merci. Ouais, seuls les propriétaires de projet sur github peuvent ajouter des balises comme "demande de fonctionnalité" donc rien de plus que vous n'auriez pu faire avec ça. En général, je pense qu'il est préférable de publier des descriptions complètes des problèmes sur ce site, car les questions et les demandes de fonctionnalités ont naturellement un formatage différent; les gens lisent souvent les problèmes de github dans les e-mails; etc.
Peut-être une version non réassignante de
DT <- DT [vec,]? (En "non-réaffectant", j'assume une forme d'affectation interne, sans avoir besoin de réaffecter une table à elle-même comme ça.)@ r2evans Je ne sais pas comment faire ça. Si vous savez, n'hésitez pas à poster une réponse.
Je ne vois pas de problème (sur les 698 actuels) qui inclut
order rows integer, peut-être pouvez-vous demander / suggérer une modification? github.com/Rdatatable/data.table/issuesImo, vous devez conserver la colonne qui capture l'ordre de ligne souhaité (assigné à NULL comme étape finale dans les deux réponses ci-dessous) si vous effectuez plusieurs opérations; et si vous ne faites qu'une seule opération, autant faire
DT [order (neworder), stuff_to_do]sans changer réellement l'ordre des lignes.@ r2evens J'ai ouvert un numéro (# 3686) demandant cette fonctionnalité.