簡體   English   中英

在整個data.table列上應用自定義函數?

[英]Apply a custom function on an entire column of data.table?

我有一個非常大的Data Table有兩列。 我希望在特定列上應用自定義函數。 生成問題的代碼如下:

require(data.table)
X <- rep("This is just random text", 1e5)
data <- data.frame(1:1e5, replicate(1, X, simplify=FALSE), stringsAsFactors=FALSE)
colnames(data) <- paste("X", seq_len(ncol(data)), sep="")
DT <- as.data.table(data)

現在,我們有一個大型數據表,看起來像

| X1 |            X2           |
|----|-------------------------|
| 1  | This is just random text|
| 2  | This is just random text|
| 3  | This is just random text|
| 4  | This is just random text|
| .. |            ...          |

如果我想在這個列的任何一個上做一些向量操作,考慮到這個data.table的大小非常大(約~100M行),該怎么辦?

我們來看一個X1列的例子。 假設,我想在其上應用以下功能:

Fun4X1 <- function(x){return(x+x*2)}

在X2列上有一個非常復雜的NLP函數,看起來像

Fun4X2 <- function(x){
             require(stringr)
             return(str_split(x, " ")[[1]][1])
          }

我該如何為大型數據集執行此操作? 請建議分鍾。 耗時的方法因為我的Function本身非常復雜。

PS我已嘗試過foreachsapply ,當然還有for-loop並且在一個相當不錯的硬件系統上都非常慢。

該方法應該與將任何其他內置(或包加載)函數應用於data.table的特定列data.table :使用list(fun(variable), otherfun(othervariable))類型的構造。 如果需要,您也可以命名結果列,否則它們將被命名為“V1”,“V2”等等。

換句話說,對於您的問題,您可以這樣做:

DT[, list(X1 = Fun4X1(X1), X2 = Fun4X2(X2))]

但是,我懷疑你的減速很多可能是由於你實際使用的功能造成的。 比較以下細微的改進:

Fun4X2.old <- function(x){
  require(stringr)
  return(str_split(x, " ")[[1]][1])
}

Fun4X2.new1 <- function(x) {
  vapply(strsplit(x, " "), 
         function(y) y[1], character(1))
} 

Fun4X2.new2 <- function(x) {
  vapply(strsplit(x, " ", fixed=TRUE), 
         function(y) y[1], character(1))
} 

Fun4X2.sub <- function(x) sub("(.+?) .*", "\\1", x)

X <- rep("This is just random text", 1e5)    

system.time(out1 <- Fun4X2.old(X))
#    user  system elapsed 
#  18.838   0.000  18.659 
system.time(out2 <- Fun4X2.new1(X))
#    user  system elapsed 
#   0.000   0.000   0.944 
system.time(out3 <- Fun4X2.new2(X))
#    user  system elapsed 
#   1.584   0.000   0.270 
system.time(out4 <- Fun4X2.sub(X))
#    user  system elapsed 
#   0.000   0.000   0.222 

最后一點,關於你的評論

@AnandaMahto我正在尋找類似的東西但是如果我使用你的解決方案然后文本列上的輸出沒有矢量化我得到相同的輸出,即使我在每行有不同的文本

順便提一下,您原來的Fun4X2() (上面重命名為Fun4X2.old() )表現出相同的行為。

DT2 <- data.table(X1 = 1:4, X2 = c("a b c", "d e f", "g h i", "j k l"))
DT2[, list(Fun4X1(X1), Fun4X2.old(X2))]
#    V1 V2
# 1:  3  a
# 2:  6  a
# 3:  9  a
# 4: 12  a

DT2[, list(Fun4X1(X1), Fun4X2.new1(X2))]
#    V1 V2
# 1:  3  a
# 2:  6  d
# 3:  9  g
# 4: 12  j

查看降雪包, http://cran.r-project.org/web/packages/snowfall/snowfall.pdf ,了解並行計算。 您可以設置本地群集並使用所有核心。 我發現通過在這個軟件包中使用sfApply ,它將我的大部分計算時間減少了5倍

(我有一個8核,所以它會快8倍,但顯然是將數據加載到集群並在最后收集它的成本)。

例如

install.packages('snowfall')

require(snowfall)
sfInit( parallel=TRUE, cpus=4 )
sfExport(list=c('DT','Fun4X1','Fun4X2'))
sfApply(DT,1,function(X) return(c(fun4X1(X[1]),fun4X2(X[2]))))
sfStop()

apply需要25.07秒, sfApply在我的機器上需要9.11秒

您可以使用快速和矢量化函數sub來解決第二個問題:

Fun4X2 <- function(x) sub("(.+?) .*", "\\1", x)

head(Fun4X2(DT[,X2]))
# [1] "This" "This" "This" "This" "This" "This"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM