複数の行と列に基づいてグループ化

複数の行と列に基づいてグループ化

データの例を以下に示します。最初の2つの列はIDで、3番目の列は頻度です。

1 2 99
2 3 62
4 5 80
4 4 98
5 5 79
6 1 98

最初と2番目の列は、同一のIDまたは重複したIDです。たとえば、1、2、3、6は同じ人です。 1==2、2==3などなので、1==3です。したがって、データをこのように分割できます。

人1

1 2 99
2 3 62
6 1 98

人2

4 5 80
4 4 98
5 5 79

上記のようにデータをどのように分割できますか?ここでは、行全体を比較する必要があります。これは私にとって混乱した部分です。次に、各グループ内の3番目の列の頻度に基づいてIDを選択したいと思います。ここでは、他のファイルからこれらのIDを削除するために最も頻度の低い動物を取得します。推奨される最終出力は次のとおりです。

2 3 62
6 1 98
4 5 80
5 5 79 

私は答えを探していますが、私にとっては複雑に見えます。たぶん、データを分割するよりも良い方法があるかもしれません。どんなアイデアでもお願いします。

ベストアンサー1

最初の質問を解決するには、すべてのUnixシステムのbourne派生シェルでawk + ​​sortを使用して入力を分割する方法は次のとおりです(私はshebangでbashを使用しますが、bashである必要はありません)。

$ cat tst.sh
#!/usr/bin/env bash

awk '{ print $0 ORS $2, $1, $3 }' "${@:--}" |
sort -n -k1,1 -k2,2 |
awk '
    !seen[($1 > $2 ? $1 FS $2 : $2 FS $1)]++ {
        out = ""

        for ( i=1; i<=2; i++ ) {
            if ( $i in map ) {
                out = map[$i]
                break
            }
        }

        if ( out == "" ) {
            out = "person_" (++numPeople)
        }

        for ( i=1; i<=2; i++ ) {
            map[$i] = out
        }

        print >> out
        close(out)
    }
'

次の行を含むように公開した入力例を変更する必要があります。私のコメント分割が機能していることを実際にテストするには、次の手順を実行します。

$ cat file
1 2 99
2 3 62
4 5 80
4 4 98
5 5 79
6 1 98
7 8 99
9 10 98
9 7 97

$ ./tst.sh file

$ head person*
==> person_1 <==
1 2 99
1 6 98
2 3 62

==> person_2 <==
4 4 98
4 5 80
5 5 79

==> person_3 <==
7 8 99
7 9 97
9 10 98

1 2 x上記はと同じであるため、各行の最初の2つのIDの順序は重要ではないと仮定します2 1 x

おすすめ記事