Substituindo todos os resultados diferentes de zero por “1” para formar presença / ausência

1

Eu tenho uma tabela delimitada por tabulações

  a b c
A 5 2 0
B 0 5 4
C 4 3 4
D 2 0 2

Eu quero alterar os valores diferentes de zero para "1", sem alterar os nomes de coluna ou linha.

Saída desejada:

  a b c
A 1 1 0
B 0 1 1
C 1 1 1
D 1 0 1

Para esclarecer, esta é uma tabela de exemplo. As letras são variáveis representando os nomes de coluna / linha - pode haver centenas de colunas e linhas. Os valores diferentes de zero (dados aqui como números) podem não ser necessariamente números - podem ser os nomes de pessoas, por exemplo.

    
por P.tin 24.01.2017 / 15:42

5 respostas

4

Supondo uma entrada restrita por tabulação:

$ cat data.in
        a       b       c
A       nancy   bilbo baggins   0
B       0       darcy   bender
C       phantom menace  Unix    !!
D       last row        0       the end

$ cat -t data.in
^Ia^Ib^Ic
A^Inancy^Ibilbo baggins^I0
B^I0^Idarcy^Ibender
C^Iphantom menace^IUnix^I!!
D^Ilast row^I0^Ithe end

Um script awk para fazer o trabalho:

BEGIN { OFS = FS = "\t" }

NR != 1 {
    for (i = 2; i <= NF; ++i) {
        if ($i != "0") {
            $i = "1";
        }
    }
}

{ print }

Executando:

$ awk -f script.awk data.in
        a       b       c
A       1       1       0
B       0       1       1
C       1       1       1
D       1       0       1

O script compara cada campo (coluna) com o caractere único 0 (exceto o primeiro campo) e substitui tudo o que não é exatamente 0 por 1 . A saída será delimitada por tabulações.

    
por 24.01.2017 / 16:29
2
sed '1!s/ [^ ]*[^ 0][^ ]*/ 1/g'

Substituiria qualquer sequência de caracteres não espaciais que contivesse pelo menos um caractere diferente de 0 (e que segue um espaço) com 1 (exceto na primeira linha).

IOW, que substituiria qualquer coisa diferente de seqüências de 0s e a primeira coluna e linha com 1 .

    
por 24.01.2017 / 16:15
1

Considerando que os cabeçalhos não incluem números como sua amostra, a maneira mais fácil de pensar é:

sed 's/[1-9]/1/g' file.txt

observe o intervalo: 1 a 9, zero excluído.

$ echo "A 5 2 0" |sed 's/[1-9]/1/g'
A 1 1 0

Isso funciona se os números nas colunas forem até 9. Se não for esse o caso e os números puderem ser 10 ou mais, eu preciso revisar.

De acordo com o último esclarecimento do OP, como as entradas diferentes de zero podem ser nomes, etc, isso NÃO funcionará.

    
por 24.01.2017 / 16:07
0

Esta é uma boa tarefa para o Python.

$ cat input.txt
    a   b   c
A   alpha   beta    0
B   0   gamma   zeta
C   alpha   phi omega
D   kappa   0   delta

$ ./replace_nonzero.py  < input.txt                                                                                      
a   b   c
A   1   1   0
B   0   1   1
C   1   1   1
D   1   0   1

E aqui está o replace_nonzero.py em si:

#!/usr/bin/env python
from __future__ import print_function
import sys

for index,line in enumerate(sys.stdin):
   if index == 0 :
       print(line.strip())
       continue
   words = line.strip().split()
   print(words[0],end="\t")

   new_line = []
   for word in words[1:]:
      if word.isdigit() and int(word) == 0:
          new_line.append('0')
      else:
          new_line.append('1')
   print("\t".join(new_line))

A maneira como isso funciona é simples: pulamos a primeira linha como se trata de um caso especial, e dividimos todas as outras linhas em palavras, e examinamos as que partem da posição 1. A lógica aqui funciona da suposição oposta - se a palavra que nós got é um dígito e é zero, então acrescentamos uma string '0' na nova lista (que é uma lista de palavras para cada linha), caso contrário - acrescentamos a string '1'. Por fim, pegamos a nova lista e a imprimimos novamente - delimitada por tabulações.

    
por 25.01.2017 / 00:40
0

Isso só funciona no bash

bash$ paste <(cut -f1 file) <(cut -f2- file |
        sed -r '1b;        # if title line then skip to end
        s#\t#\n#g          # seperate line to multi-line
        s#.*[^0].*#1#Mg    # apply multi-line operation 
        s#\n#\t#g' )       # turn to one line

        a       b       c
A       1       1       0
B       0       1       1
C       1       1       1
D       1       0       1
    
por 25.01.2017 / 00:03