2015-08-09 83 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