列转数据矩阵 awk

列转数据矩阵 awk

我正在寻找一个awk从此表中获取的解决方案(第 1 列中有 x 个名称,第 2 列的长度不同,以“;”分隔):

数据框.txt:

name1 1;2;4;8
name2 4;5;7
name3 8
name4 11;12
namex 20;21

1到这个包含存在和不存在的矩阵0

矩阵.txt:

        1 2 4 5 7 8 11 12 20 21
name1   1 1 1 0 0 1 0  0  0  0 
name2   0 0 1 1 1 0 0  0  0  0
name3   0 0 0 0 0 1 0  0  0  0
name4   0 0 0 0 0 0 1  1  0  0
namex   0 0 0 0 0 0 0  0  1  1

答案1

Awk解决方案:

awk 'BEGIN{
         h = "1 2 3 4 5 6 7 8 11 12 20 21";
         len = split(h, head);
         print "\t\t" h
     }
     {
         printf "%s\t", $1;
         for (i = 1; i <= len; i++)
             printf "%s%d", (i == 1? "" : OFS), ($2 ~ "\\<" head[i] "\\>");
         print "" 
     }' file
  • h = "1 2 3 4 5 6 7 8 11 12 20 21"-标头线
  • len = split(h, head)- 将h行分割成数组head,其中索引是从起始位置开始的有序位置1,值是通过分割获得的关键值;len包含数组大小
  • print "\t\t" h- 打印标头带有前导制表符的行
  • printf "%s\t", $1;- 打印第一个字段$1
  • for (i = 1; i <= len; i++)- 迭代head项目
    • $2 ~ "\\<" head[i] "\\>"- 检查第二个字段是否$2包含当前访问的项目head[i]

输出:

        1 2 3 4 5 6 7 8 11 12 20 21
name1   1 1 0 1 0 0 0 1 0 0 0 0
name2   0 0 0 1 1 0 1 0 0 0 0 0
name3   0 0 0 0 0 0 0 1 0 0 0 0
name4   0 0 0 0 0 0 0 0 1 1 0 0
namex   0 0 0 0 0 0 0 0 0 0 1 1

答案2

另一种awk方法是先自行生成标头,然后用1对于数组中的每个键都head存在于当前输入行中,否则0如果不存在。

我们过去grep只获取与-o数字左边缘的空字符串匹配的数字(与我们在左侧和右侧使用的\b相同)。\<awk

awk 'NR==FNR { !head[$1]++; next } 
    { printf $1; for (x in head) { printf (x?FS:"") ($0 ~ "\\<" x "\\>") }; print ""
}' <(grep -o '\b[0-9]\+' infile) infile

输出是:

name1 1 1 1 0 0 1 0 0 0 0
name2 0 0 1 1 1 0 0 0 0 0
name3 0 0 0 0 0 1 0 0 0 0
name4 0 0 0 0 0 0 1 1 0 0
namex 0 0 0 0 0 0 0 0 1 1

您可以生成标题并插入输入文件的第一行,然后就很awk简单:

awk 'NR==1{ split($0, head); next }
    { printf $1; for (x in head){ printf (x?FS:"") ($2 ~ "\\<" head[x] "\\>" ) }; 
print "" }' infile

相关内容