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 " "

对于 a ,使用 2/1 的值,因为有两个正数和一个负数,其中 c2="v1"

目前我最接近使用聚合函数,但我仍然没有真正做到正确。不确定是否有更好的功能可用于此类问题?

4

3 回答 3

3

如果你想使用纯 R-baseaggregate应该是你的朋友:

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 )

但是,由于它的简单性,我建议使用ddplyfrom package:plyr

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 的解决方案,我也是这样做的。

于 2012-11-25T12:15:25.837 回答
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    
于 2012-11-25T12:18:40.763 回答
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
于 2012-11-25T12:24:01.480 回答