我想转置一个如下所示的文件,其中第二列和每个列标题(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
代码,但没有运气。
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))
- 每个下一列的连接值(每列两个值)这个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))
假设输入数据以制表符分隔,这是使用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