2013-07-07 69 views
2

我有一個由幾個基因(newID)和相關值組成的大表。一些基因(newID)是唯一的,一些基因(多個行)。如何從表中排除那些只有一個事件(行)?在下面的例子中,只有最後一行會被刪除,因爲它是唯一的。使用data.table來選擇非唯一行

head(exons.s, 10) 
         Row.names exonID pvalue log2fold.5_t.GFP_t.    newID 
1 ENSMUSG00000000001_Gnai3:E001 E001 0.3597070   0.029731989 ENSMUSG00000000001 
2 ENSMUSG00000000001_Gnai3:E002 E002 0.6515167   0.028984837 ENSMUSG00000000001 
3 ENSMUSG00000000001_Gnai3:E003 E003 0.8957798   0.009665072 ENSMUSG00000000001 
4 ENSMUSG00000000001_Gnai3:E004 E004 0.5308266  -0.059273822 ENSMUSG00000000001 
5 ENSMUSG00000000001_Gnai3:E005 E005 0.4507640  -0.061276835 ENSMUSG00000000001 
6 ENSMUSG00000000001_Gnai3:E006 E006 0.5147357  -0.068357886 ENSMUSG00000000001 
7 ENSMUSG00000000001_Gnai3:E007 E007 0.5190718  -0.063959853 ENSMUSG00000000001 
8 ENSMUSG00000000001_Gnai3:E008 E008 0.8999434   0.032186993 ENSMUSG00000000001 
9 ENSMUSG00000000001_Gnai3:E009 E009 0.5039369   0.133313175 ENSMUSG00000000001 
10 ENSMUSG00000000003_Pbsn:E001 E001  NA     NA ENSMUSG00000000003 
> dim(exons.s) 
[1] 234385  5 

隨着plyr我會去這樣的:

## remove single exon genes: 
multEx <- function(df){ 
    if (nrow(df) > 1){return(df)} 
} 

genes.mult.ex <- ddply(exons.s , .(newID), multEx, .parallel=TRUE) 

但是,這是非常緩慢的。我想這是很容易與data.table但我無法弄清楚:

exons.s <- data.table(exons.s, key="newID") 
x.dt.out <- exons.s[, lapply(.SD, multEx), by=newID] 

我是新來data.table所以在正確的方向的任何指針將受到歡迎。

回答

4

創建一個列給每個組中行的數量,那麼子集:

exons.s[,n:=.N,by=newID] 
exons.s[n>1] 
+0

當然!乾杯。 – fridaymeetssunday

+0

或者,如果你不想分配一個新列:'exons.s [,c(.SD,n = .N),by = newID] [n> 1]' –

+1

只要語法簡單,I認爲這是最自然的版本:'exons.s [,.SD [.N> 1],by = newID]' – eddi

2

有這樣使用複製()函數,而不是計數組大小的更簡單,更effiecent方式。

首先,我們需要生成一個測試dastaset:

# Generate test datasets 
smallNumberSampled <- 1e3 
largeNumberSampled <- 1e6 

smallDataset <- data.table(id=paste('id', 1:smallNumberSampled, sep='_'), value1=sample(x = 1:26, size = smallNumberSampled, replace = T), value2=letters[sample(x = 1:26, size = smallNumberSampled, replace = T)]) 
largeDataset <- data.table(id=paste('id', 1:largeNumberSampled, sep='_'), value1=sample(x = 1:26, size = largeNumberSampled, replace = T), value2=letters[sample(x = 1:26, size = largeNumberSampled, replace = T)]) 

# add 2 % duplicated rows: 
smallDataset <- rbind(smallDataset, smallDataset[sample(x = 1:nrow(smallDataset), size = nrow(smallDataset)* 0.02)]) 
largeDataset <- rbind(largeDataset, largeDataset[sample(x = 1:nrow(largeDataset), size = nrow(largeDataset)* 0.02)]) 

然後我們實現三個解決方案的功能:

# Original suggestion 
getDuplicatedRows_Count <- function(dt, columnName) { 
    dt[,n:=.N,by=columnName] 
    return(dt[n>1]) 
} 

# Duplicated using subsetting 
getDuplicatedRows_duplicated_subset <- function(dt, columnName) { 
    return(dt[which(duplicated(dt[,columnName, with=FALSE]) | duplicated(dt[,columnName, with=FALSE], fromLast = T) ),]) 
} 

# Duplicated using the "by" argument to avoid copying 
getDuplicatedRows_duplicated_by <- function(dt, columnName) { 
    return(dt[which(duplicated(dt[,by=columnName]) | duplicated(dt[,by=columnName], fromLast = T) ),]) 
} 

然後我們測試,他們給了相同的結果

results1 <- getDuplicatedRows_Count  (smallDataset, 'id') 
results2 <- getDuplicatedRows_duplicated_subset(smallDataset, 'id') 
results3 <- getDuplicatedRows_duplicated_by(smallDataset, 'id') 

> identical(results1, results2) 
[1] TRUE 
> identical(results2, results3) 
[1] TRUE 

而我們時間3種解決方案的平均表現:

# Small dataset 
> system.time(temp <- replicate(n = 100, expr = getDuplicatedRows_Count   (smallDataset, 'id')))/100 
user system elapsed 
0.00176 0.00007 0.00186 
> system.time(temp <- replicate(n = 100, expr = getDuplicatedRows_duplicated_subset(smallDataset, 'id')))/100 
user system elapsed 
0.00206 0.00005 0.00221 
> system.time(temp <- replicate(n = 100, expr = getDuplicatedRows_duplicated_by (smallDataset, 'id')))/100 
user system elapsed 
0.00141 0.00003 0.00147 

#Large dataset 
> system.time(temp <- replicate(n = 100, expr = getDuplicatedRows_Count   (largeDataset, 'id')))/100 
user system elapsed 
0.28571 0.01980 0.31022 
> system.time(temp <- replicate(n = 100, expr = getDuplicatedRows_duplicated_subset(largeDataset, 'id')))/100 
user system elapsed 
0.24386 0.03596 0.28243 
> system.time(temp <- replicate(n = 100, expr = getDuplicatedRows_duplicated_by (largeDataset, 'id')))/100 
user system elapsed 
0.22080 0.03918 0.26203 

這表明duplicate()方法的縮放比例更好,尤其是在使用「by =」選項的情況下。

UPDATE:11月21日相同的輸出(如建議的阿倫 - 感謝)在2014年測試使用data.table v 1.9.2中發現的問題與我在哪裏,重複的fromLast不起作用。我更新到v 1.9.4並重新分析,現在差異小得多。

UPDATE:2014年11月26日。包含並測試了「by =」方法從data.table中提取列(正如Arun所建議的,因此信用額度已達到此值)。此外,對運行時間的測試在100次測試中取平均值,以確保結果的正確性。

+0

答案是否相同? – Arun

+0

好的建議阿倫 - 我已經相應地更新了答案。 –

+0

謝謝。 'duplicate'爲data.tables還有一個'by ='參數來指定列名,而不是必須子集(它複製data.table)。 – Arun