Data.table'daki sütun sınıflarını dönüştürün


118

Data.table'ı kullanırken sorun yaşıyorum: Sütun sınıflarını nasıl dönüştürürüm? İşte basit bir örnek: data.frame ile onu data.table ile dönüştürmede sorun yaşamıyorum, nasıl yapacağımı bilmiyorum:

df <- data.frame(ID=c(rep("A", 5), rep("B",5)), Quarter=c(1:5, 1:5), value=rnorm(10))
#One way: http://stackoverflow.com/questions/2851015/r-convert-data-frame-columns-from-factors-to-characters
df <- data.frame(lapply(df, as.character), stringsAsFactors=FALSE)
#Another way
df[, "value"] <- as.numeric(df[, "value"])

library(data.table)
dt <- data.table(ID=c(rep("A", 5), rep("B",5)), Quarter=c(1:5, 1:5), value=rnorm(10))
dt <- data.table(lapply(dt, as.character), stringsAsFactors=FALSE) 
#Error in rep("", ncol(xi)) : invalid 'times' argument
#Produces error, does data.table not have the option stringsAsFactors?
dt[, "ID", with=FALSE] <- as.character(dt[, "ID", with=FALSE]) 
#Produces error: Error in `[<-.data.table`(`*tmp*`, , "ID", with = FALSE, value = "c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2)") : 
#unused argument(s) (with = FALSE)

Burada bariz bir şeyi özlüyor muyum?

Matthew'un gönderisi nedeniyle güncelleme: Daha önce eski bir sürümü kullandım, ancak 1.6.6'ya (şu an kullandığım sürüm) güncelledikten sonra bile hala bir hata alıyorum.

Güncelleme 2: Diyelim ki "faktör" sınıfının her sütununu bir "karakter" sütununa dönüştürmek istiyorum, ancak önceden hangi sütunun hangi sınıftan olduğunu bilmiyorum. Data.frame ile aşağıdakileri yapabilirim:

classes <- as.character(sapply(df, class))
colClasses <- which(classes=="factor")
df[, colClasses] <- sapply(df[, colClasses], as.character)

Data.table ile benzer bir şey yapabilir miyim?

Güncelleme 3:

sessionInfo () R sürüm 2.13.1 (2011-07-08) Platform: x86_64-pc-mingw32 / x64 (64-bit)

locale:
[1] C

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] data.table_1.6.6

loaded via a namespace (and not attached):
[1] tools_2.13.1

data.tableYöntemlerdeki "[" işleci argümanları için olduğundan farklıdata.frame
IRTFM

1
Lütfen yerine gerçek hatayı yapıştırın #Produces error. Yine de +1. Hata almadım, hangi sürüme sahipsiniz? Yine de bu alanda bir sorun var, daha önce gündeme getirildi, FR # 1224 ve FR # 1493 ele almak için yüksek önceliğe sahip. Andrie'nin cevabı yine de en iyi yoldur.
Matt Dowle

Sorumda bunu kaçırdığım için özür dilerim @MatthewDowle, yazımı güncelledim.
Christoph_J

1
@Christoph_J Teşekkürler. Bu invalid times argumenthatadan emin misin ? Benim için iyi çalış. Hangi sürüme sahipsiniz?
Matt Dowle

Yazımı sessionInfo () ile güncelledim. Ancak bugün iş makinemde kontrol ettim. Dün, ev makinemde (Ubuntu) aynı hata oluştu. R'yi güncelleyeceğim ve sorunun hala orada olup olmadığını göreceğim.
Christoph_J

Yanıtlar:


104

Tek bir sütun için:

dtnew <- dt[, Quarter:=as.character(Quarter)]
str(dtnew)

Classes ‘data.table’ and 'data.frame':  10 obs. of  3 variables:
 $ ID     : Factor w/ 2 levels "A","B": 1 1 1 1 1 2 2 2 2 2
 $ Quarter: chr  "1" "2" "3" "4" ...
 $ value  : num  -0.838 0.146 -1.059 -1.197 0.282 ...

Kullanılması lapplyve as.character:

dtnew <- dt[, lapply(.SD, as.character), by=ID]
str(dtnew)

Classes ‘data.table’ and 'data.frame':  10 obs. of  3 variables:
 $ ID     : Factor w/ 2 levels "A","B": 1 1 1 1 1 2 2 2 2 2
 $ Quarter: chr  "1" "2" "3" "4" ...
 $ value  : chr  "1.487145280568" "-0.827845218358881" "0.028977182770002" "1.35392750102305" ...

2
@Christoph_J Lütfen mücadele ettiğiniz gruplama komutunu gösterin (gerçek sorun). Basit bir şeyi kaçırmış olabileceğinizi düşünün. Neden sütun sınıflarını dönüştürmeye çalışıyorsunuz?
Matt Dowle

1
@Christoph_J Eğer data.table'ları değiştirmekte zorlanıyorsanız, neden onları geçici olarak data.frames'e dönüştürmeyesiniz, veri temizliği yapıp sonra geri data.tables'a dönüştürmeyesiniz?
Andrie

17
Bunu bir sütun alt kümesi için (tümü yerine) yapmanın deyimsel yolu nedir? convcolsSütunlardan oluşan bir karakter vektörü tanımladım . R neredeyse donarken dt[,lapply(.SD,as.numeric),.SDcols=convcols]neredeyse anında dt[,convcols:=lapply(.SD,as.numeric),.SDcols=convcols], bu yüzden yanlış yaptığımı tahmin ediyorum. Teşekkürler
Frank

4
@Frank Matt Dowle'un Geneorama'nın cevabına aşağıdaki yorumuna bakın ( stackoverflow.com/questions/7813578/… ); benim için yeterince yararlı ve deyimseldi [alıntıyı başlat] Başka ve daha kolay bir yol da set()örneğin for (col in names_factors) set(dt, j=col, value=as.factor(dt[[col]]))[son alıntı] kullanmaktır
swihart

4
Neden by = ID seçeneğini kullanıyorsunuz?
skan

48

Bunu dene

DT <- data.table(X1 = c("a", "b"), X2 = c(1,2), X3 = c("hello", "you"))
changeCols <- colnames(DT)[which(as.vector(DT[,lapply(.SD, class)]) == "character")]

DT[,(changeCols):= lapply(.SD, as.factor), .SDcols = changeCols]

7
şimdi Filtersütunları tanımlamak için işlevi kullanabilirsiniz , örneğin: changeCols<- names(Filter(is.character, DT))
David Leal

1
IMO Bu, seçilen cevabı verdiğim nedenden dolayı daha iyi cevaptır.
James Hirschorn

1
veya daha fazla öz: changeCols <- names(DT)[sapply(DT, is.character)].
sindri_baldur

8

Matt Dowle'un Geneorama'nın cevabına yaptığı yorumu ( https://stackoverflow.com/a/20808945/4241780 ) daha açık hale getirmek için (teşvik edildiği gibi) kullanabilirsiniz for(...)set(...).


library(data.table)

DT = data.table(a = LETTERS[c(3L,1:3)], b = 4:7, c = letters[1:4])
DT1 <- copy(DT)
names_factors <- c("a", "c")

for(col in names_factors)
  set(DT, j = col, value = as.factor(DT[[col]]))

sapply(DT, class)
#>         a         b         c 
#>  "factor" "integer"  "factor"

2020-02-12 tarihinde reprex paketi tarafından oluşturuldu (v0.3.0)

Daha fazla bilgi için https://stackoverflow.com/a/33000778/4241780 adresinde Matt'in başka bir yorumuna bakın .

Düzenle.

Espen ve in tarafından belirtildiği gibi help(set), j"Sütun isimleri (karakterleri) veya sayılar (tamsayı), sütun (lar) zaten mevcut olduğunda değer atanacak" olabilir. Bu names_factors <- c(1L, 3L)da işe yarayacak.


names_factorsBurada ne olduğunu eklemek isteyebilirsiniz . Ben alınan sanırım stackoverflow.com/a/20808945/1666063 o yüzden names_factors = c('fac1', 'fac2')bu durumda - bu da örneğin 1 sütun numaraları olabilir names.But sütundur; tüm sütunları dönüştürmek istiyorum Ncol (dt)
Espen Riskedal

@EspenRiskedal Teşekkürler İyi nokta, daha açık hale getirmek için yazıyı düzenledim.
JWilliman

2

Bu, bunu yapmanın KÖTÜ bir yolu! Bu yanıtı yalnızca diğer tuhaf sorunları çözmesi durumunda bırakıyorum. Bu daha iyi yöntemler, muhtemelen kısmen daha yeni data.table sürümlerinin sonucudur ... bu yüzden bu zor şekilde belgelemeye değer. Artı, bu sözdizimi için güzel bir sözdizimi örneğidir eval substitute.

library(data.table)
dt <- data.table(ID = c(rep("A", 5), rep("B",5)), 
                 fac1 = c(1:5, 1:5), 
                 fac2 = c(1:5, 1:5) * 2, 
                 val1 = rnorm(10),
                 val2 = rnorm(10))

names_factors = c('fac1', 'fac2')
names_values = c('val1', 'val2')

for (col in names_factors){
  e = substitute(X := as.factor(X), list(X = as.symbol(col)))
  dt[ , eval(e)]
}
for (col in names_values){
  e = substitute(X := as.numeric(X), list(X = as.symbol(col)))
  dt[ , eval(e)]
}

str(dt)

sana veren

Classes ‘data.table’ and 'data.frame':  10 obs. of  5 variables:
 $ ID  : chr  "A" "A" "A" "A" ...
 $ fac1: Factor w/ 5 levels "1","2","3","4",..: 1 2 3 4 5 1 2 3 4 5
 $ fac2: Factor w/ 5 levels "2","4","6","8",..: 1 2 3 4 5 1 2 3 4 5
 $ val1: num  0.0459 2.0113 0.5186 -0.8348 -0.2185 ...
 $ val2: num  -0.0688 0.6544 0.267 -0.1322 -0.4893 ...
 - attr(*, ".internal.selfref")=<externalptr> 

42
Başka ve daha kolay bir yol, set()örneğin kullanmaktırfor (col in names_factors) set(dt, j=col, value=as.factor(dt[[col]]))
Matt Dowle

1
Sanırım cevabım bunu tüm sürümler için tek satırda gerçekleştiriyor. setDaha uygun olup olmadığından emin değilim .
Ben Rollert

1
for(...)set(...)Burada daha fazla bilgi : stackoverflow.com/a/33000778/403310
Matt Dowle

1
@skan Güzel soru. Daha önce sorulan bulamazsanız, lütfen yeni bir soru sorun. Gelecekte başkalarına yardım eder.
Matt Dowle


0

Birkaç yaklaşım denedim.

# BY {dplyr}
data.table(ID      = c(rep("A", 5), rep("B",5)), 
           Quarter = c(1:5, 1:5), 
           value   = rnorm(10)) -> df1
df1 %<>% dplyr::mutate(ID      = as.factor(ID),
                       Quarter = as.character(Quarter))
# check classes
dplyr::glimpse(df1)
# Observations: 10
# Variables: 3
# $ ID      (fctr) A, A, A, A, A, B, B, B, B, B
# $ Quarter (chr) "1", "2", "3", "4", "5", "1", "2", "3", "4", "5"
# $ value   (dbl) -0.07676732, 0.25376110, 2.47192852, 0.84929175, -0.13567312,  -0.94224435, 0.80213218, -0.89652819...

, ya da

# from list to data.table using data.table::setDT
list(ID      = as.factor(c(rep("A", 5), rep("B",5))), 
     Quarter = as.character(c(1:5, 1:5)), 
     value   = rnorm(10)) %>% setDT(list.df) -> df2
class(df2)
# [1] "data.table" "data.frame"

0

Bunu yapmanın daha genel ve daha güvenli bir yolunu sağlıyorum,

".." <- function (x) 
{
  stopifnot(inherits(x, "character"))
  stopifnot(length(x) == 1)
  get(x, parent.frame(4))
}


set_colclass <- function(x, class){
  stopifnot(all(class %in% c("integer", "numeric", "double","factor","character")))
  for(i in intersect(names(class), names(x))){
    f <- get(paste0("as.", class[i]))
    x[, (..("i")):=..("f")(get(..("i")))]
  }
  invisible(x)
}

Fonksiyon .., data.table kapsamı dışında bir değişken elde etmemizi sağlar; set_colclass kolonlarınızın sınıflarını belirleyecektir. Bunu şu şekilde kullanabilirsiniz:

dt <- data.table(i=1:3,f=3:1)
set_colclass(dt, c(i="character"))
class(dt$i)

-1

Data.table'da sütun adları listeniz varsa, do sınıfını değiştirmek istersiniz:

convert_to_character <- c("Quarter", "value")

dt[, convert_to_character] <- dt[, lapply(.SD, as.character), .SDcols = convert_to_character]

Bu cevap aslında @ Nera'nın aşağıdaki cevabının kötü bir versiyonudur. Daha dt[, c(convert_to_character) := lapply(.SD, as.character), .SDcols=convert_to_character]yavaş data.frame atamasını kullanmak yerine sadece referansla atama yapın.
altabq

-3

Deneyin:

dt <- data.table(A = c(1:5), 
                 B= c(11:15))

x <- ncol(dt)

for(i in 1:x) 
{
     dt[[i]] <- as.character(dt[[i]])
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.