我有一个包含2列的数据框,一个标识符和带有名称的列。列ID中有几个标识符(见下文)。
ID Names
uc001aag.1 DKFZp686C24272
uc001aag.1 DQ786314
uc001aag.1 uc001aag.1
uc001aah.2 AK056232
uc001aah.2 FLJ00038
uc001aah.2 uc001aah.1
uc001aah.2 uc001aah.2
uc001aai.1 AY217347
现在我想创建一个这样的数据框:
ID Names
uc001aag.1 DKFZp686C24272 | DQ786314 | uc001aag.1
uc001aah.2 AK056232 | FLJ00038 | uc001aah.1 | uc001aah.2
uc001aai.1 AY217347
任何人都可以帮助我吗?
答案 0 :(得分:4)
您可以使用aggregate
:
R> aggregate(Names ~ ID, data=tmp, FUN=paste, collapse=" | ")
ID Names
1 uc001aag.1 DKFZp686C24272 | DQ786314 | uc001aag.1
2 uc001aah.2 AK056232 | FLJ00038 | uc001aah.1 | uc001aah.2
3 uc001aai.1 AY217347
答案 1 :(得分:4)
聚合速度非常快,但您可以使用sapply解决方案来并行化代码。这可以使用snowfall
:
require(snowfall)
sfInit(parallel=TRUE,cpus=2)
sfExport("Data")
ID <- unique(Data$ID)
CombNames <- sfSapply(ID,function(i){
paste(Data$Names[Data$ID==i],collapse=" | ")
})
data.frame(ID,CombNames)
sfStop()
并行版本将为您提供额外的加速,但单个sapply解决方案实际上比聚合慢。 Tapply有点快,但无法使用降雪进行并行化。在我的电脑上:
n <- 3000
m <- 3
Data <- data.frame( ID = rep(1:n,m),
Names=rep(LETTERS[1:m],each=n))
# using snowfall for parallel sapply
system.time({
ID <- unique(Data$ID)
CombNames <- sfSapply(ID,function(i){
paste(Data$Names[Data$ID==i],collapse=" | ")
})
data.frame(ID,CombNames)
})
user system elapsed
0.02 0.00 0.33
# using tapply
system.time({
CombNames <- tapply(Data$Names,Data$ID,paste,collapse=" | ")
data.frame(ID=names(CombNames),CombNames)
})
user system elapsed
0.44 0.00 0.44
# using aggregate
system.time(
aggregate(Names ~ ID, data=Data, FUN=paste, collapse=" | ")
)
user system elapsed
0.47 0.00 0.47
# using the normal sapply
system.time({
ID <- unique(Data$ID)
CombNames <- sapply(ID,function(i){
paste(Data$Names[Data$ID==i],collapse=" | ")
})
data.frame(ID,CombNames)
})
user system elapsed
0.75 0.00 0.75
注意:
为了记录,更好的解决方案是:
CombNames <- sapply(split(Data$Names,Data$ID),paste,collapse=" | ")
data.frame(ID=names(CombNames),CombNames)
相当于tapply。但是并行化这个实际上比较慢,因为你必须在sfSapply
内移动更多的数据。速度来自将数据集复制到每个cpu。当您的数据集很庞大时,您必须记住这一点:您将以更多的内存使用量来支付速度。