Agradeço o código user78605
que forneceu, pois ele me orientou sobre como encontrar a mediana em minhas consultas. O código acima mencionado, no entanto, ignora certas condições que são necessárias para calcular a mediana corretamente.
Problemas:
- As linhas finais em branco (se existirem no arquivo) não devem ser contadas, pois contá-las afeta o tamanho dos dados e, portanto, a média, a mediana, o modo e outras quantidades estatísticas. O mesmo provavelmente deve ser feito para as linhas que não possuem valores numéricos (id est:
"abc"
, "28b"
, "h2f"
, ""
e et cetera).
- A mediana é o valor médio de não o conjunto de dados original, mas um conjunto de dados ordenado. Ou seja, os dados para os quais a mediana deve ser encontrada devem ser classificados primeiro.
- Se a quantidade de valores em um conjunto de dados ordenado for par, a média dos dois valores intermediários deve ser tomada.
- O modo é um valor com a maior frequência. É possível que o conjunto de dados tenha mais de um modo, em cujo caso dois ou mais valores precisam ser listados como modo.
A seguir, minha expansão do código, levando em conta as condições mencionadas acima:
awk -F',' '
{col=$1}{if((col ~ /^-?[0-9]*([.][0-9]+)?$/) && ($0!=""))
{
sum+=col;
a[x++]=col;
b[col]++
if(b[col]>hf){hf=b[col]}
}
}
END{n = asort(a);idx=int((x+1)/2)
print "Mean: " sum/x
print "Median: " ((idx==(x+1)/2) ? a[idx] : (a[idx]+a[idx+1])/2)
for (i in b){if(b[i]==hf){(k=="") ? (k=i):(k=k FS i)}{FS=","}}
print "Mode: " k
}' file
EXPLICAÇÃO:
Solução para o problema nº 1:
col=$1
#easier to change columns if stored in a variable.
(col ~ /^-?[0-9]*([.][0-9]+)?$/)
#The string must only comprise numerals, a period (decimal separator), or a dash (minus sign). [Only the scientific notation is overlooked.]
($0!="")
#the entire row must not be blank.
Nas linhas elegíveis, execute as seguintes operações de loop:
sum+=col
#(Short for sum=sum+col
.) Sum of all values.
a[x++]=col
#Every value is stored into an array.
b[col]++
#Values in col
are treated as surrogate keys of array b
. Hence there are only as many elements in b
as the number of unique values in col
. This iterator creates an array of frequency counts. (Short for b[col]=b[col]+1
.)
if(b[col]>hf){hf=b[col]}
#Let hf
stand for "the highest frequency". Loop through all the frequencies and update hf
only if higher frequencies are found. hf
is initially "" (nothing).
Solução para o problema nº 2:
Depois que as operações de loop forem concluídas:
Sort the values stored in the array: n = asort(a)
It is important to note that the original indices of array a
ranged from "0" to "x-1". In addition to sorting, the new index range is from "1" to "x". This is why I use int((x+1)/2)
instead of
int((x-1)/2)
as the index which holds the median - or the smaller of the two numbers which will be averaged out to a median.
Solução para o problema nº 3:
((idx == (x+1)/2) ? a[idx] : (a[idx]+a[idx+1])/2)
This is a shorthand notation for an if-else construction:
If int((x+1)/2)
equals (x+1)/2
then the number of values is odd, and the median will be a[idx]
. If this is not so, int()
will round down (x+1)/2
to the nearest integer signifying that the number of values is even. In this case, the average of a[idx]
and a[idx]+1
will be the median.
Solução para o problema nº 4:
for (i in b) {if(b[i]==hf){(k=="") ? (k=i):(k=k FS i)}{FS=","}}
Since hf
is the value which represents the highest frequency in the data set, if any value of b is equal to hf
, its surrogate key is the mode, or at least one of the modes.
This code concatenates all surrogate keys, i
, which match the criterion and stores them into a variable, k
, that can be printed on one row with the title "Mode".
Outros ajustes:
-F
deve ser ajustado de acordo com o caractere que estiver sendo usado como separador de coluna no arquivo.
Se o arquivo tiver cabeçalhos na primeira linha, adicione NR > 1
na frente de {col=$1}
.
FS
foi usado para concatenar duas variáveis juntas. O uso de FS
é especialmente útil quando se escolhe não usar o separador. Isto é, FS=""
.
Dados
Os seguintes dados foram usados para experimentação para criar o script:
10
20
10
20.5
50
30
40
50
10
30
20.5
-h
h
4.35
-537
0
-0
30
d
.
RESULTADOS:
Mean: -13.2281
Median: 20.25
Mode: 10,30