R 使用data.table选择非唯一行
我有一个很大的表,由几个基因newID和相关值组成。有些基因newID是唯一的,有些基因有多个实例出现在多行中。如何从表中排除只有一行出现的内容?在下面的示例中,仅删除最后一行,因为它是唯一的R 使用data.table选择非唯一行,r,unique,data.table,subset,R,Unique,Data.table,Subset,我有一个很大的表,由几个基因newID和相关值组成。有些基因newID是唯一的,有些基因有多个实例出现在多行中。如何从表中排除只有一行出现的内容?在下面的示例中,仅删除最后一行,因为它是唯一的 head(exons.s, 10) Row.names exonID pvalue log2fold.5_t.GFP_t. newID 1 ENSMUSG00000000001_Gnai3:E001 E001 0.3597
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,所以欢迎任何指向正确方向的指针 创建一列,给出每组中的行数,然后创建子集:
exons.s[,n:=.N,by=newID]
exons.s[n>1]
有一种更简单、更有效的方法可以使用复制函数而不是计算组大小 首先,我们需要生成一个测试数据集:
# 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) {
# .. means "look up one level"
return( dt[which( duplicated(dt[, ..columnName]) | duplicated(dt[, ..columnName], 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
这表明复制方法可以更好地扩展,尤其是在使用by=选项的情况下
更新:2014年11月21日。根据Arun-Thank的建议,对相同的输出进行测试,发现我在使用data.table v 1.9.2时出现了一个问题,其中重复的fromLast不起作用。我更新到v1.9.4并重新编辑了分析,现在差异小得多
更新:2014年11月26日。按照Arun的建议,包括并测试了从data.table中提取列的by=方法,因此这里有信用。此外,运行时测试平均超过100次,以确保结果的正确性 或者,如果您不想指定一个新列:exons.s[,c.SD,n=.n,by=newID][n>1]就语法简单而言,我认为这是最自然的版本:exons.s[,.SD[.n>1],by=newID]答案相同吗?谢谢。duplicated for data.tables还有一个用于指定列名的by=参数,而不必为复制data.table的子集创建子集。这又是一个多么好的习惯好的建议Arun-我已经相应地更新了答案,by=参数的效果更好。