Domanda:Convertire colonne di classe arbitraria alla classe di colonne corrispondenti in un altro data.table
sto lavorando in R. Voglio le colonne condivise di 2 data.tables (comune che significa lo stesso nome di colonna) per avere classi corrispondenti. Sto lottando con un modo per convertire genericamente un oggetto di classe sconosciuta alla classe sconosciuta di un altro oggetto.
Altro contesto:
so come impostare la classe di una colonna in un data.table, e so sulla la funzione as
. Inoltre, questa domanda non è interamente specifica data.table
, ma si presenta spesso quando utilizzo data.table
s. Inoltre, supponiamo che la coercizione desiderata sia possibile.
Ho 2 data.tables. Condividono alcuni nomi di colonne e tali colonne sono destinate a rappresentare le stesse informazioni. Per i nomi di colonna condivisi dalla tabella A e dalla tabella B, voglio che le classi di A corrispondano a quelle di B (o altro).
Esempio data.table
s:
A <- structure(list(year = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), stratum = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L)), .Names = c("year", "stratum"), row.names = c(NA, -45L), class = c("data.table", "data.frame"))
B <- structure(list(year = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), stratum = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L), bt = c(-9.95187702337873, -9.48946944434626, -9.74178662514147, -5.36167545158338, -4.76405522202426, -5.41964239804882, -0.0807951335119085, 0.520481719699774, 0.0393874225863578, 5.40557402913123, 5.47927931969583, 5.37228402911139, 9.82774396910091, 9.89629694010177, 9.98105260936272, -9.82469892896284, -9.42530210357904, -9.66171049964775, -5.17540952901709, -4.81859082470115, -5.3577146169737, -0.0685310909609001, 0.441383303157166, -0.0105897444321987, 5.24205882775199, 5.65773605162835, 5.40217185632441, 9.90299445851434, 9.78883672575814, 9.98747998379124, -9.69843398105195, -9.31530717395811, -9.77406601252698, -4.83080164375344, -4.89056304189872, -5.3904000267275, -0.121508487954861, 0.493798577602088, -0.118550709142654, 5.23654772583187, 5.87760447006892, 5.22478092346285, 9.90949768116403, 9.85433376398086, 9.91619307289277), yr = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3)), .Names = c("year", "stratum", "bt", "yr"), row.names = c(NA, -45L), class = c("data.table", "data.frame"), sorted = c("year", "stratum"))
Ecco quello che sembrano:
> A
year stratum
1: 1 1
2: 1 2
3: 1 3
4: 1 4
> B
year stratum bt yr
1: 1 1 -9.95187702 1
2: 1 2 -9.48946944 1
3: 1 3 -9.74178663 1
4: 1 4 -5.36167545 1
Qui ci sono le classi:
> sapply(A, class)
year stratum
"integer" "integer"
> sapply(B, class)
year stratum bt yr
"numeric" "integer" "numeric" "numeric"
Manualmente, posso realizzare il compito desiderato attraverso il seguente:
A[,year:=as.numeric(year)]
Questo è facile quando c'è solo 1 delle colonne per cambiare, si sa che di colonna prima del tempo, e si conosce la classe desiderata prima del tempo. Se lo si desidera, è anche abbastanza facile convertire colonne arbitrarie in una determinata classe. So anche come convertire colonne arbitrarie in una data classe.
Il mio tentativo è fallito:
(EDIT: Questo funziona in realtà, vedi la mia risposta)
s2c <- function (x, type = "list")
{
as.call(lapply(c(type, x), as.symbol))
}
# In this case, I can assume all columns of A can be found in B
# I am also able to assume that the desired conversion is possible
B.class <- sapply(B[,eval(s2c(names(A)))], class)
for(col in names(A)){
set(A, j=col, value=as(A[[col]], B.class[col]))
}
Ma questo ancora restituisce la colonna anno come "integer"
, non "numeric"
:
> sapply(A, class)
year stratum
"integer" "integer"
Il problema nell'esempio precedente è che class(as(1L, "numeric"))
restituisce ancora "integer"
. D'altra parte, class(as.numeric(1L))
restituisce "numeric"
; tuttavia, non so in anticipo che sia necessario il numero as.numeric
.
domanda, Restated:
Come faccio a fare la partita classi colonna, quando né colonne né i to
/from
classi sono noti prima del tempo?
Pensieri supplementari:
In un certo senso, la questione è per lo più sulla corrispondenza di classe arbitraria. Mi imbatto in questo problema spesso con data.table perché è molto vocale sulla corrispondenza delle classi. Ad esempio, si verificano problemi simili quando è necessario inserire NA
del tipo appropriato (NA_real_
rispetto a NA_character_
, ecc.), A seconda della classe della colonna (vedere domanda/problema correlato in This Question).
Ancora una volta, questa domanda può essere vista come un problema generale di conversione tra classi arbitrarie che non sono conosciute in anticipo. In passato, ho scritto delle funzioni usando switch
per fare qualcosa come switch(class(x), double = as.numeric(...), character = as.character(...), ...
, ma questo mi sembra un po 'brutto. L'unica ragione per cui sto portando tutto questo nel contesto di data.table è perché è il posto dove più spesso incontro la necessità di questo tipo di funzionalità.
Forse fare 'lapply (A,.%>% As.character%>% type.convert)' o simili su ognuno di essi. (Senza libreria (magrittr), questo è 'lapply (A, function (x) type.convert (as.character (x)))'). Questo è un modo molto crudo, però, e fallirà con classi di fantasia. – Frank
@Frank Non voglio necessariamente che entrambi condividano una classe arbitraria (carattere), ho bisogno di A per abbinare la classe di B. Questo è diverso dal tuo suggerimento, giusto? – rbatt
L'idea alla base del mio suggerimento era di dare loro la stessa classe, non necessariamente il carattere. 'type.convert' è la funzione utilizzata durante la lettura dei dati da un file di testo per determinare la classe di ciascuna colonna (ad esempio, in' fread' di data.table). Ho una variante di questa idea, ma è più lunga quindi la metterò in una risposta – Frank