转置表

问题描述 投票:2回答:3

我想转置一个如下所示的文件,其中第二列和每个列标题(B4,B3,E0)可以取两个值。我希望B4 B3 ...的所有值都在一行中。这意味着B4 B3 E0将是单独的行。

如何用例如awk sed或python。我可以在python中做简单的转置,但我不明白如何解决这个特殊的问题。

输入:第2列和第3列具有相同的列名,即B4,类似地,第4列和第5列具有相同的列名,即B3,依此类推。当我们转置两个对应于B4的值时,应该像12 13 13 14 13 13 12 13 13 13 12 13一样转换为单位。它应该在一条线上。输入文件包含20多列和2000行。

输入:

ID  B4    B3    
 1  12  13  19  21  
 2  13  14  19  21  
 3  13  13  19  21  
 4  12  13  19  19  
 5  13  13  18  19  
 6  12  13  19  21

期望的输出:

ID 1 1 2 2 3 3 4 4 5 5 6 6
B4 12  13 13  14 13  13 12  13 13  13 12  13
B3 19  21 19  21 19  21 19  19 18  19 19  21

这是我尝试过的:

python -c "import sys; print('\n'.join(' '.join(c) for c in zip(*(l.split() for l in sys.stdin.readlines() if l.strip()))))" < input file>output file 

还尝试了awk代码,但没有运气。

python unix awk sed
3个回答
3
投票

awk解决方案:

awk 'NR==1{ for (i=1; i<=NF; i++) col[i]=$i }
     NR>1{ 
         col[1]=sprintf("%s %s %s",col[1],$1,$1); j=1; 
         for (i=2; i<=NF; i+=2) {
             j++; col[j]=sprintf("%s %s %s",col[j],$i,$(i+1)) 
         }
     }
     END { len=length(col); for (i=1; i<=len; i++) print col[i] }' input

输出:

ID 1 1 2 2 3 3 4 4 5 5 6 6
B4 12 13 13 14 13 13 12 13 13 13 12 13
B3 19 21 19 21 19 21 19 19 18 19 19 21

  • NR==1{ for(i=1;i<=NF;i++) col[i]=$i } - 在第1行累积列名
  • col[1]=sprintf("%s %s %s",col[1],$1,$1) - 连接第一个ID列的值
  • j++; col[j]=sprintf("%s %s %s",col[j],$i,$(i+1)) - 每个下一列的连接值(每列两个值)

1
投票

这个python代码解决了你的问题

import sys

header = sys.stdin.readline().strip().split()
transposed = [[item] for item in header]

for line in sys.stdin.readlines():
    items = line.strip().split()
    transposed[0].append(items[0])
    for i in range(1, len(transposed)):
        transposed[i].extend(items[2*i - 1: 2*i + 1])

for line in transposed:
    print(" ".join(line))

0
投票

假设输入数据以制表符分隔,这是使用coreutils和datamash的一种方法:

# Name of the input file
infile=input
(
  # Grab header
  head -n1 $infile

  # Combine columns without the header, 1. duplicate every line, 
  # 2. and 3. zip columns together
  paste <(tail -n+2 $infile | cut -f 1   | sed 'h; G')     \
        <(tail -n+2 $infile | cut -f 2,3 | sed 's/\t/\n/') \
        <(tail -n+2 $infile | cut -f 4,5 | sed 's/\t/\n/')
) | datamash transpose

输出:

ID  1   1   2   2   3   3   4   4   5   5   6   6
B4  12  13  13  14  13  13  12  13  13  13  12  13
B3  19  21  19  21  19  21  19  19  18  19  19  21

如果输入不是以制表符分隔的,您可以使用sed来实现:

sed 's/^ *\| *$//g; s/ \+/\t/g' infile > outfile
© www.soinside.com 2019 - 2024. All rights reserved.