一个最近的邻居使用awk

时间:2016-06-18 12:49:13

标签: bash shell awk text-processing gawk

这是我尝试使用AWK语言做的事情。我主要遇到第2步的问题。我已经展示了一个样本数据集,但原始数据集包含100个字段和2000个记录。

算法

1)初始化准确度= 0

2)对于每条记录r

     Find the closest other record, o, in the dataset using distance formula

要找到r0的最近邻居,我需要将r0与r1和r9进行比较并按如下方式进行数学运算: square(abs(r0.c1 - r1.c1))+ square(abs(r0.c2) - r1.c2))+ ... + square(abs(r0.c5 - r1.c5)) 并存储这些距离。

3)一个最小距离,比较其c6值。如果c6值相等,则将精度增加1。

重复所有记录的过程后。

4)最后,获得1nn的准确率百分比 (precision / total_records)* 100;

示例数据集

        c1   c2   c3   c4   c5   c6  --> Columns
  r0  0.19 0.33 0.02 0.90 0.12 0.17  --> row1 & row7 nearest neighbour in c1
  r1  0.34 0.47 0.29 0.32 0.20 1.00      and same values in c6(0.3) so ++accuracy
  r2  0.37 0.72 0.34 0.60 0.29 0.15 
  r3  0.43 0.39 0.40 0.39 0.32 0.27 
  r4  0.27 0.41 0.08 0.19 0.10 0.18 
  r5  0.48 0.27 0.68 0.23 0.41 0.25 
  r6  0.52 0.68 0.40 0.75 0.75 0.35 
  r7  0.55 0.59 0.61 0.56 0.74 0.76 
  r8  0.04 0.14 0.03 0.24 0.27 0.37 
  r9  0.39 0.07 0.07 0.08 0.08 0.89

代码

BEGIN   {
            #initialize accuracy and total_records
            accuracy = 0;
            total_records = 10;
        }


NR==FNR {    # Loop through each record and store it in an array
                for (i=1; i<=NF; i++) 
                {
                     records[i]=$i;
                }
            next             
        }

        {   # Re-Loop through the file and compare each record from the array with each record in a file    
              for(i=1; i <= length(records); i++)
              {
                   for (j=1; j<=NF; j++) 
                   {      # here I need to get the difference of each field of the record[i] with each all the records, square them and sum it up. 
                          distance[j] = (records[i] - $j)^2;
                   }
               #Once I have all the distance, I can simply compare the values of field_6 for the record with least distance.
              if(min(distance[j]))
              {
                  if(records[$6] == $6)
                  {
                        ++accuracy;
                  } 
              }
       }
END{
     percentage = 100 * (accuracy/total_records); 
     print percentage;
}

1 个答案:

答案 0 :(得分:0)

这是一种方法

$ cat -n file > nfile
$ join nfile{,} -j99 | 
  awk 'function abs(x) {return x>0?x:-x}  
           $1<$8 {minc=999;for(i=2;i<7;i++) 
                 {d=abs($i-$(i+7)); 
                  if(d<minc)minc=d} 
                  print $1,minc,$7==$14}' | 
  sort -u -k1,2 -k3r | 
  awk '!a[$1]++{sum+=$3} END{print sum}'

7

由于对称性,你只需要比较n *(n-1)/ 2条记录,更容易设置连接以准备所有匹配并过滤掉冗余的$1<$8,找到最小列距离每条记录并记录最后一个字段$7==$14的匹配,找到每个记录按第一个记录号和距离排序的最小距离,最后得到匹配条目的总和。

这里为您的配方我想结果将是100*2*7/10=140%,因为您需要重复计算(R1~R7和R7~R1),否则70%

<强>更新
使用新的距离函数,脚本可以重写为

$ join nfile{,} -j999 | 
  awk '$1<$8 {d=0; 
              for(i=2;i<7;i++) d+=($i-$(i+7))^2; 
              print $1,d,$7==$14}' | 
  sort -k1,2n -k3r | 
  awk '!a[$1]++{sum+=$3;count++} 
            END{print 100*sum/(count+1)"%"}'

70%

<强>解释

cat -n file > nfile创建一个包含记录号的新文件。 join无法从stdin中获取这两个文件,因此您必须创建一个临时文件。

join nfile{,} -j999记录的交叉产品(每条记录将与每条记录连接(两个嵌套循环的类似效果)

$1<$8会将记录过滤到十字产品的上三角形部分(如果您将其想象为2D矩阵)。

for(i=2;i<7;i++) d+=($i-$(i+7))^2;计算每条记录相对于其他记录的距离

print $1,d,$7==$14从记录,距离方格打印,并指示最后一个字段是否匹配

sort -u -k1,2 -k3r找到每条记录的分钟数,将第3个字段反向排序,这样1如果有的话,它将是第一个。

a[$1]++{sum+=$3;count++}计算行数并将每个记录的指标加起来

END{print 100*sum/(count+1)"%"}字段数比记录多一个,转换为格式化百分比。

我建议了解每个管道部分分阶段运行的情况,并尝试验证中间结果。

对于您的真实数据,您必须更改硬编码参考值。加入的字段应该大于您的字段数。