Executar um comando do tipo GROUP BY no UNIX

0

Estou tendo um arquivo de texto como o seguinte:

1 2 3 4 5 6 7 8 9 ... n    <-- column numbering
1 0 0 1 0 0 0 1 0 ... 0
0 1 0 0 0 0 0 0 0 ... 1
1 0 0 0 0 0 0 1 1 ... 0
0 1 1 1 0 1 0 0 0 ... 0
0 1 0 0 1 0 1 0 1 ... 1

Na verdade, é uma matriz muito esparsa, onde os valores binários. Em cada linha deve haver mais de um 1s e em cada coluna pelo menos um 1.

O que eu quero fazer é descobrir quais colunas dizem menos de 2 1s. Por exemplo, na minha matriz acima, eu gostaria de me livrar das colunas 3, 5, 6 e 7 porque elas têm apenas 1.

Existe um comando do UNIX para fazer isso? Provavelmente eu preciso de um comando Group by-like (SQL) e, em seguida, acompanhar quais colunas são menores que um determinado número, mas não vejo como eu poderia fazê-lo.

    
por ddmichael 02.06.2014 / 18:20

1 resposta

1

Você pode usar awk para percorrer a matriz e contar o número de 1s e 0s usando o seguinte script:

count.awk :

NR != 1 {
  for (i=1; i<=NF; ++i)
    count[i] += $i;
}

END {
  ORS = ",";
  for (i=1; i<=length(count); ++i)
    if (count[i] >= min)
       print i
}

Se você executar este script usando

awk -v min=2 -f count.awk matrix.txt

você receberá uma linha de colunas com dois ou mais 1s, neste caso "1,2,4,8,9" (observação: você pode alterar o min=X para qualquer limite mínimo desejado).

Agora, use cut para imprimir apenas as colunas que desejamos:

cols=$(awk -v min=2 -f count.awk matrix.txt); cut -d' ' -f${cols:0:-1} matrix.txt

Isso armazena a saída awk em uma variável (a razão para isso é que awk retorna uma lista de colunas com um , extra no final. Eu "fatia" a vírgula quando eu passo os cols para cut ).

Defina o delimitador para cut para "espaço" ( -d' ' ) e as colunas de saída para a lista separada por vírgulas de awk , com a última vírgula sendo dividida ( -f${cols:0:-1} ).

Saída:

1 2 4 8 9 n
1 0 1 1 0 0
0 1 0 0 0 1
1 0 0 1 1 0
0 1 1 0 0 0
0 1 0 0 1 1

Se você deseja produzir as colunas com menos de min 1s (ou seja, colunas 3, 5, 6, 7), apenas inverta a condição da instrução if no script awk acima para ler if (count[i] < min) .

Saída:

3 5 6 7
0 0 0 0
0 0 0 0
0 0 0 0
1 0 1 0
0 1 0 1
    
por 02.06.2014 / 20:54

Tags