2015-11-23 65 views
0

我目前使用ddply來應用我寫入數據框的函數。該函數根據列中的值評估每行,然後將多個其他函數應用於該行中的數據。結果是一個與輸入數據幀具有相同結構的數據幀,以及一個附加列,其中每行應用函數的結果。如何用Dplyr或Data.Table替換ddply

我的問題是數據集是相當大的,因此使用ddply需要很長時間 - 太長了的目的!

當時間很重要時,我已經閱讀了許多其他SO問題和關於替代品的博客帖子到ddply。大多數帖子都推薦使用dplyr包中的data.table或某些組合函數,其中do。雖然速度是最重要的,但我從來沒有使用過data.table,所以易用性/直觀性也很重要。

同樣,雖然this question在解釋如何結合您自己的函數使用不同的dplyr函數時非常有用,但我還需要將其他對象傳遞給我的函數,但我不確定如何使用問題中的答案。

我在下面創建了一個簡化示例。我的問題是如何複製以下ddply功能調用與dplyrdata table給出我的以上幾點。

首先,我設置一些數據以模擬實際的數據

noObs <- 1e5 
dataIn <- data.frame(One = rep(c("J", "K"), noObs/2), Two = rep(c("ID", "BR", "LB", "OZ"), noObs/4), 
        Three = runif(noObs)) 

secondaryData <- data.frame(Two = c("ID", "BR", "LB", "OZ"), Size = c(300, 500, 250, 400)) 

我的功能的一個簡單的例子是下面的結構(在實踐中,該函數的參數是大於2且它調用等功能本身)

MyFunction <- function(dataIn, secondaryData){ 

    groupNames <- c("BR", "LB") 

    if(dataIn$One == "J"){ 
    if(!(dataIn$Two%in%groupNames)){ 
     if(dataIn$Two == "ID"){ 
     idx <- match(dataIn$Two, secondaryData$Two) 
     value <- secondaryData[idx, "Size"] 
     dataIn$newCalc <- dataIn$Three*value 
     }else{ 
     dataIn$newCalc <- dataIn$Three*1000 
     } 
    }else{ 
     idx <- match(dataIn$Two, secondaryData$Two) 
     value <- secondaryData[idx, "Size"] 
     dataIn$newCalc <- dataIn$Three*value+1 
    } 
    }else{ 
    idx <- match(dataIn$Two, secondaryData$Two) 
    value <- secondaryData[idx, "Size"] 
    dataIn$newCalc <- dataIn$Three*value 
    } 

    return(dataIn) 

} 

ddply調用看起來像

dataOut <- ddply(dataIn, names(dataIn), MyFunction, secondaryData) 

最後的事情我已經嘗試了一些例子(我還沒有嘗試data.table

dataIn %>% group_by(names(dataIn)) %>% do(MyFunction(dataIn, secondaryData)) 
dataIn %>% group_by(names(dataIn)) %>% MyFunction(dataIn, secondaryData) 
dataIn %>% group_by(.dots = names(dataIn)) %>% MyFunction(secondaryData) 

編輯

我已經能夠找到一種方法與dplyr,除了它的作品甚至比慢與ddply,我不知道如何使用group_bynames。這對我來說不正確,因爲dplyr意味着更快。

此外,我一直在試驗data.table,但一直未能得到它的工作。再次,我要尋找運行速度比ddply

#Plyr 
start <- proc.time() 
dataOut <- ddply(dataIn, names(dataIn), MyFunction, secondaryData) 
plyrTime <- proc.time() - start 

#Dplyr 
#Works 
start <- proc.time() 
res <- dataIn %>% group_by(One, Two, Three) %>% do(MyFunction(.,secondaryData)) 
dplyrTime <- proc.time() - start 
#Doesn't work 
res <- dataIn %>% group_by(.,names(dataIn)) %>% do(MyFunction(.,secondaryData)) 

#Data.table 
dataInDT <- data.table(dataIn) 
dataInDT[,.(MyFunction(.,secondaryData)), by=.(One, Two, Three)] 
+0

也許'library(dplyr); dataIn%>%group_by _(。dots = names(dataIn))%>%myFunction(projSettings,secondaryData)''。請提供一個可重複的例子。 – lukeA

+6

SO不是一個代碼服務。向我們展示您已經嘗試過的內容(包括[可重現的示例])(http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/5963610))。 – Jaap

+0

@lukeA我添加了一個可重現的例子。希望這有助於 – Celeste

回答

0

我發現使用data.table解決的東西。值得注意的是,它爲每一行執行正確的計算,但速度非常快。功能的格式不同,以適應data.table的不同風格。我確信使用data.table有更好或更正確的解決方法,但下面的解決方案效果很好。

dataInDT <- data.table(dataIn) 

groupNames <- c("BR", "LB") 
start <- proc.time() 
dataInDT[, NewCalc := { 
    if(One == "J"){ 
    if(!(Two%in%groupNames)){ 
     if(Two == "ID"){ 
     Three*secondaryData[match(Two, secondaryData$Two), "Size"] 
     }else{ 
     Three*1000 
     } 
    }else{ 
     Three*secondaryData[match(Two, secondaryData$Two), "Size"]+1 
    } 
    }else{ 
    Three*secondaryData[match(Two, secondaryData$Two), "Size"] 
    }}, by=.(One, Two, Three)] 
datTableTime <- proc.time() - start 

這個比較老的解決方案,你可以看到速度大大提高

start <- proc.time() 
dataOut <- ddply(dataIn, names(dataIn), MyFunction, secondaryData) 
plyrTime <- proc.time() - start 

當然,在實踐中我使用了data.table功能更是錯綜複雜,特別是by切片更久,更長。

我無法找到使用dplyr的解決方案,我仍然很想知道它是如何工作的。

相關問題