我拥有的许多数据文件的较小版本如下所示:
0 0 0
0.05 9.6877884e-06 0.0024898597
0.1 4.2838688e-05 0.0049595502
0.15 0.00016929444 0.0074092494
0.2 0.00036426881 0.009839138
0.25 0.00055234582 0.012249394
0.3 0.00077448576 0.014640196
0.35 0.00082546537 0.017011717
0.4 0.0012371619 0.019364133
0.45 0.0013286382 0.02169761
我希望得到类似以下内容的结果,其中第一列重复,第二列的条目包含原始文件中的第 2 列及以上列。
0 0
0.05 9.6877884e-06
0.1 4.2838688e-05
0.15 0.00016929444
0.2 0.00036426881
0.25 0.00055234582
0.3 0.00077448576
0.35 0.00082546537
0.4 0.0012371619
0.45 0.0013286382
0 0
0.05 0.0024898597
0.1 0.0049595502
0.15 0.0074092494
0.2 0.009839138
0.25 0.012249394
0.3 0.014640196
0.35 0.017011717
0.4 0.019364133
0.45 0.021697611
awk '{print $1 " " $2}' data > tmp
我可以使用后面的生成它,awk '{print $1 " " $3}' data >> tmp
但这对于我拥有的列数来说变得非常乏味。
有没有更明智的方法来实现我的需求?
编辑
我想要一个任意数量的列 n 的解决方案。列到行的正确顺序对于我的需求至关重要。因此,输入的第 3 列应“移动”到输入的第 2 列下方,第 4 列位于第 2 和第 3 列下方,依此类推,第 1 列重复堆叠在下方。无论每列有多少行,第一列都应按升序排列,即 0, 0.05, ..., 0.45, 0, 0.05,..., 0.45, 0,0.05,...,0.45 等。
答案1
awk
该 awk 脚本将在任意数量 > 2 的列上运行,并且出现的顺序将被保留为从下到上,并且不对列是什么做出任何假设(IE它们是否是数字、是否排序等都无关紧要):
{
for (i = 2; i <= NF; i++) {
a[j + i] = $1 " " $i
}
j += (i - 1);
}
END {
OutNR = NR * NF;
for (i = 2; i <= NF; i++) {
for (j = 0; j < OutNR; j += NF) {
print a[j + i];
}
}
}
鉴于:
0 0 0 0.2340
0.05 9.6877884e-06 0.0024898597 0.2341
0.1 4.2838688e-05 0.0049595502 0.2342
0.15 0.00016929444 0.0074092494 0.2343
0.2 0.00036426881 0.009839138 0.2344
0.25 0.00055234582 0.012249394 0.2345
0.3 0.00077448576 0.014640196 0.2346
0.35 0.00082546537 0.017011717 0.2347
0.4 0.0012371619 0.019364133 0.2348
0.45 0.0013286382 0.02169761 0.2349
按列排序 (2..n)然后按行:
0 0
0.05 9.6877884e-06
0.1 4.2838688e-05
0.15 0.00016929444
0.2 0.00036426881
0.25 0.00055234582
0.3 0.00077448576
0.35 0.00082546537
0.4 0.0012371619
0.45 0.0013286382
0 0
0.05 0.0024898597
0.1 0.0049595502
0.15 0.0074092494
0.2 0.009839138
0.25 0.012249394
0.3 0.014640196
0.35 0.017011717
0.4 0.019364133
0.45 0.02169761
0 0.2340
0.05 0.2341
0.1 0.2342
0.15 0.2343
0.2 0.2344
0.25 0.2345
0.3 0.2346
0.35 0.2347
0.4 0.2348
0.45 0.2349
右
尽管大多数人并不认为 R 用于文本处理,但在这种情况下,它实际上更直接一些,尽管所有选项设置使其看起来比实际情况更复杂。这个解决方案的本质是简单地rbind()
多重cbind()
:
d.in <- read.table(file = commandArgs(trailingOnly = T)[1]
, colClasses = "character");
d.out<-data.frame();
for (i in 2:length(d.in)) {
d.out <- rbind(d.out, cbind(d.in[,1], d.in[,i]));
}
write.table(d.out, row.names = F, col.names = F, quote = F);
然后,只需:
$ Rscript script.R data.txt
0 0
0.05 9.6877884e-06
0.1 4.2838688e-05
0.15 0.00016929444
0.2 0.00036426881
0.25 0.00055234582
0.3 0.00077448576
0.35 0.00082546537
0.4 0.0012371619
0.45 0.0013286382
0 0
0.05 0.0024898597
0.1 0.0049595502
0.15 0.0074092494
0.2 0.009839138
0.25 0.012249394
0.3 0.014640196
0.35 0.017011717
0.4 0.019364133
0.45 0.02169761
0 0.2340
0.05 0.2341
0.1 0.2342
0.15 0.2343
0.2 0.2344
0.25 0.2345
0.3 0.2346
0.35 0.2347
0.4 0.2348
0.45 0.2349
答案2
如果顺序不重要,你可以简单地使用这个:
awk '{for(i=2;i<=NF;i++)print $1,$i}' file
答案3
这是一个awk
解决方案:
$ awk '{a[i++]=$1" "$3;print $1,$2}END{for(i=0;i<length(a);i++){print a[i]}}' file
0 0
0.05 9.6877884e-06
0.1 4.2838688e-05
0.15 0.00016929444
0.2 0.00036426881
0.25 0.00055234582
0.3 0.00077448576
0.35 0.00082546537
0.4 0.0012371619
0.45 0.0013286382
0 0
0.05 0.0024898597
0.1 0.0049595502
0.15 0.0074092494
0.2 0.009839138
0.25 0.012249394
0.3 0.014640196
0.35 0.017011717
0.4 0.019364133
0.45 0.02169761
解释
处理文件时,我们将 $1 和 $3 保存到数组中,
a
索引从 0 到每行的行数。然后打印$1
和$2
。最后,我们循环遍历 array
a
,打印它的每个元素(即 value$1 $3
)。顺序被保留,因为我们再次使用索引从 0 到数组长度进行循环a
。
更新
对于任意列 n,我使用perl
:
$ perl -anle '$h{$i++} = [@F[0..$#F]];
END {
for $j (1..$#F) {
for (sort {$a<=>$b} keys %h) {
print $h{$_}->[0]," ",$h{$_}->[$j]
}
}
}' file