2012-11-25 53 views
0

考虑下面的数据帧:这里汇总使用的功能吗?

d <- data.frame(c1=c(rep("a",6),rep("b",6)), 
       c2=c("v1","v1","v2","v3","v3","v1", "v2","v3","v1","v2","v3","v2"), 
       c3=c(1.4,-1.2,1.5,1.6,-1.7,1.2, -1.1,-1.2,1.3,1.5,1.1,-1.9)) 

我想添加一个第4列C4计数许多正数和负数如何在那里为列C1“A”和“B”。但是,在c2等于“v1”的情况下,只应考虑c3中的那些值。此外,如果仅存在正或负的值的空字符串应打印

所以对于我的例子的第4列应为:

> d 
    c1 c2 c3 c4 
1 a v1 1.4 2/1 
2 a v1 -1.2 2/1 
3 a v2 1.5 2/1 
4 a v3 1.6 2/1 
5 a v3 -1.7 2/1 
6 a v1 1.2 2/1 
7 b v2 -1.1 " " 
8 b v3 -1.2 " " 
9 b v1 1.3 " " 
10 b v2 1.5 " " 
11 b v3 1.1 " " 
12 b v2 -1.9 " " 

要的2/1的值作为有是两个正数和一个负数,其中c2 =“v1”

目前我使用聚合函数来最接近,但我仍然没有真正把它做对。不知道是否有更好的功能用于这类问题?

回答

3

对于使用多列,我发现plyr更方便(比一个(或多个)由您小组其他)任何东西:

ddply(d, "c1", transform, 
       c4 = { pos <- sum(c2 == "v1" & c3 >= 0) 
         neg <- sum(c2 == "v1" & c3 < 0) 
         ifelse(pos * neg == 0, ' ', paste(pos, neg, sep = '/')) }) 

# c1 c2 c3 c4 
# 1 a v1 1.4 2/1 
# 2 a v1 -1.2 2/1 
# 3 a v2 1.5 2/1 
# 4 a v3 1.6 2/1 
# 5 a v3 -1.7 2/1 
# 6 a v1 1.2 2/1 
# 7 b v2 -1.1  
# 8 b v3 -1.2  
# 9 b v1 1.3  
# 10 b v2 1.5  
# 11 b v3 1.1  
# 12 b v2 -1.9  
+0

很抱歉回到你们这么晚了。还有其他的事情要做。我非常感谢你在这里完成的工作!非常感谢! – user969113

3

如果你想使用纯R基本aggregate应该是您的朋友:

ag <- aggregate.data.frame(
    d$c3, 
    by = list(d$c1, d$c2), 
    FUN = function(x){ paste(sum(x < 0), sum(x>0), sep="/") } 
) 
> ag 
    Group.1 Group.2 x 
1  a  v1 1/2 
2  b  v1 0/1 
3  a  v2 0/1 
4  b  v2 2/1 
5  a  v3 1/1 
6  b  v3 1/1 

那么你可以merge汇总数据到原来的data.frame:

d <- merge(d, ag, by.x = c("c1", "c2"), by.y = c("Group.1", "Group.2"), all.x = TRUE) 

然而,我建议使用ddplyplyr包由于其简单:

library("plyr") 
d <- ddply(d, c("c1","c2"), function(x) { 
    x$c4 <- paste(sum(x$c3 < 0), sum(x$c3 > 0), sep="/") 
    return(x) 
}) 

编辑:

在已经重读的问题,这应该是使用aggregate正确的解决方案:

d.sub <- d[ d$c2 == "v1", , drop=FALSE ] 
ag <- aggregate(
    d.sub$c3, 
    by = list(d.sub$c1), 
    FUN = function(x){ # taken from @flodel 
    pos <- sum(x < 0); 
    neg <- sum(x > 0); 
    ifelse(pos * neg == 0, "", paste(pos, neg, sep="/")) 
    } 
) 
d <- merge(d, ag, by.x = "c1", by.y = "Group.1", all.x = TRUE ) 

关于ddply @ flodel的解决方案是我怎么会做它的。

+0

我想你误解了这个问题,'c1'应该是唯一的分组变量。然后,在每个组内,结果仅基于一个数据子集,其中'c2 ==“v1”'。从OP的描述和预期输出中可以清楚地看出。 – flodel

+0

@flodel你是对的:-) – Beasterfield

+0

我觉得你已经证明'aggregate'可能不是这个特定任务的最佳工具,因为'merge'步骤会非常昂贵。如果我在这里使用'base'方法,那么也许'split/lapply/rbind'会更好。这是'ddply'为你做的。 – flodel

1

下面是一个使用略有不同的方法与ddply另一种解决方案:

library(plyr) 
ddply(d, .(c1), transform, c4 = { 
         tab <- table(factor(sign(c3[c2 == "v1"]), c(1, -1))); 
         ifelse(any(tab == 0), " ", paste(tab, collapse = "/")) }) 



# c1 c2 c3 c4 
# 1 a v1 1.4 2/1 
# 2 a v1 -1.2 2/1 
# 3 a v2 1.5 2/1 
# 4 a v3 1.6 2/1 
# 5 a v3 -1.7 2/1 
# 6 a v1 1.2 2/1 
# 7 b v2 -1.1  
# 8 b v3 -1.2  
# 9 b v1 1.3  
# 10 b v2 1.5  
# 11 b v3 1.1  
# 12 b v2 -1.9 
+0

恕我直言,难以破译。在零点附近也不是很灵活。 – flodel

+0

@ flodel你为什么觉得它在零点附近不是很灵活? –

+0

因为'sign(0)'等于'0',不是吗?所以他们被当前的代码删除。如果用户想要对一个或另一个(正数或负数)进行零计数,那不会太容易。 – flodel