按行号和列号子集文件

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)

使用cutawk循环的当前解决方案(相关文章:使用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(列)进行子集化,以使数据更易于管理(小)作为其他统计软件(如)的输入.

系统:

$ 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和其他项的性能.

最好的,
金正恩


Jam*_*own 6

一个在Gnu awk 4.0或更高版本中作为列排序依赖于forPROCINFO["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到它的结束.

  • @JamesBrown好一个!然后+1,干得好!这必须比我的解决方案更快,因为它不会通过所有列检查它们是否必须打印; 相反,它只是拿起它们. (2认同)
  • 顺便说一句,James:不应该``PROCINFO ["sorted_in"] ="@ ind_num_asc";`设置在`BEGIN`块中?我很好奇,如果在阅读第一个文件时设置它可能会影响其他文件. (2认同)
  • 显然,该功能仅在更高版本中可用,在某处提到了4.0. (2认同)