AWKを使って簡単にデータ変換

AWKを使って簡単にデータ変換

この形式のデータがあります;-

Type,Fac1,Fac2,Fac3
1,0.1,0.1,0.1
2,0.2,0.2,0.2
3,0.3,0.3,0.3

AWKを使用してデータを次のように変換する必要があります。

Type
1,Fac1,0.1
1,Fac2,0.1
1,Fac3,0.1
2,Fac1,0.2
2,Fac2,0.2
2,Fac3,0.2
3,Fac1,0.3
3,Fac2,0.3
3,Fac3,0.3

つまり、水平方向から垂直方向に変化する「ピボット」動作です。

だから私はこれを試しました:

awk -F ',' '{for (i=2;i<=NF;i++) { if (i==2) {print $1"," $i } else print $1"," $i}}'

答え1

$ cat tst.awk
BEGIN { FS=OFS="," }
NR==1 {
    print $1
    split($0,tags)
    next
}
{
    for (i=2; i<=NF; i++) {
        print $1, tags[i], $i
    }
}

$ awk -f tst.awk file
Type
1,Fac1,0.1
1,Fac2,0.1
1,Fac3,0.1
2,Fac1,0.2
2,Fac2,0.2
2,Fac3,0.2
3,Fac1,0.3
3,Fac2,0.3
3,Fac3,0.3

答え2

perlカンマで行を区切ります。

perl -sF, -lane '
  $.==1 && do{
    print shift @F;
    @h = @F; next;
  };
  my $i;
  print $F[0], splice(@F,1,1), $h[$i++] while @F > 1;
' -- -,=, file

出力:-

Type
1,0.1,Fac1
1,0.1,Fac2
1,0.1,Fac3
2,0.2,Fac1
2,0.2,Fac2
2,0.2,Fac3
3,0.3,Fac1
3,0.3,Fac2
3,0.3,Fac3

itertoolsモジュールでPythonとリストを理解する

python3 -c 'import itertools as it, sys
ifile = sys.argv[1]
fs,rs = ",","\n"
ofs,ors = fs,rs
with open(ifile) as f:
  for nr,l in enumerate(f,1):
    L = l.rstrip(rs).split(fs)
    if nr == 1:
      print(L.pop(0))
      H = L
    else:
      print(*[ofs.join([a,*b])
      for a,b in zip(it.repeat(L.pop(0)),zip(L,H))],sep=ors)
' file

拡張正規表現モードのGNU sed:-

sed -Ee '
  1{
    s/,/\n/;P
    s/.*\n//
    h;d
  }
  /\n/!G
  s/,/&\n/2
  s/^(([^,]*,).*)\n(.*\n)([^,]*),/\1\4\n\2\3/
  /\n.*\n/!s/\n/,/
  P;D
' file

関連情報