重塑制表符分隔的文件

重塑制表符分隔的文件

我有一个如下所示的文件:

 Time   Flag
 0.65   5.885581e-01
 0.56   5.847484e-01
 0.58   5.278409e-01
 0.57   1.140746e+00
 1.00   0
 0.00   0
 1.00   1
 0.00   0

但这是因为我写的时候忘了转置一些东西。因此,一半的计时最终出现在标志列中,一半的标志最终出现在时间列中。本来应该是

 Time Flag
 0.65   1
 0.59   0
 0.56   0
 0.58   0
 0.58   1
 0.53   1
 0.57   0
 1.14   0

因此,在这个小示例中,前四行应该成为第一列。最后四行应成为第二列。请注意,每列中的一半元素已在原始文件中正确格式化(以交替方式)。重塑和重新格式化它的最简单方法是什么?

答案1

$ awk 'NR > 1 { d[++n] = $1; d[++n] = $2 } END { print "Time", "Flag"; for (i = 1; 2*i <= n; ++i) printf "%.2f%s%d%s", d[i], OFS, d[n/2 + i], ORS }' file
Time Flag
0.65 1
0.59 0
0.56 0
0.58 0
0.58 1
0.53 1
0.57 0
1.14 0

awk代码将所有数据按行读取到数组中的连续元素中d(跳过标头)。

END块中,打印标题,然后我们i从 1 到数组长度的一半进行迭代d,打印索引处的值i(时间值)和标记处的值n/2 + i(标志值)。完成输出的格式化,以便将时间值打印为带有两位小数的浮点值,并将标志值打印为整数。

OFS和变量ORS保存默认的输出字段和记录分隔符(默认为空格和换行符)。对于制表符分隔的输出,请使用awk -v OFS='\t' '{ ... }' file.

作为参考,该awk代码作为独立脚本:

#!/usr/bin/awk -f

NR > 1 {
    d[++n] = $1
    d[++n] = $2
}

END {
    print "Time", "Flag"

    for (i = 1; 2*i <= n; ++i)
        printf "%.2f%s%d%s", d[i], OFS, d[n/2 + i], ORS
}

答案2

OP 没有说明问题需要将文件分成两半,修复每一半,然后重新连接在一起,但我想知道在没有这些知识的情况下如何完成它。

我真的很喜欢csvkit尤其是GoCSV用于声明性管道处理。

转换/设置

第一步是将固定宽度示例数据转换为 CSV。 csvkit 让我指定一个列宽模式...

架构.csv

column,start,length
Time,0,4
Flag,7,13

然后转换为 CSV:

in2csv -s schema.csv input.txt > input.csv

分离和转置

我想按类别拆分输入:标志和时间。然后为每个类别制作一组单行 CSV(用于下一步的转置):

gocsv filter -c 2 --regex "^[01]$" input.csv | 
gocsv split --max-rows 1 --filename-base flags

对于互补的时间,使用相同的模式--exclude

gocsv filter -c 2 --regex "^[01]$" --exclude input.csv | 
gocsv split --max-rows 1 --filename-base times

这会生成一组文件,例如:

ls flags-*.csv                                     
flags-1.csv  flags-2.csv  flags-3.csv  flags-4.csv

每个看起来都像:

标志-1.csv

Time,Flag
1.00,0

或者:

times-4.csv

Time,Flag
0.57,1.140746e+00

Time,Flag头并不是很重要,但重要的是要看到它的存在并且会影响转置后的结构。

对于每个文件,迭代:转置,选择第二列(因为虚假标题成为第一列),并使用适当的标题进行封顶:

for FILE in flags-*; do 
  gocsv transpose $FILE | 
  gocsv select -c 2 | 
  gocsv cap --names Flag \
  > trans_$FILE; 
done

for FILE in times-*; do
  gocsv transpose $FILE |
  gocsv select -c 2 |
  gocsv cap --names Time \
  > trans_$FILE;
done

堆叠成列

将标志和时间堆叠到各自的列中:

gocsv stack trans_flags*  > col_flag.csv

gocsv stack trans_times*  > col_time.csv

然后拉链在一起(我只是要使用csvlook因为它有更漂亮的 Markdown 表格,但它也标准化了数字!):

gocsv zip col_time.csv col_flag.csv > output.csv
csvlook output.csv
时间 旗帜
0.650… 1
0.589… 0
0.560… 0
0.585… 0
0.580… 1
0.528… 1
0.570… 0
1.141… 0

这很可爱。

但最后一步是使用 GoCSV 的内置(对我来说是新的)SPRIG 模板和round清理浮点数、整数和科学记数法的函数。我根据原始列添加新列,然后仅选择新的/格式化的列:

cat output.csv |
gocsv add -n Time -t "{{round .Time 2}}" |
gocsv add -n Flag -t "{{round .Flag 0}}" |
gocsv select -c 3- |
gocsv tsv

我们得到:

Time    Flag
0.65    1
0.59    0
0.56    0
0.58    0
0.58    1
0.53    1
0.57    0
1.14    0

相关内容