1

大きなデータセットに取り組んでいますが、データのクリーニングに問題があります。私のデータセットは次のようになります。

data <- cbind (group = c(1,1,1,2,2,3,3,3,4,4,4,4,4), 
               member = c(1,2,3,1,2,1,2,3,1,2,3,4,5), 
               score = c(0,1,0,0,0,1,0,1,0,1,1,1,0)) 

スコアの合計が1に等しいグループを保持し、スコアの合計が0に等しいグループ全体を削除したいだけです。スコアの合計が1より大きいグループの場合、たとえば、スコアの合計=3、スコアが1の2つのグループメンバーをランダムに選択して、グループから削除します。その場合、データは次のようになります。

newdata <- cbind (group = c(1,1,1,3,3,4,4,4), 
                  member = c(1,2,3,2,3,1,3,5), 
                  score = c(0,1,0,0,1,0,1,0)) 

誰かが私がこれを成し遂げるのを手伝ってくれる?

4

3 に答える 3

1

私はあなたが望むことをする関数を定義します。次に、を使用ddplyして分割しgroupます。

myfun <- function(x) {
  if(sum(x$score)==1) {
    return(x)
  } else if(sum(x$score)==0) {
    return(data.frame())
  } else {
    row.names(x) <- NULL
    score.1 <- sample(as.integer(row.names(x[x$score==1,])), nrow(x[x$score==1,])-1)
    return(x[-score.1,])
  }
}

library(plyr)
ddply(as.data.frame(dat), .(group), myfun)

  group member score
1     1      1     0
2     1      2     1
3     1      3     0
4     3      1     1
5     4      1     0
6     4      2     1
7     4      3     1
于 2012-06-06T15:25:53.960 に答える
1

さまざまな操作を組み合わせた関数を作成します。これがそのような関数の1つであり、コメントが多いです。

process <- function(x) {
    ## this adds a vector with the group sum score
    x <- within(x, sumScore <- ave(score, group, FUN = sum))
    ## drop the group with sumScore == 0
    x <- x[-which(x$sumScore == 0L), , drop = FALSE]
    ## choose groups with sumScore > 1
    ## sample sumScore - 1 of the rows where score == 1L
    foo <- function(x) {
        scr <- unique(x$sumScore) ## sanity & take only 1 of the sumScore
        ## which of the grups observations have score = 1L
        want <- which(x$score == 1L)
        ## want to sample all bar one of these
        want <- sample(want, scr-1)
        ## remove the selected rows & retun
        x[-want, , drop = FALSE]
    }
    ## which rows are samples with group sumScore > 1
    want <- which(x$sumScore > 1L)
    ## select only those samples, split up those samples by group, lapplying foo
    ## to each group, then rbind the resulting data frames together
    newX <- do.call(rbind,
                    lapply(split(x[want, , drop = FALSE], x[want, "group"]),
                           FUN = foo))
    ## bind the sampled sumScore > 1L on to x (without sumScore > 1L)
    newX <- rbind(x[-want, , drop = FALSE], newX)
    ## remove row labels
    rownames(newX) <- NULL
    ## return the data without the sumScore column
    newX[, 1:3]
}

あなたのデータでそれ:

dat <- data.frame(group = c(1,1,1,2,2,3,3,3,4,4,4,4,4), 
                  member = c(1,2,3,1,2,1,2,3,1,2,3,4,5), 
                  score = c(0,1,0,0,0,1,0,1,0,1,1,1,0)) 

与える:

> set.seed(42)
> process(dat)
  group member score
1     1      1     0
2     1      2     1
3     1      3     0
4     3      1     1
5     3      2     0
6     4      1     0
7     4      3     1
8     4      5     0

何が欲しかったのかと思います。

更新:上記ではprocess()、内部関数foo()を書き直して1行のみをサンプリングし、他の行を削​​除することができました。foo()つまり、以下のものに置き換えます。

foo <- function(x) {
    scr <- unique(x$sumScore) ## sanity & take only 1 of the sumScore
    ## which of the grups observations have score = 1L
    want <- which(x$score == 1L)
    ## want to sample just one of these
    want <- sample(want, 1)
    ## return the selected row & retun
    x[want, , drop = FALSE]
}

これらは基本的に同じ操作ですがfoo()、1行だけを選択すると、意図した動作が明示的になります。scr-1サンプル値ではなく、スコア==1Lの行からランダムに1行を選択します。

于 2012-06-06T15:42:38.513 に答える
0
ugroups<-unique(data[,1])
scores<-sapply(ugroups,function(x){sum(data[,1]==x & data[,3]==1)})
data[data[,1]%in%ugroups[scores>0],]
....... etc

各グループの累積スコアなどが表示されます

于 2012-06-06T15:27:12.830 に答える