我有一个如下的文本文件:
1 2 3 4 5 6 7 8 9 ... n <-- column numbering
1 0 0 1 0 0 0 1 0 ... 0
0 1 0 0 0 0 0 0 0 ... 1
1 0 0 0 0 0 0 1 1 ... 0
0 1 1 1 0 1 0 0 0 ... 0
0 1 0 0 1 0 1 0 1 ... 1
实际上是一个非常稀疏的矩阵,其中二进制值。每行应该有多个 1,每列至少有一个 1。
我想要做的是找出哪些列中的 1 少于 2 个。例如,在上面的矩阵中,我想删除第 3、5、6 和 7 列,因为它们只有一个 1。
有没有 UNIX 命令可以做到这一点?可能我需要一个类似 Group by 的 (SQL) 命令,然后跟踪哪些列小于某个数字,但我不知道该怎么做。
答案1
您可以使用awk
以下脚本来遍历矩阵并计算 1 和 0 的数量:
计数工具:
NR != 1 {
for (i=1; i<=NF; ++i)
count[i] += $i;
}
END {
ORS = ",";
for (i=1; i<=length(count); ++i)
if (count[i] >= min)
print i
}
如果你使用以下方式执行此脚本
awk -v min=2 -f count.awk matrix.txt
您将得到一行包含两个或更多个 1 的列,在本例中为“1,2,4,8,9”(注意:您可以将其更改min=X
为您想要的任何最小阈值)。
现在,cut
仅打印出我们想要的列:
cols=$(awk -v min=2 -f count.awk matrix.txt); cut -d' ' -f${cols:0:-1} matrix.txt
这会将awk
输出存储在一个变量中(这样做的原因是awk
返回一个列表,列表,
末尾有一个额外的列。当我将列传递给时,我会将逗号“切掉” cut
。)
将 的分隔符设置为cut
“空格”(-d' '
),并将输出列设置为 的逗号分隔列表awk
,并将最后一个逗号切掉(-f${cols:0:-1}
)。
输出:
1 2 4 8 9 n
1 0 1 1 0 0
0 1 0 0 0 1
1 0 0 1 1 0
0 1 1 0 0 0
0 1 0 0 1 1
如果要输出少于min
1 的列(即第 3、5、6、7 列),只需将上述脚本if
中的语句条件反转即可。awk
if (count[i] < min)
输出:
3 5 6 7
0 0 0 0
0 0 0 0
0 0 0 0
1 0 1 0
0 1 0 1