2012-06-06 56 views
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的組員,並將他們從組中刪除。然後數據可能看起來像這樣:

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

有沒有人可以幫助我做到這一點?

+0

如果總分大於1,你是否總是刪除兩個組成員? – Chase

+0

如果一個組的分數總和大於1,我想ramdoly選擇一個有1分的成員,並將其保留在組中,並刪除組中有1分的其他成員。在這種情況下,我會保留組中有0分的組員。 – user187454

回答

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():僅選擇1排,使預期的行爲明確

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();我們希望從得分== 1L的那些中隨機選擇1行,而不是樣本scr-1的值。

+0

+1注重細節和簡潔! – Justin

+0

非常感謝。你的代碼工作得很好,你的筆記和代碼很有用。再次感謝你。 – user187454

+0

您的更新代碼也很棒。謝謝你幫助我。 – user187454

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 
+0

謝謝你的幫助。但這不完全是我想要的。對於第三組,我想保留第二名成績爲0的成員。對於第四組,我想只保留一個成員有1分,而另一個有0分。請在我的簡單中看到我的「newdata」上面的例子。 t – user187454

+0

@ user187454但是賈斯汀已經完成了90%的工作_for_你在這裏。剩下的就是稍微調整一下功能。 – joran

+0

請參閱我在我的回答中編輯的功能...以及@joran說的內容:) – Justin

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 

會給你累積的分數爲每個組等

+0

謝謝你的幫助。 – user187454