Linux

用唯一標識符替換所有列中的每個唯一值

  • September 17, 2017

我有一個包含 250k 行和 10 列的文件,例如:

img1 aa bb cc ...
img2 aa yy dd ...
img3 uu bb ee ...
img4 NA bb tt ...

我想要一個腳本,將這個文件轉換為:

img1 1 1 1 ...
img2 1 2 2 ...
img3 2 1 3 ...
img4 0 1 4 ...

第一列之後每列的唯一值應替換為從 0 開始的唯一標識符,其中 0 為字元串“NA”保留。

此外,對於每一列,我想生成一個包含映射的文件。例如,第二列的文件應該是:

NA 0
aa 1
uu 2

誰能為此提出一個優雅的解決方案?任何幫助將不勝感激。

這是一個非常簡單的方法。對我來說很好,使用 gawk 3.1.7。

#!/usr/bin/awk -f
{
   for(x=2;x<=NF;x++) {
       if(x$x in a) {
           $x=a[x$x]
       } else {
           if($x=="NA") {
               print $x,0 > "column"x
               a[x$x]=0
               $x="0"
           } else {
               m[x]++
               print $x,m[x] > "column"x
               a[x$x]=m[x]
               $x=m[x]
           }
       }
   }
   print $0 > "results"
}
$ awk 'BEGIN { id["NA"] = ++n } { for (i=2; i<=NF; ++i) { id[$i] || id[$i] = ++n; $i = id[$i] - 1 } } { print } END { for (i in id) { print i, id[i] - 1 >"map" } }' file
img1 1 2 3
img2 1 4 5
img3 6 2 7
img4 0 2 8

img這會為除第一列( -column)之外的所有列中的每個值分配一個唯一 ID 。我選擇使 ID 全域唯一,而不是僅對列唯一,因為這將減少必須生成的所需映射文件的數量。

劇本解開:

BEGIN   { id["NA"] = ++n }

       {
           for (i=2; i<=NF; ++i) {
               id[$i] || id[$i] = ++n;
               $i = id[$i] - 1
           }
       }

       { print }

END     {
           for (i in id) {
               print i, id[i] - 1 >"map"
           }
       }

它首先為字元串分配NAID 1(在輸出之前,ID 始終減 1)並將計數器更新n為 1。 n將始終是分配給前一個字元串的 ID。

對於每個輸入行,我們遍歷欄位。如果沒有為目前欄位中的字元串分配 ID,我們分配一個並修改該欄位。

然後列印該行及其修改的欄位。

最後,所有字元串及其對應的 ID 都儲存在名為map.

對於給定的輸入,這個文件可能看起來像

bb 2
ee 7
cc 3
NA 0
tt 8
dd 5
yy 4
aa 1
uu 6

引用自:https://unix.stackexchange.com/questions/392682