Usando awk para identificar o número de colunas idênticas

Usando awk para identificar o número de colunas idênticas

Tenho um grande número de arquivos individuais que contêm seis colunas cada (o número de linhas pode variar). Como um exemplo simples:

1   0   0   0   0   0

0   1   1   1   0   0

Estou tentando identificar quantas colunas únicas tenho (ou seja, números e sua ordem coincidem), neste caso seria 3.

Existe uma linha simples para fazer isso? Eu sei que é fácil comparar uma coluna com outra coluna, mas como encontrar colunas idênticas?

Responder1

Você pode contar as colunas exclusivas com o seguinte canal:

$ awk '{for (i=1; i<=NF; ++i) a[i]=a[i]$i; } END { for (i in a) print a[i] }' foo \
  | sort -u | wc -l

O comando awk transpõe sua entrada, as linhas resultantes são classificadas, apenas as linhas únicas são mantidas ( -u) e no final todas as linhas (únicas) (ou seja, as colunas transpostas) são contadas ( wc -l).

Observe que NFé uma variável interna do awk e é automaticamente definida para o número de campos no registro atual. $ifaz referência ao i-ésimo campo e ENDprotege o bloco seguinte para que seja executado após todos os registros serem processados. O Awk usa por padrão a delimitação de campos em branco e não em branco.

Responder2

(((...))), mas como encontrar colunas idênticas?

$ printf '%s\n' '1 0 0 0 0 0' '0 1 1 1 0 0' | awk -vSUBSEP='=' '
    { for (i=1; i<NF; i++)
        for (j=i+1; j<=NF; j++)
          if ($i==$j)
            M[i,j]++
    }
    END{ for (m in M) if (M[m]==NR) print m }'
5=6
2=3
2=4
3=4

Para todas as colunas i<jde cada linha, aumente M[i,j]sempre que os valores dessas colunas forem iguais. Portanto, M[i,j]==NRdepois de ler NRas médias das linhas, os valores eram idênticos para todas as linhas lidas.

Responder3

Essa pergunta me interessou e eu queria seguir uma abordagem que não consegui descobrir exatamente e recebi uma ajuda maravilhosadepois que postei como uma pergunta diferente. Você pode entender a abordagem que estou tentando seguir com a pergunta que postei.

Eu tenho mais 2 soluções para este problema (uma deGnouc'sresposta que é umperlsolução e outra de Joãosolução combinada com a minha solução).

#The variable appended_input will remove spaces/tabs and just append the rows. 
#Modify the file name in this line. Here I use inputfile as the filename. 

appended_input=$(column -s '\t' inputfile | tr -d '[:space:]') ;

#The array variable will store each column-wise value as an array element.  
#I use sort to find the number of unique elements.

array=($(
    for ((i=0; i<6; i++))
    do
        new=${appended_input:$i:1}
        for ((j=i+6; j<${#appended_input}; j=j+6))
        do 
            new="$new${appended_input:$j:1}"
        done
        echo "$new"
    done
    )) | echo "${array[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '

Teste

Meu arquivo de entrada é como abaixo.

1 0 0 1 0 0
0 1 1 0 0 0
1 1 1 1 1 0
1 0 0 1 0 1
1 0 0 1 0 1

Depois de executar o script acima, recebo a saída como,

00011 00100 01100 10111

Você poderia ter a wc -wcomo canal final e obteria a saída apenas 4 em vez dos valores de coluna exclusivos como acima.

Responder4

Aqui está uma gawksolução que usa coprocessos para alimentar cada coluna para uma instância separada sha256sume relata o número total de hashes exclusivos (o número de hashes exclusivos deve coincidir com o número de colunas exclusivas, visto que a probabilidade de colisão de hash sha256sumé estatisticamente insignificante). Embora alguns possam considerar isso um hack flagrante, uma vantagem que essa abordagem tem sobre algumas das outras é que ela não tenta concatenar/transpor os dados e, portanto, é relativamente eficiente em termos de memória.

awk 'BEGIN{for(i=1; i<=6; ++i){s=sprintf("%*s", i+1, ""); a[i]="sha256sum"s}}
    {for (i=1; i<=6; ++i) print $i |& a[i]}
    END{com= "sort | uniq | wc -l"
    for (i=1; i<=6; ++i){close(a[i], "to"); a[i] |& getline x;
    close(a[i]); print x | com};
    close(com)}' file 

informação relacionada