将一列(长)转换为长度不等的多列(短)

将一列(长)转换为长度不等的多列(短)

我有一个包含一列数据的文件(即每行一个数据值)。我将这些数据解释为多个数据 数据集由一行或多NA行分隔。请注意,数据集的长度不同。我想将其转换为多列格式,其中每个数据集都位于一列中(与它们在输入文件中出现的顺序相同)。

例如,我有以下文件(实际上,该文件包含更多数据):

NA
4
3
5
7
8
3
NA
NA
NA
3
4
5
2
NA
2 
7
4
6
9
NA

我的预期输出如下:

4 3 2
3 4 7
5 5 4
7 2 6
8 . 9
3

8 和 9 之间的点并不是真正需要的,但也可以用空格代替。

答案1

您可以awk将每组数据(其中的数据位于NA行之间)分割成单独的文件并跳过NA行,然后将paste它们放在一起。

awk '/^NA$/ && !NA{N++; NA=1; next} !/^NA$/{print >"file"N; NA=0}
    END{system("paste file*")}' inile.txt

NA标志用于按顺序创建文件,我们可以在下面使用。

awk '/^NA$/{N++; next} !/^NA$/{print >"file"N}
    END{system("paste file*")}' inile.txt

输出是:

4 3 2
3 4 7
5 5 4
7 2 6
8   9
3

答案2

该输出格式对我来说没有意义。我认为这根本不实用。

无论如何,只需每行写入它,然后转置(或者更好,将其保留在每行):

tr '\n' ' ' < example | tr 'N' '\n' | sed 's/^A //; /^$/d'

给出

4 3 5 7 8 3 
3 4 5 2 
2 7 4 6 9

答案3

在外壳中转换是一件痛苦的事情。这是 Perl 的简短答案,需要数组::转置::参差不齐来自 CPAN

perl -MArray::Transpose::Ragged=transpose_ragged -lnE '
        if (/NA/) { $n++; next }      # next row
        push @{$data[$n]}, $_;        # creating the 2D matrix of data
    } END {
        say join "\t", @$_ for transpose_ragged [grep {defined} @data];
' file

这是另一种方法:之前的管道gawk本质上与 @n.caillou 的答案相同,awk 代码进行转置

paste -sd " " file | sed 's/NA/\n/g' | sed '/^ *$/d' | gawk '
    {
        for (i=1; i<=NF; i++) data[FNR][i] = $i
        if (NF > max) max = NF
    }
    END {
        for (i=1; i<=max; i++) {
            for (j=1; j<=NR; j++) printf "%s\t", data[j][i]
            print ""
        }
    }
'

使用 GNU awk 处理多维数组

答案4

GNU 数据混合需要 1.1.1 版本。在 1.0.7 版本中它无法正常工作。

#!/bin/bash

tr '\n' ' ' < input.txt |
sed 's/\s*NA\s*/\n/g;' |
sed '/^$/d'  |
datamash --no-strict --filler="." -W -t' ' transpose

解释

  1. tr '\n' ' ' < input.txt- 将所有换行符替换为空格。换句话说,将所有行连接到一行。
  2. sed 's/\s*NA\s*/\n/g;'- 将所有“NA”和相邻空格替换为换行符。也就是说,它将大行分成几行,每一行都是未来的列,水平书写。
  3. sed '/^$/d'- 删除所有空行。
  4. datamash --no-strict --filler="." -W -t' ' transpose
    • --no-strict- 允许具有不同数量字段的行
    • --filler="."- 用点填充缺失值。可以将其更改为空间。
    • -W- 使用空格(一个或多个空格和/或制表符)作为输入字段分隔符。
    • -t' '- 使用空格而不是制表符作为输出字段分隔符。
    • transpose- 将行转换为列。

输入

NA
4
3
5
7
8
3
NA
NA
NA
3
4
5
2
NA
2
7
4
6
9
NA

输出

4 3 2
3 4 7
5 5 4
7 2 6
8 . 9
3 . .

相关内容