Concatene o CSV com algumas colunas compartilhadas

2

Eu tenho dois arquivos grandes ~ 9GB. O arquivo CSV 1 tem colunas A, B, C, D, E e o arquivo CSV 2 tem colunas B, C, F, G . A saída desejada é A, B, C, D, E, F, G . Tudo o que tenho conseguido encontrar é juntar colunas semelhantes e concatenar com as mesmas colunas, no entanto aqui algumas coincidem, e outras não. Um exemplo de saída seria algo ao longo destas linhas:

A   B   C   D   E   F   G

1   2   3   4   5   6   7

NaN 1   2   NaN 1   2   1

Portanto, se o valor não existir para essa coluna, como ela não existe, eu só quero que ela tenha um valor NaN . Espero ter explicado bem o problema. Obrigado!

Editar: Normalmente, eu faria isso em Python , mas esses arquivos enormes tornam consideravelmente mais irritante repetir iterações em partes e concatenar no final. Parece haver uma maneira mais direta de usar o bash que eu desconheço. Obrigado!

    
por aws_apprentice 14.02.2017 / 23:22

1 resposta

2

Isso funciona com base nos seguintes fatos:
(a) Todos os campos são estritamente separados por tabulação (b) colunas comuns em ambos os arquivos (B e C) têm o mesmo valor

$ join --nocheck-order -eNaN -13 -22 -t$'\t' -o 1.1 1.2 1.3 1.4 1.5 2.3 2.4 b.txt c.txt
A   B   C   D   E   F   G
1   2   3   4   5   6   7
NaN 1   2   NaN 1   2   1

Amostra de arquivos:

$ cat b.txt
A   B   C   D   E
1   2   3   4   5
    1   2       1
$ cat c.txt
B   C   F   G
2   3   6   7
1   2   2   1

Opções de adesão:
-13 -22: Junção baseada no arquivo1 coluna3 (C) = arquivo2 coluna2 (C)
-t $ '\ t': delimitador de tabulação para entrada e saída
-o: formato de saída. 1.1 significa arquivo1, coluna1 e assim por diante.
-e: Preencher valores vazios com NaN
Para mais informações, consulte man join e melhor ainda info join

Solução alternativa com AWK
PS: Fique comigo no awk, sou um aprendiz novo.

$ awk -F"\t" '{a[1]="";{for (i=1;i<=NF;i++) if (i==6 ||i==7) continue;else \
if ($i!="") a[1]=a[1]FS$i;else a[1]=a[1]FS"NaN";print a[1]}}' <(paste b.txt c.txt)

Atualização para campos de entrada separados por vírgula
Conforme recomendado em seus comentários, como os arquivos csv são separados por vírgula, essa solução separará campos de entrada por vírgula e emitirá os resultados usando as guias para que sejam mais legíveis.

awk 'BEGIN {FS=",";OFS="\t"}{a[1]="";{for (i=1;i<=NF;i++) if (i==6 ||i==7) continue;else \
if ($i!="") a[1]=a[1]OFS$i;else a[1]=a[1]OFS"NaN";print a[1]}}' <(paste b.txt c.txt)

Se você precisar que a saída seja impressa também com vírgula, basta substituir a seção inicial por {FS=OFS=","}

Embora ainda não esteja claro o que você pretende fazer com colunas comuns / valores diferentes.

Você pode remover a parte if (i==6 ||i==7) continue;else para ver se os resultados atendem às suas necessidades. Essa verificação de condição, na verdade, ignora o campo 6 (coluna B do arquivo2) e o campo7 (coluna C do arquivo2), uma vez que essas duas colunas do arquivo 2 foram consideradas idênticas às colunas do arquivo 1 até o momento.

Para a solução de associação:
Substitua -t$'\t' por -t',' para ler campos separados por vírgulas

Para as colunas comuns, você pode reproduzir com este formato de saída:

join --nocheck-order -eNaN -13 -22 -t',' -o 1.1 1.2 2.1 1.3 2.2 1.4 1.5 2.3 2.4 b.txt c.txt
    
por 15.02.2017 / 00:11