2014-02-16 43 views
2

我與〜450個000行中的以下數據:爲什麼未分裂這麼慢

'data.frame': 451712 obs. of 7 variables: 
$ mid: int 5732 5732 5732 5732 5732 5732 5732 5732 5732 5732 ... 
$ id : int 25 26 28 29 30 31 33 36 37 38 ... 
$ x : num 3197 5545 3205 6947 7264 ... 
$ y : num 6138 5555 6209 5465 5230 ... 
$ t : Factor w/ 2 levels "C","L": 2 2 2 2 2 2 2 2 2 2 ... 
$ r : Factor w/ 5 levels "Aberrant","Both",..: 3 1 3 4 4 4 4 4 4 4 ... 
$ c : num 1 0 1 2 2 2 2 3 2 2 ... 

爲什麼以下操作花費很長的時間(> 5分鐘,我停止執行)

unsplit(split(data, data$mid), data$mid) 

split本身速度很快,但在合併數據時需要花費很長時間。如果我將數據截斷爲100 000行,那麼我可以在10秒內得到結果,但隨着行數增加,時間不會線性增加。

+1

你是否檢查過你的RAM分配?如果你咀嚼了所有這些,就會發生很多交換,導致更長的執行時間。如果你在'k * 1e5'塊上運行一個循環,看看會發生什麼。 –

+2

你真的需要擁有和以前一樣的數據嗎?如果不考慮只使用'do.call(rbind,split(data,data $ mid))',這在我的測試中看起來要快一點。 – nograpes

+0

另外,你可以添加一些代碼來生成像你這樣的數據,例如:'n <-1e7; d <-data.frame(d = factor(sample(1:10,n,replace = TRUE)),v = RNORM(N),V2 = RNORM(N),V3 = RNORM(N))'。我很難生成足夠大的數據,而這些數據在30秒內不會完成。 – nograpes

回答

7

雖然看起來很奇怪,但您需要了解的一點是,數據幀的速度非常慢。每一個修改數據幀的操作都是昂貴的,並且unsplit正在做的是通過重新插入修改每個分割的數據幀。每次修改內部邏輯時都需要複製整個數據幀。這就是所謂的爲unsplit部分:

`split<-.data.frame` 
function (x, f, drop = FALSE, ..., value) 
{ 
    ix <- split(seq_len(nrow(x)), f, drop = drop, ...) 
    n <- length(value) 
    j <- 0 
    for (i in ix) { 
     j <- j%%n + 1 
     x[i, ] <- value[[j]] 
    } 
    x 
} 
<bytecode: 0x7ffd5e282c68> 
<environment: namespace:base> 

x這裏是初始化爲你的結果的大小data.frame,你可以看到,基本上我們插入它每分裂。由於您的數據幀非常龐大,因此每個插入的代價都非常高。爲了強調爲什麼這是可怕的,考慮下面的例子,我們用數據框中的一列中的每個值進行基準測試,而對等效矩陣做同樣的事情。儘管我們做的是完全一樣的東西,但數據幀版本慢了30倍!這是爲了一個微小的數據框。當data.frame很大時,你可以很快看到這到底是怎麼回事。

df <- data.frame(a=seq(1:100), b=runif(100), c=sample(1:10, 100, rep=T)) 
mx <- as.matrix(df) 

microbenchmark(for(i in 1:nrow(df)) df[i, 2] <- 1) 
# Unit: milliseconds 
#         expr  min  lq median  uq  max neval 
# for (i in 1:nrow(df)) df[i, 2] <- 1 4.018833 4.273562 4.584293 4.726672 23.46349 100  

microbenchmark(for(i in 1:nrow(mx)) mx[i, 2] <- 1) 
# Unit: microseconds 
#         expr  min  lq median  uq  max neval 
# for (i in 1:nrow(mx)) mx[i, 2] <- 1 148.304 153.9795 158.5975 163.7065 277.861 100 

順便說一句,這就是爲什麼在上述類型的操作的建議是先計算向量,並在結束更換向量到數據幀列,以便只修改數據幀一次。

回覆:使用data.tabledplyr,我挑戰你張貼的問題分析的類型,你與split/unsplit做,我懷疑你會被這些軟件包多麼強大可以解決你的問題感到驚訝。

+0

哇! @BrodieG,謝謝你這麼全面的回答!現在很清楚爲什麼時間隨着團隊數量的增加而迅速增長。肯定會花一些時間來學習推薦的軟件包。 –