我有一个排序的 ID 和数字(位置)文件。我需要将第二列中的位置分组为一组 500 的间隔。
如果该行的值与上一行相比小于500,则将它们分组到同一组中;而如果该行的值超过 500,则将它们分组到不同的组中。
输入文件:
snp00001 200
snp00002 300
snp00003 400
snp00004 500
snp00005 600
snp00006 900
snp00007 1500
snp00008 1800
snp00009 3000
snp00010 3500
snp00011 4000
snp00012 5000
期望的输出
snp00001 200 Group1
snp00002 300 Group1
snp00003 400 Group1
snp00004 500 Group1
snp00005 600 Group1
snp00006 900 Group1
snp00007 1500 Group2
snp00008 1800 Group2
snp00009 3000 Group3
snp00010 3500 Group3
snp00011 4000 Group4
snp00012 5000 Group5
额外说明:snp00001 到 snp00006 将被归入同一组,因为它们之间的范围 (snp00002 - snp00001) 或 (snp00003 - snp00002) 或 (snp00004 - snp00003) ... 小于 500。
snp00006 和 snp00007 被分到下一组,因为它们之间的范围(snp00007 - snp00006)超过 500。
我试过用awk,但没有成功。
awk -v step=500 -v OFS='\t' '{if(NR==1 || $2+limit){group++} file="Group"group; print file,$0}' input_file
您需要跟踪以前的值并将当前值与保存的值进行比较。如果差值超过 500,则增加组数。
例如
(FWIW,您的 9/10/11 输出不一致;9->10 是 500 但不增加组,但 10->11 也是 500 但确实增加组)。
使用Raku(以前称为 Perl_6)
这是一个有些不同的分组方案,可能证明是有用的。它使用 Raku 的
~~
smartmatch 运算符快速判断一个位置是否在一个范围内(或不在):样本输入:
样本输出(从核苷酸 1 开始,每 500 个核苷酸对 SNP 进行分组):
上面的 Raku 代码声明了一个 Group# 迭代器和
$i
一个. 输入被视为,并且每一行被分成 (whitespace-delimited) 。运行 if/else 条件:第二列smartmatches 在范围、行、Group# 和范围内,取范围并edly 递增,而不是(即)智能匹配成功。然后打印与之前相同的信息,但这次使用正确递增的 Group# ( )。$r
1..500
lines
words
if
~~
$r
say
else
$r
repeat
500
until
~~
++$i
上述分组方案的优点是生成的组都具有相等的间隔长度,在这种情况下约为 500 个核苷酸。该方案防止组间隔长度的“膨胀”,这可能发生在多个 SNP 在某种程度上位于一起时(间隔“膨胀”可能会产生“聚类”的错误印象)。
为了使其成为更通用的“分组”工具,您可以将 Range 的右侧抽象为变量 (
$m
),以便快速分组:https://docs.raku.org/type/Range
https://raku.org