2011-11-04 52 views
2

我正在嘗試重構一個巨大的數據框(大約12.000個案例):在舊的數據框中,一個人是一行並且有大約250列(例如Person 1,test A1,testA2, testB,...),並且我想要測試A的所有結果(1到10個A的整體和24個項目(AY)在一列中,所以一個人最終有24列和10行。也是一個固定的數據框部分在項目AY開始之前(像年齡,性別等個人信息),我想保持原樣(fixdata) 函數/循環適用於30個案例(我提前試過),但對於12.000,它仍然在計算,現在已經接近24小時了。任何想法爲什麼?R中的無限函數/循環:數據管理

restructure <- function(data, firstcol, numcol, numsets){ 
    out <- data.frame(t(rep(0, (firstcol-1)+ numcol))) 
    names(out) <- names(daten[0:(firstcol+numcol-1)]) 
     for(i in 1:nrow(daten)){ 
     fixdata <- (daten[i, 1:(firstcol-1)]) 

      for (j in (seq(firstcol, ((firstcol-1)+ numcol* numsets), by = numcol))){ 
       flexdata <- daten[i, j:(j+numcol-1)] 
       tmp <- cbind(fixdata, flexdata) 
       names(tmp) <- names(daten[0:(firstcol+numcol-1)]) 
       out <- rbind(out,tmp) 
      } 
     } 
    out <- out[2:nrow(out),] 
    return(out) 
} 

提前致謝!

+4

這聽起來像是一個重塑問題。看看包'reshape2'中的函數'melt'。你的'data.frame'實際上並不那麼龐大。如果'熔化'不能在一秒內處理不了,我會很驚訝。 (類似的問題已經在SO上定期出現了,爲了一些靈感,搜索「[r] reshape」 – Andrie

+0

Andrie是正確的。一般來說,儘量不要在大數據集上使用for循環,同時你可以嘗試如下: 'system.time(restructure([30datasets]))'',然後'system.time(restructure([300datasets]))'等等。這至少會讓你知道現有的代碼需要多長時間才能完成N個數據集 –

+3

添加一個測試用例將有助於... –

回答

5

想法爲什麼:你在每次迭代中都會使用rbindout。這將需要更長的每次迭代隨着增長 - 所以你必須期望隨着數據集的增加運行時間超過線性增長。

所以,正如安德里告訴你可以看看melt

或者您可以使用核心R:stack。 然後,你需要自己cbind固定部分的結果,(你需要each = n.var.cols

第三種方法重複固定列是從包arrayhelpers array2df

+0

融化似乎是有幫助的,但我想知道如何融化數據塊的大塊。可以說我有ID,TestA1,TestA2,TestB1和TestB2。我想要這樣的東西:'行1:ID | TestA1 | TestA2'和'第2行:ID | TestB1 | TestB2'等。融化可能嗎? – Elisa

+0

'melt'一路融化數據集,'cast'把它放回你想要的形狀。 –

+0

雖然我不能讓它融化成塊,但它只能逐個融化所有變量......有人知道該怎麼做嗎? (看上面的例子) – Elisa

0

也許你沒有得到plyr或其他函數來重新調整數據組件,如何讓更直接和更低級別的東西如果你現在只有一條線去A1,A2,A3 ... A10,B1-B10等等,然後從那裏提取那些東西你的數據框,我猜測第11-250列,然後只是讓這個部分變成你想要的形狀,然後把它們放回去。

yDat <- data[, 11:250] 
yDF <- lapply(1:nrow(data), function(i) matrix(yDat[i,], ncol = 24)) 
yDF <- do.call(rbind, y) #combine the list of matrices returned above into one 
yDF <- data.frame(yDF) #get it back into a data.frame 
names(yDF) <- LETTERS[1:24] #might as well name the columns 

這是以您想要的形狀獲取大量數據的最快方法。所有lapply函數都是爲每行添加維度屬性,以便它們處於所需的形狀,然後將它們作爲列表返回,並用隨後的行進行處理。但是現在它沒有來自主數據幀的任何ID信息。你只需要複製前10列的每一行10次。或者,您可以使用便利功能merge來幫助解決該問題。創建一個已經在前10行中的公共列,並將它們合併。

yInfo <- data[, 1:10] 
ID <- yInfo$ID 
yDF$ID <- rep(yInfo$ID, each = 10) 
newDat <- merge(yInfo, yDF) 

現在大功告成......大多是,你可能想使一個額外的列名稱的新行

newDat$condNum <- rep(1:10, nrow(newDat)/10) 

這將是非常快的運行代碼。你的data.frame實際上並沒有那麼大,上面的大部分內容都會在幾秒鐘內完成。

這就是你應該如何考慮R中的數據。並不是說沒有方便的函數來處理大部分的數據,但是你應該這樣做,儘可能地避免循環。從技術上講,上面發生的事情只有一個循環,在開始時使用lapply。它在這個循環中也很少(當你使用它們時它們應該是緊湊的)。你用標量代碼編寫,而且它在R中非常慢......即使你在做這件事時並沒有真正濫用內存和增長數據。此外,請記住,雖然你不能總是避免某種循環,但幾乎總是可以避免嵌套循環,這是你最大的問題之一。

(讀this更好地理解這個代碼的問題......你所做的最有大的錯誤)

1

我與他人同意,考慮reshape2plyr包,只是想在另一個方向添加一點。特別是melt,cast,dcast可能會幫助你。另外,它可能有助於利用智能列名的,例如:

As<-grep("^testA",names(yourdf)) 
# returns a vector with the column position of all testA1 through 10s. 

此外,如果你對測試#和測試類型「花」一個data.frame的兩個維度,有明顯沒有離開的人。當然,你用一個ID標識它們,你可以在繪圖時添加一個美學,但是根據你想要做什麼,你可能想要將它們存儲在list中。所以你最終得到每個人都有一個data.frame的人員列表。我不確定你想要做什麼,但仍然希望這有助於。

+0

也許你也想爲我們創建一個最小的例子;) –