2015-10-05 43 views
14

我想將data.table cols的子集轉換爲新類。這裏有一個受歡迎的問題(Convert column classes in data.table),但答案會創建一個新對象,而不是在起始對象上進行操作。在data.table中轉換* some *列類

拿這個例子:

dat <- data.frame(ID=c(rep("A", 5), rep("B",5)), Quarter=c(1:5, 1:5), value=rnorm(10)) 
cols <- c('ID', 'Quarter') 

如何以最佳方式轉換爲只cols列(例如)一個因素?在一個正常的data.frame你可以這樣做:

dat[, cols] <- lapply(dat[, cols], factor) 

但是,這並不爲data.table工作,而且也沒有這個

dat[, .SD := lapply(.SD, factor), .SDcols = cols] 

從馬特Dowle鏈接的問題中留言(從2013年12月)建議以下,這工作正常,但似乎不太優雅。

for (j in cols) set(dat, j = j, value = factor(dat[[j]])) 

是否有目前更好的data.table答案(即短+不產生計數器變量),或者我應該只使用上述+ rm(j)

+0

我相信方法馬特Dowle建議將是最好的。畢竟,他是* data.table *作者。 –

+1

是的,但評論是從2013年開始的,自那以後有很多軟件包更新,所以我認爲值得把這條釣魚線扔出 – arvi1000

+2

更多關於'for(...)set(...)'成語的詳細信息最近在這裏:http://stackoverflow.com/a/33000778/403310 –

回答

26

除了使用選項馬特Dowle的建議,更改列類的另一種方式如下:

dat[, (cols) := lapply(.SD, factor), .SDcols=cols] 

通過使用:=您可以通過引用更新數據表。支票,這是否工作:

> sapply(dat,class) 
     ID Quarter  value 
"factor" "factor" "numeric" 

正如評論suggeted通過@MattDowle,你也可以使用的for(...) set(...)組合如下:

for (col in cols) set(dat, j = col, value = factor(dat[[col]])) 

這將給予同樣的結果。第三個選擇是:

for (col in cols) dat[, (col) := factor(dat[[col]])] 

在一個較小的數據集,該for(...) set(...)選項比lapply選項快約三倍(但其實並不重要,因爲它是一個小的數據集)。在較大的數據集上(例如200萬行),這些方法中的每一種都需要大致相同的時間。對於在更大的數據集進行測試時,我用:

dat <- data.table(ID=c(rep("A", 1e6), rep("B",1e6)), 
        Quarter=c(1:1e6, 1:1e6), 
        value=rnorm(10)) 

有時候,你將不得不這樣做有點不同(例如,當數值存儲爲一個因素)。然後,你必須使用這樣的事情:

dat[, (cols) := lapply(.SD, function(x) as.integer(as.character(x))), .SDcols=cols] 


警告:下面的解釋是做事data.table三通。數據表不會通過引用進行更新,因爲複製是在內存中創建並存儲的(如@Frank指出的那樣)會增加內存使用量。它更多的是爲了解釋with=FALSE的工作。

當你想更改的列類,你會用一個數據框做同樣的方式,你必須添加with = FALSE如下:

dat[, cols] <- lapply(dat[, cols, with = FALSE], factor) 

的檢查,這是否工作:

> sapply(dat,class) 
     ID Quarter  value 
"factor" "factor" "numeric" 

如果您未添加with = FALSE,則數據表將評估爲dat[, cols]作爲向量。檢查的輸出差異dat[, cols]dat[, cols, with=FALSE]之間:

> dat[, cols] 
[1] "ID"  "Quarter" 

> dat[, cols, with=FALSE] 
    ID Quarter 
1: A  1 
2: A  2 
3: A  3 
4: A  4 
5: A  5 
6: B  1 
7: B  2 
8: B  3 
9: B  4 
10: B  5 
+1

我想你不想用'<-'。如果我在它之前和之後運行'address()',它看起來像修改不是通過引用(即使'[< - 。data.table'似乎覆蓋了這種用法)。 – Frank

+1

@Frank我知道,但是我添加了第二部分,主要是爲了解釋當你希望數據表以與數據框相同的方式返回列時,爲什麼需要'with = FALSE'。我添加了一個警告。 – Jaap

+0

是的,正如你指出的那樣,我知道'with'是如何工作的,但這不是'data.table'原生的方式。感謝主要的答案 – arvi1000

1

您可以使用.SDcols

dat[, cols] <- dat[, lapply(.SD, factor), .SDcols=cols]

+0

任何理由這是越來越downvotes?它似乎得到了提問者正在尋找的結果 – Chris

+1

與我對其他答案的評論相同。使用data.table的一個很大的優點是通過引用進行修改,但據我所知,'[<-'沒有利用這個優勢。 – Frank

+0

@克里斯人在這裏採取「沒有簡短答案」的指導方針有點過於嚴肅。儘管幾乎總是有擴展/闡述的空間。 – shadowtalker