我有一个由单个单元1s,2s和3s组成的多列文件。每列中有很多重复的单元,有时它会从一个单元切换到另一个单元。我想计算每一列发生这种切换的次数。例如,在第1列中,开关从1变为2到3变为1,因此有3个开关,输出应为3.在第二列中,整个列有2个,因此更改为0,输出为0 。
我的输入文件有4000列,因此无法手动完成。该文件是空格分隔的。
例如:
输入:
1 2 3 1 2
1 2 2 1 3
1 2 3 1 2
2 2 2 1 2
2 2 2 1 2 ......
3 2 2 1 2
3 2 2 1 1
1 2 2 1 1
1 2 2 1 2
1 2 2 1 1
期望的输出:
3 ## column 1 switch times
0 ## column 2 switch times
3 .....
0
5
我正在使用:
awk '{print $1}' <inputfile> | uniq | wc -l
awk '{print $2}' <inputfile> | uniq | wc -l
awk '{print $3}' <inputfile> | uniq | wc -l
....
一次执行一列。它将给出第一列的输出“4”,稍后我将计算4-1 = 3以获得我想要的输出。但有没有办法可以将这个awk命令写入循环并在每个列上执行并输出到一个文件?
谢谢!
答案 0 :(得分:3)
awk
告诉您变量NF中给定行中有多少个字段,因此您可以创建两个数组来跟踪所需的信息。一个数组将保留给定列中最后一行的值。另一个将计算给定列中的开关数。您还将跟踪最大列数(并将新列的计数设置为零,以便在该列的开关数为0时在末尾的输出中正确打印它们)。您还将确保不计算从空字符串到非空字符串的转换 - 这是在第一次遇到列时发生的。
实际上,如果文件的列数统一相同,那么只会影响第一行数据。如果后续行实际上有比第一行更多的列,则会添加它们。如果列停止出现一点,我认为它应该从它停止的地方恢复(好像缺失的列与之前的值相同)。您可以决定不同的算法;这可能算作两个转换(从数字到空白,从空白到数字也是如此。如果是这种情况,你必须修改计数代码。或者,更明智的是,你可以决定不允许不规则数量的列,在这种情况下,如果当前行中的列数与上一行中的列数不同,您可以提前纾困(当心空行,或者它们也是非法的?)。
你不会尝试将整个程序写在一行上,因为它是不可理解的,而且实际上没有必要。
awk '{ if (NF > maxNF)
{
for (i = maxNF + 1; i <= NF; i++)
count[i] = 0;
maxNF = NF;
}
for (i = 1; i <= NF; i++)
{
if (col[i] != "" && $i != col[i])
count[i]++;
col[i] = $i;
}
}
END {
for (i = 1; i <= maxNF; i++)
print count[i];
}' data-file-with-4000-columns
根据您的样本数据(删除了点),脚本的输出符合要求:
3
0
3
0
5
这个带有锯齿状行的替代数据文件:
1 2 3 1 2
1 2 2 1 3
1 2 3 1 2
2 2 2 1 2
2 2 2 1 2 1 1 1
3 2 2 1 2 2 1
3 2 2 1 1
1 2 2 1 1 2 2 1
1 2 2 1
1 2 2 1 1 3
产生输出:
3
0
3
0
3
2
1
0
根据我制定的规则,这是正确的 - 但如果你决定要不同的规则来覆盖数据,你可能会得到不同的答案。
如果在最后一个循环中使用printf("%d\n", count[i]);
,则不需要在循环中将计数值设置为零。你付钱并拿走你的选择。
答案 1 :(得分:2)
使用循环并为每个列当前值保留一个数组,并为相应的计数保留另一个数组:
awk '{for(i=0;i<5;i++) if(c[i]!=$(i+1)) {c[i]=$(i+1); t[i]++}} END{for(i=0;i<5;i++)print t[i]-1}' filename
请注意,这假设列的值不为零。如果您碰巧有零值,那么只需将数组c
初始化为某个唯一值,该值将不会出现在文件中。
答案 2 :(得分:0)
为了便于查看而编写代码,SaveColx,CountColx应该是数组。我会在结果中打印列号本身至少用于检查: - )
BEGIN {
SaveCol1 = " "
CountCol1 = 0
CountCol2 = 0
CountCol3 = 0
CountCol4 = 0
CountCol5 = 0
}
{
if ( SaveCol1 == " " ) {
SaveCol1 = $1
SaveCol2 = $2
SaveCol3 = $3
SaveCol4 = $4
SaveCol5 = $5
next
}
if ( $1 != SaveCol1 ) {
CountCol1++
SaveCol1 = $1
}
if ( $2 != SaveCol2 ) {
CountCol2++
SaveCol2 = $2
}
if ( $3 != SaveCol3 ) {
CountCol3++
SaveCol3 = $3
}
if ( $4 != SaveCol4 ) {
CountCol4++
SaveCol4 = $4
}
if ( $5 != SaveCol5 ) {
CountCol5++
SaveCol5 = $5
}
}
END {
print CountCol1
print CountCol2
print CountCol3
print CountCol4
print CountCol5
}