Converta uma coluna (longa) em múltiplas colunas (curtas) de comprimentos desiguais

4

Eu tenho um arquivo com uma coluna de dados (por exemplo, um valor de dados por linha). Eu interpreto esses dados como vários dados conjuntos ; os conjuntos de dados são separados por um ou mais NA linhas. Observe que os conjuntos de dados não são do mesmo tamanho. Eu quero converter isso para um formato multi-coluna em que cada conjunto de dados está em uma coluna (na mesma ordem em que aparecem no arquivo de entrada).

Por exemplo, Eu tenho o seguinte arquivo (na realidade, o arquivo contém muito mais dados):

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

Minha saída esperada é a seguinte:

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

O ponto entre 8 e 9 não é realmente necessário, mas também pode ser substituído por um espaço.

    
por Froelicher 15.09.2017 / 23:02

4 respostas

2

Você pode usar awk para dividir cada grupo de dados (onde estão entre NA linhas) em arquivos separados e pular NA linhas e, em seguida, paste juntos.

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

A flag NA é usada para criar arquivos em ordem sequencial, poderíamos usar abaixo em vez disso.

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

A saída é:

4 3 2
3 4 7
5 5 4
7 2 6
8   9
3
    
por 16.09.2017 / 05:27
1

Esse formato de saída não faz sentido para mim. Eu não acho que seja prático.

De qualquer forma, apenas escreva por linha, depois transponha (ou melhor, deixe por linha):

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
    
por 16.09.2017 / 04:34
1
Transposição na casca é uma dor na bunda. Aqui está uma resposta curta com Perl que requer Array :: Transpose :: Ragged do 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

Aqui está outra abordagem: o pipeline antes de gawk é essencialmente o mesmo que a resposta de @ n.caillou, o código awk faz a transposição

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 ""
        }
    }
'

Usa o GNU awk para matrizes multidimensionais

    
por 16.09.2017 / 14:43
0

O datamash do GNU é necessário na versão 1.1.1. Na versão 1.0.7 não funciona corretamente.

#!/bin/bash

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

Explicação

  1. tr '\n' ' ' < input.txt - substitui todas as novas linhas por espaços. Em outras palavras, junte todas as linhas à linha.
  2. sed 's/\s*NA\s*/\n/g;' - substitui todos os espaços "NA" e adjacentes pela nova linha. Isto é, divide a linha grande em poucas linhas separadas, cada uma é a coluna futura, escrita horizontalmente.
  3. sed '/^$/d' - remove todas as linhas em branco.
  4. %código%
    • datamash --no-strict --filler="." -W -t' ' transpose - permite linhas com um número variável de campos
    • --no-strict - preenche os valores ausentes com ponto. Pode ser alterado para o espaço.
    • --filler="." - use espaço em branco (um ou mais espaços e / ou tabulações) para delimitadores de campo de entrada.
    • -W - use espaço em vez de TAB como delimitador de campo de saída.
    • -t' ' - converte linhas em colunas.

Entrada

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

Resultado

4 3 2
3 4 7
5 5 4
7 2 6
8 . 9
3 . .
    
por 18.09.2017 / 00:35