Eu tenho um dado assim:
111 5
111 6
111 1
222 8
222 9
222 1
222 3
555 9
555 7
555 6
e para cada valor de $1
, quero obter o valor mediano de todos os valores de $2
para isso $1
se possível usando AWK .
saída desejada:
111 5 5
111 6 5
111 1 5
222 8 5.5
222 9 5.5
222 1 5.5
222 3 5.5
555 9 7
555 7 7
555 6 7
Onde 5 é o valor médio de 5, 6 e 1 (os valores para $1
== 111
), 5,5 o valor médio de 8, 9, 1 e 3, etc.
Supondo que os dados já estejam classificados lexicograficamente na primeira coluna e que você esteja usando um shell que entenda as substituições de processo com
<(...)
:Isso executa uma operação de JOIN relacional no primeiro campo do arquivo com o resultado do comando
Este comando calcula a mediana para cada conjunto de valores do segundo campo, agrupados pelos valores do primeiro campo. Com a
-W
opção, fazemos com que o GNUdatamash
trate a entrada como delimitada por espaços em branco.O resultado dessa operação é
Unindo isso aos dados originais no primeiro campo, você obtém o resultado desejado.
Se os dados ainda não estiverem classificados no primeiro campo:
Se você quiser garantir que as linhas com o mesmo primeiro campo não sejam reordenadas uma em relação à outra, certifique-se de que o
sort file
comando use um algoritmo de classificação estável . A maioria dassort
implementações permite que você faça isso usando a-s
opção não padrão.Para um shell sem substituição de processo:
Os dados são classificados:
Os dados precisam de classificação:
Usando qualquer sort+awk em qualquer shell em cada caixa unix:
O acima armazena todos os
$2
valores para o atual$1
em uma matriz chamadavals[]
, então quando o$1
valor muda ou o final do arquivo é atingido, ele chamaprt()
que descobre o valor mediano para essa matriz, armazena-o em uma variável chamadamed
e depois em um loop imprime$1
mais todos os se associados$2
emed
.O acima reordena as linhas para saída. Se isso for um problema, podemos decorar as linhas primeiro para salvar sua ordem original, depois fazer o sort+awk acima, depois ordenar novamente para a ordem original e, finalmente, descorar.
Se você tiver GNU awk e seus valores de chave já estiverem classificados, você poderá chamar
asort()
dentro daprt()
função e não precisará chamarsort
antes deawk
. Se nada for classificado, você poderá armazenar tudo em arrays e classificar na seção END. Mas apenas chamarsort
primeiro, como mostrado, é mais claro, mais simples, mais eficiente e mais portátil.Usando GNU awk para a função asort() e independentemente de seus dados serem classificados ou não, mas requerem processar o arquivo de entrada duas vezes; no primeiro processamento, agrupamos cada valor de Id em um e depois calculamos a mediana para cada grupo e na segunda vez do arquivo de processamento estamos apenas imprimindo sua mediana calculada como a última coluna do
id
array: