2016-06-18 2 views
3

Это то, что я пытаюсь использовать с использованием языка AWK. У меня проблема с главным образом шагом 2. Я показал образец набора данных, но исходный набор данных состоит из 100 полей и 2000 записей.Один из ближайших соседей, использующий awk

Алгоритм

1) инициализирует точность = 0

2) для каждой записи г

 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) Получите 1% погрешность в процентах от (точность/total_records) * 100;

Образец Dataset

 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; 
} 
+0

Вы имеете в виду поля [i] = print $ i; и сохранить все поля в массиве? хотя поля независимы, но как только ближайшая строка будет найдена, мне нужно будет найти class_value, которое будет в поле [6]. Если я сортирую каждое поле отдельно, я перепутал данные. Можете ли вы объяснить немного больше о том, как продвигаться с идеей? –

+0

Вы включили комментарии в свое описание, так что теперь с вашими изменениями, каков фактический вопрос? То есть какая у вас сложность с шагом 2? – Soren

+0

Я не знаю, как применять формулу для каждого поля из двух записей (включая возведение в квадрат и сумму). этот бит неверен - >> distance [j] = (записи [i] - $ j); –

ответ

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 

из-за симметрии нужно просто сравнить п * (п-1)/2 записи, проще настроить его с помощью соединения, чтобы подготовить все совпадения и отфильтровать избыточные. $1<$8, находит минимальное расстояние в столбце за запись и записывает совпадение последних полей $7==$14, чтобы найти минимальное расстояние для каждой сортировки записей по первому номеру записи и расстоянию, наконец, получить сумму совпадающих записей.

Здесь для формулировки я думаю, результат будет 100*2*7/10=140%, так как вы двойной подсчет (R1 ~ R7 и R7 ~ R1), в противном случае 70%

UPDATE
С новой функцией расстояния, сценарий может быть повторно записана в виде

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

Объяснение

создайте новый файл с номерами записей. 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)"%"} количество полей больше, чем один из записей, конвертировать в процентах форматирования.

Я предлагаю понять, что происходит, запускать каждую секцию трубопровода поэтапно и пытаться проверить промежуточные результаты.

Для ваших реальных данных вам необходимо изменить значения жестко закодированных опорных значений. Поле ввода должно быть больше, чем ваш полевый счет.

+0

мой плохой, пожалуйста, не полагайтесь на набор данных, я создал свой собственный набор данных, поскольку фактический набор данных довольно огромен. dataset не будет симметрией. значения будут находиться где-то между 0.0 и 1.0, его минимальный макс нормализован. И я обновлю свой код, поскольку я думаю, что раньше делал неправильно. просто дай мне мин, я обновляю. и спасибо за ответ. –

+0

, независимо от значений, если R1 имеет минимальное расстояние до R7, он означает, что R7 имеет минимальное расстояние до R1. Поэтому вам нужно сравнивать записи только с другими записями с более высоким индексом. – karakfa

+0

Можете ли вы объяснить свой код и как его запустить? Я не понимаю соединение и функцию abs(). Я довольно новичок в AWK. Я получаю часть R1 min до R7, тогда наоборот. но допустим, у меня 2000 записей, тогда для записи = 10, мне нужно сравнить записи от 1 до 9, а затем от записи 11 до 2000. правильно? Но я не согласен с тем, что мне нужно искать только более высокие индексы. –

Смежные вопросы