Imprime valores que são pelo menos 2 vezes maiores que os valores 3 degraus acima e abaixo na mesma coluna (cont. 1)

0

Eu tenho uma mesa

A 1
A 1
A 1
A 1
A 1
A 1
A 2
B 1
B 1
B 1
B 2
B 1
B 1
B 1

Eu quero imprimir a coluna 1 de linhas com valores da coluna 2 pelo menos 2 vezes maiores que o 3º passo acima e o 3º passo abaixo na mesma coluna. No entanto, considere apenas as linhas com o mesmo nome na coluna 1.

Portanto, a saída deve ser

B

Eu quero modificar este script que foi escrito por Stéphane Chazelas, para atender a exigência adicional em negrito acima.

awk -v key=1 -v value=2 '
  NR > 6 {
    x = saved_value[NR%6]; y = saved_value[(NR - 3) % 6]; z = $value
    if (y >= 2*x && y >= 2*z) print saved_key[(NR - 3) % 6]
  }
  {saved_key[NR % 6] = $key; saved_value[NR % 6] = $value}'  < file

(Na verdade, é um post continuado de aqui . Como há uma situação mais complicada, quero ilustrar melhor aqui.)

. .

atualização 20171010:

Agora estou modificando o script escrito por Stéphane Chazelas, mas agora estou selecionando as linhas com valores que são pelo menos duas vezes menores que o terceiro valor acima e o terceiro valor abaixo . Anteriormente, simplifiquei o exemplo e, assim, consegui entender e modificar o script sozinho para v2 <= v1/2 && v2 <= v3/2 , mas, novamente, falhei ... Para tornar o assunto mais direto, agora estou fornecendo o arquivo real da seguinte maneira, em que os valores no A segunda coluna é inútil e os valores nas 3ª colunas devem ser comparados :

K00188:14:H2LMFBBXX:6:1101:27440:1668   1   2
K00188:14:H2LMFBBXX:6:1101:27440:1668   2   2
K00188:14:H2LMFBBXX:6:1101:27440:1668   3   2
K00188:14:H2LMFBBXX:6:1101:27440:1668   4   1
K00188:14:H2LMFBBXX:6:1101:27440:1668   5   1
K00188:14:H2LMFBBXX:6:1101:27440:1668   6   1
K00188:14:H2LMFBBXX:6:1101:27440:1668   7   1
K00188:14:H2LMFBBXX:6:1101:27440:1668   8   1
K00188:14:H2LMFBBXX:6:1101:27440:1668   9   1
K00188:14:H2LMFBBXX:6:1101:27440:1668   10  1
K00188:14:H2LMFBBXX:6:1101:6501:1686    1   2
K00188:14:H2LMFBBXX:6:1101:6501:1686    2   2
K00188:14:H2LMFBBXX:6:1101:6501:1686    3   2
K00188:14:H2LMFBBXX:6:1101:6501:1686    4   1
K00188:14:H2LMFBBXX:6:1101:6501:1686    5   1
K00188:14:H2LMFBBXX:6:1101:6501:1686    6   1
K00188:14:H2LMFBBXX:6:1101:6501:1686    7   2
K00188:14:H2LMFBBXX:6:1101:6501:1686    8   2
K00188:14:H2LMFBBXX:6:1101:6501:1686    9   2
K00188:14:H2LMFBBXX:6:1101:6501:1686    10  2

Se linhas inteiras são impressas, a saída esperada é:

K00188:14:H2LMFBBXX:6:1101:6501:1686    4   1
K00188:14:H2LMFBBXX:6:1101:6501:1686    5   1
K00188:14:H2LMFBBXX:6:1101:6501:1686    6   1

Esta é a minha modificação que falhou:

awk -v key=1 -v value=3 '
  NR > 6 {
    k1 = saved_key[NR%6];   k2 = saved_key[(NR - 3) % 6];   k3 = $key
    v1 = saved_value[NR%6]; v2 = saved_value[(NR - 3) % 6]; v3 = $value
    if (k1 == k2 && k2 == k3 && v2 <= v1/2 && v2 <= v3/2) print $0
  }
  {saved_key[NR % 6] = $key; saved_value[NR % 6] = $value}' < test

Como eu poderia corrigir isso?

. .

atualização 20171011:

Como eu poderia adicionar uma chave adicional para que eu pudesse comparar os valores na coluna 3 com os 3os valores acima e abaixo na coluna 4 (ou seja, uma coluna diferente) ? Por favor, consulte a atualização 20171011. Obrigado novamente!

K00188:14:H2LMFBBXX:6:1101:27440:1668   1   0   2
K00188:14:H2LMFBBXX:6:1101:27440:1668   2   0   2
K00188:14:H2LMFBBXX:6:1101:27440:1668   3   0   2
K00188:14:H2LMFBBXX:6:1101:27440:1668   4   1   0
K00188:14:H2LMFBBXX:6:1101:27440:1668   5   1   0
K00188:14:H2LMFBBXX:6:1101:27440:1668   6   1   0
K00188:14:H2LMFBBXX:6:1101:27440:1668   7   1   0
K00188:14:H2LMFBBXX:6:1101:27440:1668   8   1   0
K00188:14:H2LMFBBXX:6:1101:27440:1668   9   1   0
K00188:14:H2LMFBBXX:6:1101:27440:1668   10  1   0
K00188:14:H2LMFBBXX:6:1101:6501:1686    1   0   2
K00188:14:H2LMFBBXX:6:1101:6501:1686    2   0   2
K00188:14:H2LMFBBXX:6:1101:6501:1686    3   0   2
K00188:14:H2LMFBBXX:6:1101:6501:1686    4   1   0
K00188:14:H2LMFBBXX:6:1101:6501:1686    5   1   0
K00188:14:H2LMFBBXX:6:1101:6501:1686    6   1   0
K00188:14:H2LMFBBXX:6:1101:6501:1686    7   0   2
K00188:14:H2LMFBBXX:6:1101:6501:1686    8   0   2
K00188:14:H2LMFBBXX:6:1101:6501:1686    9   0   2
K00188:14:H2LMFBBXX:6:1101:6501:1686    10  0   2

Se linhas inteiras são impressas, a saída esperada é:

K00188:14:H2LMFBBXX:6:1101:6501:1686    4   1   0
K00188:14:H2LMFBBXX:6:1101:6501:1686    5   1   0
K00188:14:H2LMFBBXX:6:1101:6501:1686    6   1   0

É meu teste:

awk -v key1=1 -v key2=2 -v value1=3 -v value2=4 '
    {
    k1 = saved_key1[NR%6];   k2 = saved_key1[(NR - 3) % 6];   k3 = $key1
    k4 = saved_key2[NR%6];   k5 = saved_key2[(NR - 3) % 6];   k6 = $key2
    v1 = saved_value1[NR%6]; v2 = saved_value1[(NR - 3) % 6]; v3 = $value1
    v4 = saved_value2[NR%6]; v5 = saved_value2[(NR - 3) % 6]; v6 = $value2
    if (k1 == k2 && k2 == k3 && v2 <= v4/2 && v2 <= v6/2) print saved_record[(NR-3)%6]
  }
  {saved_key1[NR % 6] = $key1; saved_value1[NR % 6] = $value1}' < file
    
por Johnny Tam 07.10.2017 / 12:01

2 respostas

1

Então seria:

awk -v key=1 -v value=2 '
  NR > 6 { # for 7th record and over only
    k1 = saved_key[NR%6];   k2 = saved_key[(NR - 3) % 6];   k3 = $key
    v1 = saved_value[NR%6]; v2 = saved_value[(NR - 3) % 6]; v3 = $value
    if (k1 == k2 && k2 == k3 && v2 >= 2*v1 && v2 >= 2*v3) print k2
  }
  # for every record, save key and value in ring buffers:
  {saved_key[NR % 6] = $key; saved_value[NR % 6] = $value}'

Observe que as comparações k1 == k2 e k2 == k3 serão numéricas se os valores se parecerem com números (portanto, 00 será considerado o mesmo que 0 ) e textual caso contrário. Altere para k1 "" == k2 para forçar uma comparação textual.

Ou salve todos os registros e divida novamente ao verificar. Como para a sua atualização 20171010 :

awk -v key=1 -v value=3 '
  NR > 6 {
    # "above" is an array with the fields of 6th last record
    split(saved_record[NR%6], above)
    # "text" is the 3rd last record and the one we will be looking at
    text = saved_record[(NR - 3) % 6]
    # "text" fields split into the "here" array.
    split(text, here)
    # $0 contains the current record (the one 3 lines below "here")
    # and $1, $2, $3... the fields of that record.
    if (above[key] == here[key] && here[key] == $key && \
        here[value] <= above[value] / 2 && here[value] <= $value / 2)
      print text
  }
  {saved_record[NR % 6] = $0}'
    
por 07.10.2017 / 12:09
0

Solução GNU datamash + awk relativamente curta:

datamash -W -g1 count 2 collapse 2 <file | awk '$2==7{ split($3,a,","); k=a[4]; 
             delete a[4]; if(k>=a[7]*2) print $1 }'
    
por 07.10.2017 / 14:14