2014-05-11 39 views
0

我想在一列中的一個的cumsum突破期間將一行分成兩個(或多個)行。 是否有任何優雅的方式來執行這樣的特定行爆炸使用data.table? 請不要關注cumsum(我使用的順序是從最近排到最早排的cumsum),嚴格來說,我想從下面的代碼轉換dtrdtR用行爆發的data.table轉換

# current data 
dt <- data.table(
    time_id = 101:110, 
    desc = c('asd','qwe','xyz','qwe','qwe','xyz','asd','asd','qwe','asd'), 
    value = c(5.5,3.5,14,0.7,6,5.5,9.3,29.8,4,7.2) 
) 
dt[, cum_value_from_now := rev(cumsum(rev(value)))] 
period_width <- 10 
dt[, value_period := ceiling(cum_value_from_now/period_width)*period_width] 
dt 

# expected result 
rdt <- data.table(
    time_id = c(101,102,103,103,104,105,105,106,107,107,108,108,108,108,109,109,110), 
    desc = c('asd','qwe','xyz','xyz','qwe','qwe','qwe','xyz','asd','asd','asd','asd','asd','asd','qwe','qwe','asd'), 
    value = c(5.5,3.5,6.5,7.5,0.7,1.8,4.2,5.5,0.3,9,1,10,10,8.8,1.2,2.8,7.2) 
)[, cum_value_from_now := rev(cumsum(rev(value)))][, value_period := ceiling(cum_value_from_now/period_width)*period_width] 
rdt 

# validation 
all.equal(
    dt[,list(time_id,desc,value)], 
    rdt[,list(value = sum(value)), by=c('time_id','desc')] 
) 

編輯:我意識到我的問題是沒有很好地解釋我想執行的轉變。爲了更好地理解打破期間含義請看看我的rdtcum_value_from_now值從最後到第一。每個value_period完全由cumsum填充,valuevalue的其餘部分作爲新行生成(如果value足夠大,則它生成多行)以適應下一個時期。謝謝

+2

你是什麼意思的「打破時期」?對我們有些同情:使用一個矩陣,沒有'data.table'操作和期望的結果發佈一個小的,可重現的例子。同樣有用:告訴我們這個功能的重點是什麼,因爲實現最終目標可能有一種更簡單的方法。 –

+0

「打破期間」最好由'value_period'變量定義。它是一種分組變量,在這個例子中,用'10'分組cumsum。至於「矩陣」的例子,我已經很久沒有使用矩陣了,我記得它可能無法在矩陣中混合數據類型。在我真正的'data.table'中,我還使用了更復雜的數據類型,因此將其轉換爲矩陣更加困難。重點是將適合兩個(或更多)時間段的行拆分成多個行,這些行將聚合到源行 - 如驗證步驟中那樣。 – jangorecki

回答

1

首先,你似乎不一致地應用你的規則。如果「打破期間」意味着一行有value_period不同於前一行,那麼第2行打破了這一時期,但你不這樣對待它。

其次,你永遠不會解釋價值的分割。例如,第3行有value=14。這在rdt中被替換爲具有值6.5和7.5的兩行。這些增加到14,但沒有解釋爲什麼這應該是6.5和7.5,而不是說,7和7.因此,在下面的解決方案中我平等地劃分。

下面的代碼會生成一個通過測試的結果,但由於上述問題存在問題,因此與您的rdt不完全相同。

dt[,diff:=c(-diff(value_period)/10,0)] 
rdt <- dt[,list(value=as.numeric(rep(value/(diff+1),diff+1))), 
      by=list(time_id,desc,cum_value_from_now, value_period)] 

all.equal(
    dt[,list(time_id,desc,value)], 
    rdt[,list(value = sum(value)), by=c('time_id','desc')] 
) 
# [1] TRUE 
+0

感謝您的輸入。 廣告。第一,請看看我的'rdt'從最後一個到第一個'cum_value_from_now'值。每個'value_period'被完全填充,剩下的值被生成爲新的行以適應下一個週期。 廣告。第3行,它被分割爲6.5和7.5來精確填寫期間。拆分爲7,7會產生不滿足週期的行,但仍略微超過0.5。 廣告。下面的代碼,重新計算您的rdt上的'cum_value_from_now',看看它是不適合的時期。 我希望我的解釋清楚,期待您的答案更新。提前感謝 – jangorecki