quando rbind
due data.table
con i fattori ordinati, l'ordine sembra essere perso:
dtb1 = data.table(id = factor(c("a", "b"), levels = c("a", "c", "b"), ordered=T), key="id")
dtb2 = data.table(id = factor(c("c"), levels = c("a", "c", "b"), ordered=T), key="id")
test = rbind(dtb1, dtb2)
is.ordered(test$id)
#[1] FALSE
Qualche idea, idea?
risposte:
7 per risposta № 1data.table
fa un po 'di gioco di gambe che significa questo data.table:::.rbind.data.table
si chiama quando rbind
è chiamato su oggetti compresi data.tables
. .rbind.data.table
utilizza le accelerazioni associate a rbindlist
, con un po 'di controllo extra per corrispondere per nome ecc.
.rbind.data.table
tratta con colonne di fattori usando c
combinarli (mantenendo quindi l'attributo livelli)
# the relevant code is
l = lapply(seq_along(allargs[[1L]]), function(i) do.call("c",
lapply(allargs, "[[", i)))
In base
R
utilizzando c
in questo modo non mantiene l'attributo "ordinato", non restituisce nemmeno un fattore!
Ad esempio (in base
R
)
f <- factor(1:2, levels = 2:1, ordered=TRUE)
g <- factor(1:2, levels = 2:1, ordered=TRUE)
# it isn"t ordered!
is.ordered(c(f,g))
# [1] FALSE
# no suprise as it isn"t even a factor!
is.factor(c(f,g))
# [1] FALSE
però data.table
ha un metodo S3 c.factor
, che viene utilizzato per garantire che venga restituito un fattore e che i livelli vengano mantenuti. Sfortunatamente questo metodo non mantiene l'attributo ordinato.
getAnywhere("c.factor")
# A single object matching ‘c.factor’ was found
# It was found in the following places
# namespace:data.table
# with value
#
# function (...)
# {
# args <- list(...)
# for (i in seq_along(args)) if (!is.factor(args[[i]]))
# args[[i]] = as.factor(args[[i]])
# newlevels = unique(unlist(lapply(args, levels), recursive = TRUE,
# use.names = TRUE))
# ind <- fastorder(list(newlevels))
# newlevels <- newlevels[ind]
# nm <- names(unlist(args, recursive = TRUE, use.names = TRUE))
# ans = unlist(lapply(args, function(x) {
# m = match(levels(x), newlevels)
# m[as.integer(x)]
# }))
structure(ans, levels = newlevels, names = nm, class = "factor")
}
<bytecode: 0x073f7f70>
<environment: namespace:data.table
Quindi sì, questo è un bug. Ora è segnalato come # 5019.
1 per risposta № 2
Come di versione 1.8.11 data.table
unirà i fattori ordinati per ottenere risultati ordered
se esiste un ordine globale, e si lamenterà e determinerà un fattore se non esiste:
DT1 = data.table(ordered("a", levels = c("a","b","c")))
DT2 = data.table(ordered("a", levels = c("a","d","b")))
rbind(DT1, DT2)$V1
#[1] a a
#Levels: a < d < b < c
DT3 = data.table(ordered("a", levels = c("b","a","c")))
rbind(DT1, DT3)$V1
#[1] a a
#Levels: a b c
#Warning message:
#In rbindlist(lapply(seq_along(allargs), function(x) { :
# ordered factor levels cannot be combined, going to convert to simple factor instead
Per contrasto, ecco cosa fa R di base:
rbind(data.frame(DT1), data.frame(DT2))$V1
#[1] a a
#Levels: a < b < c < d
# Notice that the resulting order does not respect the suborder for DT2
rbind(data.frame(DT1), data.frame(DT3))$V1
#[1] a a
#Levels: a < b < c
# Again, suborders are not respected and new order is created
-1 per risposta № 3
Ho incontrato lo stesso problema dopo rbind
, basta riassegnare il livello ordinato per la colonna.
test$id <- factor(test$id, levels = letters, ordered = T)
È meglio definire fattore dopo rbind