awkを使用して他のファイルから最も近い値を見つける

awkを使用して他のファイルから最も近い値を見つける

2つのファイルがあります。

ファイル1:

123 pattern1   
452 pattern2
601 pattern3

ファイル2:

12  a
34  b
88  ee
120 f
333 qw
400 oo
566 i
993 o

私が望むのは、file2の最初の列でfile1の最初の列の各行に最も近い値を見つけて、file2の対応する2番目の列をfile1(新しいファイル内)に追加することです。

両方のファイルに重複した値はありません。

希望の出力:

123 pattern1    f   
452 pattern2    oo
601 pattern3    i

awkを使ってみましたが、うまくいきません。

awk 'NR==FNR { seq[$2]=$1; next }
{
    d = $1 - seq[$2];
    d = d < 0 ? -d : d;
    v = $1;
    next
}
{
    m = $1 - seq[$2];
    m = m < 0 ? -m : m
}
m < d {
    d = m;
    v = $1
}
{ print $0 }' file1.txt file2.txt

答え1

博多には指摘コードに問題があり、修正してください。私は代替答えを提供しています。

のみ使用してくださいawk。これは本質的に最初のファイルのデータを別の配列に分割しないことを除いて、Bodoの答えと同じです。また、表示された最小距離を初期化するために、魔法の数値定数(コード内の-1)を使用せずに、代わりにawk文字列として解釈されたときに設定されていない値が空であるという事実を使用します。

awk '
    NR == FNR { num[$0] = $1; next }
    {
        for (a in num) {
            d = (num[a]-$1)^2
            if (min[a] == "" || d < min[a]) {
                min[a] = d; symb[a] = $2
            }
        }
    } 
    END { for (a in symb) print a, symb[a] }' file1 file2

他の方法:

join -1 3 -2 3 file1 file2 |
awk '{ print ($1-$3)^2, $0 }' |
sort -k 1,1n | sort -su -k 2,3  |
awk '{ print $2, $3, $5 }'

上記は、最初にjoin存在しないフィールドを使用して、すべての入力データのリレーショナル交差積を生成します(あるファイルの各行を他のファイルのすべての行と結合します)。

データは次のとおりです。

 123 pattern1 12 a
 123 pattern1 34 b
[etc.]
 601 pattern3 566 i
 601 pattern3 993 o

次に距離測定を計算し、それを新しい最初の列に挿入します。

12321  123 pattern1 12 a
7921  123 pattern1 34 b
[etc.]
1225  601 pattern3 566 i
153664  601 pattern3 993 o

これら2つの呼び出しは、sort最初に距離測定に基づいてこのデータを数値的にソートし、次に最初のファイルのデータをソートキーとして使用して、安定した一意のソートを実行します。これにより、最初のファイルの最初のデータインスタンスを除くすべてのエントリが削除され、この場合は3行が残ります。

9  123 pattern1 120 f
2704  452 pattern2 400 oo
1225  601 pattern3 566 i

ここで興味のある列を選択してくださいawk

123 pattern1 f
452 pattern2 oo
601 pattern3 i

答え2

スクリプトにはいくつかの問題がありますawk。 2番目のワークブロックには条件がなく、で終わりますnext。これが他のブロックが決して実行されない理由です。

2番目のファイルのフィールド2をインデックスとして使用することは、seqフィールド2の値がfile1とfile2で異なるため意味がありません。

awk 'NR==FNR {
    seq[NR] = $1;
    name[NR] = $2;
    delta[NR] = -1;
    count = NR;
    next
}
{
    for(i = 1; i <= count; i++) {
       d = $1 - seq[i];
       d = d < 0 ? -d : d;
       if((delta[i] < 0) || (d < delta[i])) {
            delta[i] = d;
            val[i] = $2;
       }
    }
}
END {
    for(i = 1; i <= count; i++) {
       printf "%s %s\t%s\n", seq[i], name[i], val[i]
    }
}' file1.txt file2.txt

印刷

123 pattern1    f
452 pattern2    oo
601 pattern3    i

答え3

ファイルの順序を変更すると、もう少しコンパクトになります。

awk '
NR==FNR {A[$1]=$2; next}
{arg=1000
        for(i in A){
                cmp = sqrt(($1-i)^2)
                if(cmp < arg)
                        {arg=cmp; third=A[i]}
                }
        print $0, third}
' file2 file1

sqrt(X^2)絶対値の機能を実行する式の一部

関連情報