【问题标题】:One nearest neighbour using awk使用 awk 的最近邻
【发布时间】:2016-10-20 05:04:53
【问题描述】:

这就是我正在尝试使用 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 的准确率百分比 (准确度/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;
}

【问题讨论】:

  • 你的意思是,fields[i] = print $i;并将所有字段存储在一个数组中?尽管字段是独立的,但是一旦找到最近的行,我将需要找到将在字段 [6] 中的 class_value。如果我分别对每个字段进行排序,我就会混淆数据。你能解释一下如何实现你的想法吗?
  • 您在描述中加入了 cmets,所以现在通过您的编辑,实际问题是什么? IE。第 2 步有什么困难?
  • 我不知道如何为两条记录的每个字段应用公式(包括平方和求和)。这一点是错误的 ->> distance[j] = (records[i] - $j);

标签: bash shell awk text-processing gawk


【解决方案1】:

这是一种方法

$ 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 条记录,更容易通过 join 设置它以准备所有匹配项并过滤掉多余的匹配项$1&lt;$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 &gt; nfile 用记录号创建一个新文件。 join 不能从标准输入中获取两个文件,所以你必须创建一个临时文件。

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

$1&lt;$8 会将记录过滤到叉积的上三角部分(如果您将其想象为二维矩阵)。

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

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

sort -u -k1,2 -k3r 求每条记录的最小值,倒序排列第三个字段,如果有的话,1 会排在第一位。

a[$1]++{sum+=$3;count++} 计算行数并对每条记录的指标求和

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

我建议分阶段运行每个管道部分并尝试验证中间结果。

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

【讨论】:

  • 我的错,请不要依赖数据集,我自己制作数据集,因为实际数据集非常庞大。数据集不会是对称的。这些值将在 0.0 到 1.0 之间的任何地方,其最小值-最大值归一化。我会更新我的代码,因为我认为我之前做错了。给我一分钟,我正在更新。并感谢您的回复。
  • 无论 R1 到 R7 的距离如何,这意味着 R7 到 R1 的距离是最小的。因此,您只需将记录与索引较高的其他记录进行比较。
  • 您能解释一下您的代码以及如何运行它吗?我不明白 join 和 abs() 函数。我对AWK相当陌生。我得到 R1 到 R7 的最小距离,反之亦然。但是让我们假设,我有 2000 条记录,然后记录 = 10,我必须比较从 1 到 9 的记录,然后从记录 11 到 2000。对吗?但我不同意我只需要寻找更高的索引。
  • 好吧,你改变了 dist 计算,所以我必须重写。请注意,对于平方和,您不需要绝对值。
  • 例如,假设您有 3 条记录,您需要评估多少次比较?叉积会给你 3x3=9,其中包含冗余,你不需要自己比较记录,所以删除 3,同样由于对称你需要剩下的一半,即 3*2/2 = 3。获取过滤列表的最佳方法是什么?您希望比较索引为 1~2、1~3 和 2~3 的记录。这是条件(第一个索引)
猜你喜欢
  • 2011-12-06
  • 1970-01-01
  • 2011-06-22
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-08
  • 2019-01-03
相关资源
最近更新 更多