2015-08-09 50 views
1

這個問題類似於this,但它有一個C#答案,我需要一個R答案。R:樹上的聚合值

我有大約650行用的格式和數據部分50個文件非常相似,這個玩具數據:

dput(y) 
structure(list(level1 = c(4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 
4L, 4L, 4L), level2 = c(NA, 41L, 41L, 41L, 41L, 41L, 41L, 41L, 
42L, 42L, 42L, 42L), level3 = c(NA, NA, 4120L, 4120L, 4120L, 
4120L, 4120L, 4120L, NA, 4210L, 4210L, 4210L), level4 = c(NA, 
NA, NA, 412030L, 412030L, 412050L, 412050L, 412050L, NA, NA, 
421005L, 421005L), pid = c(NA, NA, NA, NA, 123456L, NA, 789012L, 
345678L, NA, NA, NA, 9L), description = c("income", "op.income", 
"manuf.industries", "manuf 1", "client 1", "manuf 2", "client 2", 
"client 3", "non-op.income", "financial", "interest", "bank 1" 
), value = c(NA, NA, NA, NA, 15000L, NA, 272860L, 1150000L, NA, 
NA, NA, 378L)), .Names = c("level1", "level2", "level3", "level4", 
"pid", "description", "value"), class = c("data.table", "data.frame" 
), row.names = c(NA, -12L), .internal.selfref = <pointer: 0x00000000001a0788>) 

每個在上value值行是一個「葉」 OA樹,分支在level列1至4列中標識。我想通過brach總結葉子並將相應的值放在value列中。

我預期的輸出結果如下:

dput(res) 
structure(list(level1 = c(4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 
4L, 4L, 4L), level2 = c(NA, 41L, 41L, 41L, 41L, 41L, 41L, 41L, 
42L, 42L, 42L, 42L), level3 = c(NA, NA, 4120L, 4120L, 4120L, 
4120L, 4120L, 4120L, NA, 4210L, 4210L, 4210L), level4 = c(NA, 
NA, NA, 412030L, 412030L, 412050L, 412050L, 412050L, NA, NA, 
421005L, 421005L), pid = c(NA, NA, NA, NA, 123456L, NA, 789012L, 
345678L, NA, NA, NA, 9L), description = c("income", "op.income", 
"manuf.industries", "manuf 1", "client 1", "manuf 2", "client 2", 
"client 3", "non-op.income", "financial", "interest", "bank 1" 
), value = c(1438238L, 1437860L, 1437860L, 15000L, 15000L, 1422860L, 
272860L, 1150000L, 378L, 378L, 378L, 378L)), .Names = c("level1", 
"level2", "level3", "level4", "pid", "description", "value"), class = c("data.table", 
"data.frame"), row.names = c(NA, -12L), .internal.selfref = <pointer: 0x00000000001a0788>) 

我知道這可以用一個for循環,但我想知道是否有任何更快,更簡單的替代來實現(我喜歡data.table或鹼解決方案,但任何其他包也可以)。什麼到目前爲止,我已經試過:

z4<-y[!is.na(pid),sum(value),by=level4] 
setkey(y,"level4");setkey(z4,"level4") 
y[z4,][is.na(pid)] 

這說明我在V1所需的值,所以我想看看我能不能將它們分配給value

y[z4,][is.na(pid),value:=i.V1] 
Error in eval(expr, envir, enclos) : object 'i.V1' not found 

我認爲這可能是造成因爲呼叫i.V1在鏈接[而不是在最初的y[z4呼叫。但是,如果我只是z4的子集,我怎麼能知道我應該分配幾個匹配的level4行中的哪一個(這就是爲什麼我想用is.na(pid),因爲y[z4,value:=i.V1]產生錯誤的結果,因爲它更新與level4匹配的所有值)。正如你所看到的,我對這個問題非常困惑,而且用「我的方法」,我還有3個關卡。

有沒有更簡單的方法來做到這一點?

回答

1

因爲每個級別的計算都需要上一級的計算,所以我認爲需要循環或遞歸。這裏有一個遞歸函數來獲取使用base R的值。你當然可以用data.table做類似的事情,這可能會更有效率。

## Use y as data.frame 
y <- as.data.frame(y) 

## Recursive function to get values 
f <- function(data, lvl=NULL) { 
    if (is.null(lvl)) lvl <- 1             # initialize level 
    if (lvl == 5) return (data)            # we are done 
    cname <- paste0("level", lvl)            # name of current level 
    nname <- ifelse (lvl == 4, "pid", paste0("level", lvl+1))     # name of next level 
    agg <- aggregate(as.formula(paste("value~", cname)), data=data, sum)  # aggregate data 
    inds <- (ms <- match(data[,cname], agg[,cname], F)) & is.na(data[,nname]) # find index of leaves to fill 
    data$value[inds] <- agg$value[ms[inds]]         # add new values 
    f(data, lvl+1)                # recurse 
} 

f(data=y) 
# level1 level2 level3 level4 pid  description value 
# 1  4  NA  NA  NA  NA   income 1438238 
# 2  4  41  NA  NA  NA  op.income 1437860 
# 3  4  41 4120  NA  NA manuf.industries 1437860 
# 4  4  41 4120 412030  NA   manuf 1 15000 
# 5  4  41 4120 412030 123456   client 1 15000 
# 6  4  41 4120 412050  NA   manuf 2 1422860 
# 7  4  41 4120 412050 789012   client 2 272860 
# 8  4  41 4120 412050 345678   client 3 1150000 
# 9  4  42  NA  NA  NA non-op.income  378 
# 10  4  42 4210  NA  NA  financial  378 
# 11  4  42 4210 421005  NA   interest  378 
# 12  4  42 4210 421005 9bank 1  378 

我認爲聚合步驟可以通過僅聚合數據的一個子集(如果需要的話)來提高效率。坦率地說,這很有趣,但是循環可能是一條可行的路。

+0

這很有效,但如果你允許我,我想保持一段時間,以查看是否有人可以用不同的方法考慮解決方案。謝謝! – PavoDive

+0

@PavoDive這是個好主意。這是一個奇怪的數據結構,因此看看人們肯定會想出什麼會很有趣。 – jenesaisquoi

+0

該數據結構屬於財務報表報表。級別爲賬戶:子賬戶:子子賬戶等。某些軟件以打印格式導出報告,而不是分析。在你的幫助下,我能夠分析它們,主要是通過「prop.table」 – PavoDive