Queridos, eu tenho umgrandearquivo de dados, digamosarquivo.dat, contém duas colunas
por exemplo, file.dat (mostrando algumas linhas)
0.0000 -23.4334
0.0289 -23.4760
0.0578 -23.5187
0.0867 -23.5616
0.1157 -23.6045
0.1446 -23.6473
0.1735 -23.6900
0.2024 -23.7324
0.2313 -23.7745
0.2602 -23.8162
0.2892 -23.8574
0.3181 -23.8980
0.3470 -23.9379
0.3759 -23.9772
0.4048 -24.0156
0.4337 -24.0532
0.4627 -24.0898
0.4916 -24.1254
note: data file has a blank line at the end of the file
Resultados esperados
Quero encontrar/extrair o máximo e o mínimo de ambas as colunas, por exemplo, coluna-1
max - 0.4916
min - 0.0000
da mesma forma coluna-2
max - -23.4334
min - -24.1254
Solução incompleta (não funciona para a coluna 2)
Para Coluna-1
awk 'BEGIN{min=9}{for(i=1;i<=1;i++){min=(min<$i)?min:$i}print min;exit}' file.dat
0.0000
cat file.dat | awk '{if ($1 > max) max=$1}END{print max}'
0.4916
para coluna-2
awk 'BEGIN{min=9}{for(i=2;i<=2;i++){min=(min<$i)?min:$i}print min;exit}' file.dat
-23.4334
cat file.dat | awk '{if ($2 > max) max=$2}END{print max}'
**no output showing**
Problema
Por favor, ajude-me a encontrar o valor mínimo e máximo da coluna 2 nota: o arquivo de dados possui uma linha em branco no final do arquivo
Responder1
O problema no seu código,
awk 'BEGIN{min=9}{for(i=2;i<=2;i++){min=(min<$i)?min:$i}print min;exit}' file.dat
... é que você imediatamente exit
após processar a primeira linha de entrada. Seu bloco do meio precisa ser acionado paratodolinha. Então, em um END
bloco, você pode imprimir os valores encontrados. Você faz isso em outro trecho de código:
awk '{if ($1 > max) max=$1}END{print max}'
Outra questão é que você inicializa min
com um número mágico (9 no primeiro código que citei, e 0 na segunda parte; variáveis que não são inicializadas explicitamente tem o valor 0 se você usá-las em cálculos). Se esse número mágico não estiver dentro do intervalo de números nos dados reais, os valores mínimo e/ou máximo calculados estarão errados. É melhor inicializar min e max com algum valor encontrado nos dados.
Para acompanharambosvalores mínimo e máximo, você precisa de duas variáveis, e ambas precisam ser verificadas nos dados do arquivo para cada linha, para ver se precisam de atualização.
Como awk
suporta arrays, seria natural usar arrays para min
e max
, com um elemento de array por coluna. Isso é o que fiz no código abaixo.
Generalizado para qualquer número de colunas:
NF == 0 {
# Skip any line that does not have data
next
}
!initialized {
# Initialize the max and min for each column from the
# data on the first line of input that has data.
# Then immediately skip to next line.
nf = NF
for (i = 1; i <= nf; ++i)
max[i] = min[i] = $i
initialized = 1
next
}
{
# Loop over the columns to see if the max and/or min
# values need updating.
for (i = 1; i <= nf; ++i) {
if (max[i] < $i) max[i] = $i
if (min[i] > $i) min[i] = $i
}
}
END {
# Output max and min values for each column.
for (i = 1; i <= nf; ++i)
printf("Column %d: min=%s, max=%s\n", i, min[i], max[i])
}
Dado este script e os dados da pergunta:
$ awk -f script.awk file
Column 1: min=0.0000, max=0.4916
Column 2: min=-24.1254, max=-23.4334
A condição NF == 0
para o primeiro bloco (que é executado para todas as linhas) é garantir que pulamos as linhas em branco. O teste significa "se houver zero campos (colunas) de dados nesta linha". A variável initialized
será zero desde o início (logicamentefalso), mas será definido como um (logicamenteverdadeiro) assim que a primeira linha que contém dados for lida.
A nf
variável é inicializada para NF
(o número de campos) na linha a partir da qual inicializamos os valores min
e max
. Isso ocorre para que a saída do END
bloco funcione mesmo que a última linha tenha zero campos.
Responder2
Na verdade, você pode combinar todas as instruções em um awk
programa:
awk 'NR==1{min1=max1=$1;min2=max2=$2}\
NR>1 {if ($1<min1) {min1=$1} else if ($1>max1) {max1=$1};\
if ($2<min2) {min2=$2} else if ($2>max2) {max2=$2}; }\
END{printf("Column1 min: %f\nColumn1 max: %f\nColumn2 min: %f\nColumn2 max:%f\n",min1,max1,min2,max2)}' file.dat
Isso inicializará os valores mínimo e máximo de ambas as colunas com os respectivos valores da primeira linha (regra com condição NR==1
) e, em seguida, verificará as linhas sucessivas para ver se os valores são maiores que o máximo atual/menores que o mínimo atual, respectivamente (regra com condição NR>1
).
No final do arquivo (regra com condição END
), imprime o resultado.
Perceberque isso pressupõenão há linhas vazias. Se houver, você deverá substituir a NR>1
condição por NR>1 && NF>0
. Se pode haver linhas vaziasantes do primeiro, usar
awk '!init && NF>0 {init=1; min1=max1=$1; min2=max2=$2} \
init==1 && NF>0 {if ($1<min1) {min1=$1} else if ($1>max1) {max1=$1};\
if ($2<min2) {min2=$2} else if ($2>max2) {max2=$2}; }\
END{printf("Column1 min: %f\nColumn1 max: %f\nColumn2 min: %f\nColumn2 max:%f\n",min1,max1,min2,max2)}' file.dat
Isso usará uma variável init
para verificar se uma linha não vazia já foi encontrada e usará o conteúdo da primeira linha não vazia para pré-definir o máximo/mínimo atual para ambas as colunas. Somente se init
estiver definido (após esta inicialização) as linhas (não vazias) serão consideradas para inserir essa estatística.
Como observação geral, você nunca precisa criar cat
um arquivo e canalizar o resultado para awk
.
Responder3
Usandodatamash
e printf
:
for f in 1 2 ; do printf 'Column #%s\nmax - %s\nmin - %s\n\n' $f \
$(datamash -W max $f min $f < file.dat); done
...ou sem loop:
printf 'Column #%s\nmax - %s\nmin - %s\n\n' \
$(datamash -W max 1 min 1 max 2 min 2 < file.dat |
tr -s '\t' '\n' | paste - - | nl)
Saída de:
Column #1
max - 0.4916
min - 0
Column #2
max - -23.4334
min - -24.1254
Responder4
Isto para a coluna 1 (calcula a média máxima e mínima)
sort -n -k 1 file |awk '{SUM+=$1 ; if ( NR == 1) MIN=$1} END{print "Average - "SUM/NR, "Min time - "MIN,"Max Time - "$1}'
isso para a coluna 2
sort -n -k 2 file |awk '{SUM+=$1 ; if ( NR == 1) MIN=$1} END{print "Average - "SUM/NR, "Min time - "MIN,"Max Time - "$1}'