zx8*_*754 20 bash awk cut bioinformatics subset
我们希望在行和列上对文本文件进行子集化,其中从文件中读取行和列编号.排除标题(第1行)和rownames(第1列).
inputFile.txt制表符分隔的文本文件
header 62 9 3 54 6 1
25 1 2 3 4 5 6
96 1 1 1 1 0 1
72 3 3 3 3 3 3
18 0 1 0 1 1 0
82 1 0 0 0 0 1
77 1 0 1 0 1 1
15 7 7 7 7 7 7
82 0 0 1 1 1 0
37 0 1 0 0 1 0
18 0 1 0 0 1 0
53 0 0 1 0 0 0
57 1 1 1 1 1 1
Run Code Online (Sandbox Code Playgroud)
subsetCols.txt逗号分隔,没有空格,一行,数字有序.在实际数据中,我们有500K列,需要~10K的子集.
1,4,6
Run Code Online (Sandbox Code Playgroud)
subsetRows.txt逗号分隔,没有空格,一行,数字有序.在实际数据中,我们有20K行,需要约为300的子集.
1,3,7
Run Code Online (Sandbox Code Playgroud)
使用cut和awk循环的当前解决方案(相关文章:使用awk选择行):
# define vars
fileInput=inputFile.txt
fileRows=subsetRows.txt
fileCols=subsetCols.txt
fileOutput=result.txt
# cut columns and awk rows
cut -f2- $fileInput | cut -f`cat $fileCols` | sed '1d' | awk -v s=`cat $fileRows` 'BEGIN{split(s, a, ","); for (i in a) b[a[i]]} NR in b' > $fileOutput
Run Code Online (Sandbox Code Playgroud)
输出文件:result.txt
1 4 6
3 3 3
7 7 7
Run Code Online (Sandbox Code Playgroud)
问题:
此解决方案适用于小文件,对于较大的文件50K行和200K列,它需要太长时间,15分钟加,仍在运行.我认为剪切列工作正常,选择行是慢点.
有更好的方法吗?
真实输入文件信息:
# $fileInput:
# Rows = 20127
# Cols = 533633
# Size = 31 GB
# $fileCols: 12000 comma separated col numbers
# $fileRows: 300 comma separated row numbers
Run Code Online (Sandbox Code Playgroud)
有关该文件的更多信息:文件包含GWAS基因型数据.每行代表样本(个体),每列代表SNP.对于进一步的基于区域的分析,我们需要对样本(行)和SNP(列)进行子集化,以使数据更易于管理(小)作为其他统计软件(如r)的输入.
系统:
$ uname -a
Linux nYYY-XXXX ZZZ Tue Dec 18 17:22:54 CST 2012 x86_64 x86_64 x86_64 GNU/Linux
Run Code Online (Sandbox Code Playgroud)
更新:@JamesBrown下面提供的解决方案是在我的系统中混合列的顺序,因为我使用的是不同版本的awk,我的版本是:GNU Awk 3.1.7
fed*_*qui 21
即使编程语言是国家,每种语言代表哪个国家?他们说...
Awk:朝鲜.固执地抵制变革,其用户似乎不自然地喜欢它,原因我们只能推测.
...每当你看到自己滚动sed,cut,grep,awk等时,停下来对自己说:awk可以让它独自一人!
因此,在这种情况下,需要提取行和列(调整它们以排除标题和第一列),然后缓冲输出以最终打印它.
awk -v cols="1 4 6" -v rows="1 3 7" '
BEGIN{
split(cols,c); for (i in c) col[c[i]] # extract cols to print
split(rows,r); for (i in r) row[r[i]] # extract rows to print
}
(NR-1 in row){
for (i=2;i<=NF;i++)
(i-1) in col && line=(line ? line OFS $i : $i); # pick columns
print line; line="" # print them
}' file
Run Code Online (Sandbox Code Playgroud)
使用您的示例文件:
$ awk -v cols="1 4 6" -v rows="1 3 7" 'BEGIN{split(cols,c); for (i in c) col[c[i]]; split(rows,r); for (i in r) row[r[i]]} (NR-1 in row){for (i=2;i<=NF;i++) (i-1) in col && line=(line ? line OFS $i : $i); print line; line=""}' file
1 4 6
3 3 3
7 7 7
Run Code Online (Sandbox Code Playgroud)
使用示例文件和输入作为变量,在逗号上拆分:
awk -v cols="$(<$fileCols)" -v rows="$(<$fileRows)" 'BEGIN{split(cols,c, /,/); for (i in c) col[c[i]]; split(rows,r, /,/); for (i in r) row[r[i]]} (NR-1 in row){for (i=2;i<=NF;i++) (i-1) in col && line=(line ? line OFS $i : $i); print line; line=""}' $fileInput
Run Code Online (Sandbox Code Playgroud)
我很确定这会更快.例如,您可以根据第二个文本文件检查从文本文件中删除重复项,以便比较awkover grep和其他项的性能.
最好的,
金正恩
一个在Gnu awk 4.0或更高版本中作为列排序依赖于for和 PROCINFO["sorted_in"].行和列号从文件中读取:
$ awk '
BEGIN {
PROCINFO["sorted_in"]="@ind_num_asc";
}
FILENAME==ARGV[1] { # process rows file
n=split($0,t,",");
for(i=1;i<=n;i++) r[t[i]]
}
FILENAME==ARGV[2] { # process cols file
m=split($0,t,",");
for(i=1;i<=m;i++) c[t[i]]
}
FILENAME==ARGV[3] && ((FNR-1) in r) { # process data file
for(i in c)
printf "%s%s", $(i+1), (++j%m?OFS:ORS)
}' subsetRows.txt subsetCols.txt inputFile.txt
1 4 6
3 3 3
7 7 7
Run Code Online (Sandbox Code Playgroud)
一些性能增益可能来自将ARGV[3]处理块移动到顶部的2和2并且添加next到它的结束.