我有一个大的(600万行)值表,我认为需要重新格式化才能用于与我的数据集进行比较。该表有3列我关心。 第一列含有核苷酸碱基变化,呈C> G,A> C,A> G等形式。我希望将它们分成两个独立的列。 第二列具有染色体和碱基位置,格式为10:130448,2:40483,5:30821291等。我还想将其分成两列。 第三列在许多样本群体中具有等位基因部分,格式为.02 / .03 / .20。我想将第三部分提取到一个新列中。
问题是我写的代码目前非常慢。看起来大约需要一天半才能运行。我有什么东西在这里失踪吗?任何建议,将不胜感激。
我当前的代码执行以下操作:pos,change和fraction各自接收上述值的向量split split strsplit。然后我循环遍历整个数据库,从这三个向量中获取第i个值,并使用我想要的值创建新列。
数据库格式化后,我应该可以通过染色体编号,碱基,参考等位基因,备用等位基因等轻松检查大量样本。
pos <- strsplit(total.esp$NCBI.Base, ":")
change <- strsplit(total.esp$Alleles, ">")
fraction <- strsplit(total.esp$'MAFinPercent(EA/AA/All)', "/")
for (i in 1:length(pos)){
current <- pos[[i]]
mutation <- change[[i]]
af <- fraction[[i]]
total.esp$chrom[i] <- current[1]
total.esp$base[i] <- current [2]
total.esp$ref[i] <- mutation[1]
total.esp$alt[i] <- mutation[2]
total.esp$af[i] <- af[3]
}
谢谢!
答案 0 :(得分:3)
您可以使用tidyr
,dplyr
和separate
:
library(tidyr)
library(dplyr)
total.esp %>% separate(Alleles, c("ref", "alt"), sep=">") %>%
separate(NCBI.Base, c("chrom", "base"), sep=":") %>%
separate(MAFinPercent.EA.AA.All., c("af1", "af2", "af3"), sep="/") %>%
select(-af1, -af2, af = af3)
你最后需要注意MAFinPercent.EA.AA.All.
- 你有一个可怕的专栏名称,所以可能需要重命名/引用它取决于r的确切程度(这也是一个很好的理由)在您的问题中包含至少一些数据,例如dput(head(total.esp))
)的输出。
用于检查的数据:
total.esp <- data.frame(Alleles= rep("C>G", 50), NCBI.Base = rep("10:130448", 50), 'MAFinPercent(EA/AA/All)'= rep(".02/.03/.20", 50))
因为我们现在有一个tidyr/dplyr
解决方案,一个data.table
解决方案和一个基本解决方案,所以我们对它们进行基准测试。首先,来自@akrun的数据,总计300,000行:
df1 <- data.frame(Alleles =rep(c('C>G', 'A>C', 'A>G'), 100000),
NCBI.Base=rep(c('10:130448', '2:40483', '5:30821291'), 100000),
MAFinPercent= rep(c('.02/.03/.20', '.05/.03/.04', '.02/.04/.03'), 100000),
stringsAsFactors=FALSE)
现在,基准:
microbenchmark::microbenchmark(
tidyr = {df1 %>% separate(Alleles, c("ref", "alt"), sep=">") %>%
separate(NCBI.Base, c("chrom", "base"), sep=":") %>%
separate(MAFinPercent, c("af1", "af2", "af3"), sep="/") %>%
select(-af1, -af2, af = af3)},
data.table = {setDT(df1)[, unlist(lapply(.SD, tstrsplit,
split='[>:/]', type.convert=TRUE), recursive=FALSE)]},
base = {pos <- strsplit(df1$NCBI.Base, ":");
change <- strsplit(df1$Alleles, ">");
fraction <- strsplit(df1$MAFinPercent, "/");
data.frame( chrom =sapply( pos, "[", 1),
base = sapply( pos, "[", 2),
ref = sapply( change, "[", 1),
alt = sapply(change, "[", 2),
af = sapply( fraction, "[", 3)
)}
)
Unit: seconds
expr min lq mean median uq max neval
tidyr 1.295970 1.398792 1.514862 1.470185 1.629978 1.889703 100
data.table 2.140007 2.209656 2.315608 2.249883 2.481336 2.666345 100
base 2.718375 3.079861 3.183766 3.154202 3.221133 3.791544 100
tidyr
是赢家
答案 1 :(得分:3)
这是一个data.table
解决方案。我们转换了&#39; data.frame&#39;到&#39; data.table&#39; (setDT(df1)
),使用.SD
遍历Data.table(lapply
)的子集,通过指定拆分字符使用tstrsplit
和split
列, unlist
输出recursive=FALSE
。
library(data.table)#v1.9.6+
setDT(df1)[, unlist(lapply(.SD, tstrsplit,
split='[>:/]', type.convert=TRUE), recursive=FALSE)]
# Alleles1 Alleles2 NCBI.Base1 NCBI.Base2 MAFinPercent1 MAFinPercent2
#1: C G 10 130448 0.02 0.03
#2: A C 2 40483 0.05 0.03
#3: A G 5 30821291 0.02 0.04
# MAFinPercent3
#1: 0.20
#2: 0.04
#3: 0.03
注意:我假设数据集中只有3列。如果有更多列,并且只想对3列进行拆分,我们可以指定.SDcols= 1:3
即列索引或实际列名,将输出分配(:=
)到新列和子集仅在输出中需要的列。
df1 <- data.frame(Alleles =c('C>G', 'A>C', 'A>G'),
NCBI.Base=c('10:130448', '2:40483', '5:30821291'),
MAFinPercent= c('.02/.03/.20', '.05/.03/.04', '.02/.04/.03'),
stringsAsFactors=FALSE)
答案 2 :(得分:2)
试试这个(保留前三行代码后):
total.esp <- data.frame( chrom =sapply( pos, "[", 1),
base = sapply( pos, "[", 2),
ref = sapply( change, "[", 1),
alt = sapply(change, "[", 2),
af = sapply( af, "[", 3)
)
我无法想象这需要花费超过几分钟的时间。 (我使用类似大小的R对象。)