4

我有一个包含 2N 行的多列文件,它由 0s、1s 和缺失数据(编码为“?”)组成。它看起来像这样:

1 0 0 ? 1 ?
1 ? 1 ? 1 1
1 0 1 ? 1 1
0 ? 0 1 0 ?
0 0 1 ? 0 0
0 0 0 ? 0 ?
0 ? 0 0 1 1
1 1 1 1 1 1          

我想对每两行求和并输出一个 N 行文件。如果有“?” 连续然后输出应该是“?” 对于该特定字段 (?+0=?+1=?+? = ?)。因此,我的示例的输出将如下所示:

2 ? 1 ? 2 ?
1 ? 1 ? 1 ?
0 0 1 ? 0 ?
1 ? 1 1 2 2

我尝试了这段代码,但在计算时似乎将丢失的数据视为“0”。有没有办法将丢失的数据保留为“?” ?

cat <input_file> |awk -F ' ' '{if (NR%2==1){for(j=1;j<=NF;j++)array[j]=$j;}else{result="";for(i=1;i<=NF;i++){tmp=array[i]+$i;result=sprintf("%s%d ",result,tmp);}print result;}}' > <output_file>

请帮忙。任何建议将不胜感激!

4

3 回答 3

3

I'm afraid you will have to compare each field to "?":

< input_file  awk '
NR%2 { split($0,saved,FS) }      # save odd line fields
NR%2 == 0 {                      # on even lines:
  for(i=1; i<=NF; i++){
    $i = $i=="?"       ? "?" :   #  "?" if this line field is "?"
         saved[i]=="?" ? "?" :   #  "?" if the previous line field was "?"
         saved[i]+$i             #  the sum otherwise
  }
  print
}'
于 2012-09-20T22:48:43.523 回答
3

可以在一个(bash)shell中完成:

while read line; do 
    set -- $line
    read line
    ary=( $line )
    i=0
    for arg; do     
        if [ "$arg" = "?" -o "${ary[i]}" = "?" ]; then          
            printf "? "     
        else
            printf "%d " $(( $arg + ${ary[i]} ))     
        fi     
        ((i++)) 
    done 
    printf "\n"
done < file

使用 awk,我会写一些类似的东西

awk '{ 
    getline nextline
    split(nextline, ary)
    for (i=1; i<=NF; i++) {
        if ($i == "?" || ary[i] == "?")
            printf("? ")
        else
            printf("%d ", $i + ary[i])
    }
    print ""
}' file
于 2012-09-21T01:00:57.907 回答
1
> cat temp.awk
{
if(NR%2==1)
 {
  split($0,a," ");
 }
 else
 {
 line="";
 for(i=1;i<=NF;i++)
 {
  a[i]=="?"||$i=="?" ? sum="?":sum=a[i]+$i;
  line=line" "sum;
 }
 print line; 
 }
}

创建以上 awk 脚本后,使用以下命令:

awk -f temp.awk your_file

测试如下:

> awk -f temp.awk temp
 2 ? 1 ? 2 ?
 1 ? 1 ? 1 ?
 0 0 1 ? 0 ?
 1 ? 1 1 2 2
于 2012-09-25T07:04:02.743 回答