One nearest neighbour using awk One nearest neighbour using awk shell shell

One nearest neighbour using awk


Here is one approach

$ 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

due to symmetry you just need to compare n*(n-1)/2 records, easier to set it up with join to prepare all matches and filter out the redundant ones $1<$8, finds the min column distance per record and record the match of the last fields $7==$14, to find the minimum distance for each record sort by first record number and distance, finally get the sum of the matched entries.

Here for your formulation I guess the result will be 100*2*7/10=140% since you're double counting (R1~R7 and R7~R1), otherwise 70%

UPDATE
With the new distance function, the script can be re-written as

$ 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%

Explanation

cat -n file > nfile create a new file with record numbers. join can't take both files from stdin, so you have to create a temporary file.

join nfile{,} -j999 cross product of records (each record will be joined with every record (similar effect of two nested loops)

$1<$8 will filter out the records to upper triangular section of the cross product (if you imagine it as a 2D matrix).

for(i=2;i<7;i++) d+=($i-$(i+7))^2; calculate the distance square of each record with respect to others

print $1,d,$7==$14 print from record, distance square, and indicator whether last fields match

sort -u -k1,2 -k3r find the min for each record, sort 3rd field reverse so that 1 will be first if there is any.

a[$1]++{sum+=$3;count++} count rows and sum the indicators for each from record

END{print 100*sum/(count+1)"%"} the number of fields is one more than from records, convert to percent formatting.

I suggest to understand what is going on run each piped section in stages and try to verify the intermediate results.

For your real data you have to change the hard coded reference values. Joined field should be more than your field count.