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

列c1の「a」と「b」に正と負の数がいくつあるかを数える4番目の列c4を追加したいと思います。ただし、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 " "

c2 = "v1"の場合、2つの正の数と1つの負の数があるため、2/1の値が使用されます。

現時点では、集計関数を使用して最も接近しましたが、それでも実際には正しくありません。そのような問題に使用するより良い関数があるかどうかわかりませんか?

4

3 に答える 3

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 )

ただし、そのシンプルさddplyから from plyrpackageを使用することをお勧めします。

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  )

@flodelddplyの解決策については、私がどのように行うかです。

于 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 に答える