当第 2 列、第 3 列和第 1 列中的连续单元格相同时,我尝试计算第 9 列中C_R
和的数量。S_R
该文件采用床格式(制表符分隔格式)。原始文件很大,第一列定义了染色体编号。文件的前几行看起来像这样,
chr1 10200 10300 8 10000 10214 100 214 S_R
chr1 10200 10300 8 10009 10233 100 224 S_R
chr1 10200 10300 8 10014 10220 100 206 S_R
chr1 10200 10300 8 10045 10215 100 170 S_R
chr1 10200 10300 8 10068 10209 100 141 S_R
chr1 10200 10300 8 10074 10300 100 226 C_R
chr1 10200 10300 8 10182 10283 100 101 S_R
chr1 10200 10300 8 10182 10387 100 205 C_R
chr1 10300 10400 4 10182 10387 100 205 S_R
chr1 10300 10400 4 10331 10467 100 136 S_R
chr1 10300 10400 4 10346 10461 100 115 S_R
chr1 10300 10400 4 10352 10468 100 116 S_R
chr1 10400 10500 3 10331 10467 100 136 S_R
chr1 10400 10500 3 10346 10461 100 115 S_R
chr1 10400 10500 3 10352 10468 100 116 S_R
chr1 11000 11100 2 11024 11163 100 139 S_R
chr1 11000 11100 2 11024 11188 100 164 S_R
chr1 11100 11200 3 11024 11163 100 139 S_R
chr1 11100 11200 3 11024 11188 100 164 S_R
chr1 11100 11200 3 11127 11296 100 169 S_R
chr1 11200 11300 1 11127 11296 100 169 S_R
chr1 11400 11500 2 11412 11561 100 149 S_R
chr1 11400 11500 2 11457 11608 100 151 S_R
chr1 11500 11600 3 11412 11561 100 149 S_R
chr1 11500 11600 3 11457 11608 100 151 C_R
chr1 11500 11600 3 11574 11744 100 170 S_R
chr1 11600 11700 3 11457 11608 100 151 S_R
chr1 11600 11700 3 11574 11744 100 170 C_R
chr1 11600 11700 3 11640 11815 100 175 S_R
chr1 11700 11800 4 11574 11744 100 170 S_R
chr1 11700 11800 4 11640 11815 100 175 C_R
chr1 11700 11800 4 11784 11963 100 179 S_R
chr1 11700 11800 4 11791 11936 100 145 S_R
在上表的前 8 行中,第 1、2、3 列相同,因此暂定输出文件如下所示
chr1 10200 10300 2 6
chr1 10300 10400 0 4
chr1 10400 10500 0 3
chr1 11000 11100 0 2
chr1 11100 11200 0 3
chr1 11200 11300 0 1
chr1 11400 11500 0 2
chr1 11500 11600 1 2
chr1 11600 11700 1 2
chr1 11700 11800 1 3
在输出文件中,第 4 列C_R
和第 5 列是S_R
答案1
awk
这可以通过以下方式完成:
awk 'function report() {
if (n) print last_key, 0+count["C_R"], 0+count["S_R"]
}
{key = $1 OFS $2 OFS $3}
key != last_key {report(); n = 0; split("", count); last_key = key}
{count[$9]++; n++}
END {report()}' <your-file
如果输入字段是用制表符分隔的,您可能需要添加-F '\t' -v OFS='\t'
以指定输入和输出文件分隔符。默认情况下FS
(由 设置的输入字段分隔符-F
)是一个空格字符,它具有特殊含义:任何空格序列分隔字段以及前导和尾随空格都将被丢弃,或者 IOW 字段是非空白字符序列,因此不能任何空白字段; andOFS
也是一个空格,简单的意思是输出上的字段用一个空格分隔。
答案2
这是 GNU awk
(大多数 Linux 系统上的gawk
默认设置)方法。awk
请注意,我假设此处的列是制表符分隔的,但由于这看起来像 bed 文件或 bedpe 文件,两者都需要制表符,因此我有理由确定这是正确的。
$ gawk -F'\t' -v OFS='\t' -v type1="C_R" -v type2="S_R" '
{
a[$1 OFS $2 OFS $3][$NF]++;
}
END{
for (i in a){
print i,0+a[i][type1],0+a[i][type2]
}
}' file.bed
chr1 11200 11300 0 1
chr1 11700 11800 1 3
chr1 10300 10400 0 4
chr1 11000 11100 0 2
chr1 10400 10500 0 3
chr1 11500 11600 1 2
chr1 11400 11500 0 2
chr1 11100 11200 0 3
chr1 11600 11700 1 2
chr1 10200 10300 2 6
解释
-F'\t'
将输入字段分隔符设置为制表符,并将-v OFS='\t'
输出字段分隔符设置为制表符。接下来,我们设置另外两个变量type1
adtype2
以在脚本中使用。
脚本的主体只是a[$1 OFS $2 OFS $3][$NF]++;
。这使用由输出字段分隔符(在我们的例子中是制表符)分隔的前三个字段OFS
作为二维数组的第一个键a
。第二个键是最后一个字段 ( $NF
),我们只需将值加一。因此,a
数组会计算每个字符、开始位置和结束位置与每个可能的最后字段一起找到的次数。
完成后,在END{ }
块中,我们迭代数组的所有键a
(字符、开始和结束位置),然后打印出两个可能的最后一个字段中的每一个,type1
以及type2
字符、开始和结束位置( 的值i
),然后是每个可能的最后一个字段与前三个字段一起出现的次数 ( 0+a[i][type1],0+a[i][type2]
)。我们需要0+
那里,这样如果在这些字符、开始和结束位置上没有看到特定的最后一个字段,我们将得到 a0
而不是空字段或错误。
答案3
使用 TSV 感知实用程序 Miller ( mlr
) 将输入读取为无标头 TSV 文件,仅挑选出必要的列(使用cut
),将第 9 列的值收集/折叠到;
每个列组合的 - 分隔列表中1、2 和 3(使用),然后计算为每个剩余记录收集的和字符串nest
的数量(使用表达式)。第 9 列中折叠的值最终被删除(带有)。C_R
S_R
put
cut -x
mlr --from=file --tsv -N \
cut -f 1,2,3,9 then \
nest --ivar ';' -f 9 then \
put '
a = splita($9,";");
for (k in ["C_R","S_R"]) {
$[k] = count(select(a, func(e) { return e == k }))
}' then \
cut -x -f 9
给定问题中的数据,这将生成以下制表符分隔的输出:
chr1 10200 10300 2 6
chr1 10300 10400 0 4
chr1 10400 10500 0 3
chr1 11000 11100 0 2
chr1 11100 11200 0 3
chr1 11200 11300 0 1
chr1 11400 11500 0 2
chr1 11500 11600 1 2
chr1 11600 11700 1 2
chr1 11700 11800 1 3
答案4
使用乐(以前称为 Perl_6)
~$ raku -e 'my @a = lines.map: *.split(/\s+/); \
my %hash.push: [Z=>] @a.map(*.[0..2]), @a.map(*.[*-1]); \
put join "\t", .key, (.value.map: * eq "C_R")>>.Int.sum, \
(.value.map: * eq "S_R")>>.Int.sum for %hash.sort;' file
这是用 Raku(Perl 编程语言家族的成员)编写的答案。上面lines
是在空白处map
插入的。split
结果保存到@a
数组中。%hash
声明A ,并[Z=>]
使用 Raku 的归约元运算符将push
键/值对添加到其上,.[0..2]
前三列为钥匙最后一.[*-1]
列为价值。在最后一个语句中,value
检查 seq
与C_R
和的字符串是否有效S_R
;每个布尔结果都转换为Int
、sum
med 和 output
作为列。
输入示例:
chr1 10200 10300 8 10000 10214 100 214 S_R
chr1 10200 10300 8 10009 10233 100 224 S_R
chr1 10200 10300 8 10014 10220 100 206 S_R
chr1 10200 10300 8 10045 10215 100 170 S_R
chr1 10200 10300 8 10068 10209 100 141 S_R
chr1 10200 10300 8 10074 10300 100 226 C_R
chr1 10200 10300 8 10182 10283 100 101 S_R
chr1 10200 10300 8 10182 10387 100 205 C_R
chr1 10300 10400 4 10182 10387 100 205 S_R
chr1 10300 10400 4 10331 10467 100 136 S_R
chr1 10300 10400 4 10346 10461 100 115 S_R
chr1 10300 10400 4 10352 10468 100 116 S_R
chr1 10400 10500 3 10331 10467 100 136 S_R
chr1 10400 10500 3 10346 10461 100 115 S_R
chr1 10400 10500 3 10352 10468 100 116 S_R
chr1 11000 11100 2 11024 11163 100 139 S_R
chr1 11000 11100 2 11024 11188 100 164 S_R
chr1 11100 11200 3 11024 11163 100 139 S_R
chr1 11100 11200 3 11024 11188 100 164 S_R
chr1 11100 11200 3 11127 11296 100 169 S_R
chr1 11200 11300 1 11127 11296 100 169 S_R
chr1 11400 11500 2 11412 11561 100 149 S_R
chr1 11400 11500 2 11457 11608 100 151 S_R
chr1 11500 11600 3 11412 11561 100 149 S_R
chr1 11500 11600 3 11457 11608 100 151 C_R
chr1 11500 11600 3 11574 11744 100 170 S_R
chr1 11600 11700 3 11457 11608 100 151 S_R
chr1 11600 11700 3 11574 11744 100 170 C_R
chr1 11600 11700 3 11640 11815 100 175 S_R
chr1 11700 11800 4 11574 11744 100 170 S_R
chr1 11700 11800 4 11640 11815 100 175 C_R
chr1 11700 11800 4 11784 11963 100 179 S_R
chr1 11700 11800 4 11791 11936 100 145 S_R
示例输出:
chr1 10200 10300 2 6
chr1 10300 10400 0 4
chr1 10400 10500 0 3
chr1 11000 11100 0 2
chr1 11100 11200 0 3
chr1 11200 11300 0 1
chr1 11400 11500 0 2
chr1 11500 11600 1 2
chr1 11600 11700 1 2
chr1 11700 11800 1 3
[在最后一个put
语句中,如果您希望所有列都以制表符分隔,则替换.key
为]。.key.split(" ").join("\t")
请注意,查看中间步骤通常非常有启发性,因此这是 Raku 在.raku
最终 2 列sum
挖掘之前的数据 ( ) 内部表示:
~$ raku -e 'my @a = lines.map: *.split(/\s+/); my %hash.push: [Z=>] @a.map(*.[0..2]), @a.map(*.[*-1]); .raku.say for %hash.sort;' file
"chr1 10200 10300" => $["S_R", "S_R", "S_R", "S_R", "S_R", "C_R", "S_R", "C_R"]
"chr1 10300 10400" => $["S_R", "S_R", "S_R", "S_R"]
"chr1 10400 10500" => $["S_R", "S_R", "S_R"]
"chr1 11000 11100" => $["S_R", "S_R"]
"chr1 11100 11200" => $["S_R", "S_R", "S_R"]
"chr1 11200 11300" => "S_R"
"chr1 11400 11500" => $["S_R", "S_R"]
"chr1 11500 11600" => $["S_R", "C_R", "S_R"]
"chr1 11600 11700" => $["S_R", "C_R", "S_R"]
"chr1 11700 11800" => $["S_R", "C_R", "S_R", "S_R"]