A Assimetria se refere à distribuição desigual dos dados em torno de uma média em uma distribuição de frequências, ou seja, ela representa a falta de correspondência ou equilíbrio entre suas partes, a falta de simetria. Logo abaixo, uma representação de uma distribuição simétrica.

Segundo Martins e Domingues (2014, p. 49), “em uma distribuição simétrica, há igualdade dos valores da média, mediana e moda”. Mas se em uma distribuição de dados estatísticos não tivermos coincidência entre os valores da média aritmética, da mediana e da moda, teremos uma distribuição assimétrica, que pode ser:

  • Distribuição assimétrica negativa ou assimétrica à esquerda:

$$\large \begin{matrix} M > \tilde{x} > \bar{x}\\ \small ou\\ \normalsize M > \tilde{x} > \mu \end{matrix}$$

  • Distribuição assimétrica positiva ou assimétrica à direita:

$$\large \begin{matrix} M < \tilde{x} < \bar{x}\\ \small ou\\ \normalsize M < \tilde{x} < \mu \end{matrix}$$

Para que seja possível determinar o grau de assimetria de uma distribuição de dados, os cálculos mais comumente utilizados são os que fornecem o primeiro e o segundo coeficientes de Pearson.


Fórmulas de Assimetria de Pearson:

1º coeficiente – Utiliza a Moda (M)

$$\normalsize Amostras: \large AS_{P1} = \frac{\bar{x} – M}{s}$$

$$\normalsize Populações: \large AS_{P1} = \frac{\mu – M}{\sigma}$$

2º coeficiente – Utiliza a Mediana ($\color{orangered} \tilde{x}$ ou Med)

$$\normalsize Amostras: \large AS_{P2} = \frac{3 \cdot (\bar{x} – \tilde{x})}{s}$$

$$\normalsize Populações: \large AS_{P2} = \frac{3 \cdot (\mu – \tilde{x})}{\sigma}$$

Sendo:

  • $\bar{x}$: média aritmética amostral
  • $\mu$: média aritmética populacional
  • $s$: desvio padrão amostral
  • $\sigma$: desvio padrão populacional
  • $\tilde{x}$: mediana amostral ou populacional
  • $M$: moda amostral ou populacional

Python :

' 1º coeficiente '

# Descobrindo o valor da média ponderada
m = sum(list(map(lambda x, y: (x*y), valor, freq))) / sum(freq)
# Descobrindo o valor da moda
Moda = list(valor)[freq.index(max(freq))]
# Descobrindo o valor do desvio padrão
s = sum(list(map(lambda x, y: (((x - m)**2)*y) / (sum(freq)), valor, freq)))**0.5
# Calculando o 1º coeficiente de assimetria
Asp1 = (m - Moda) / s

' 2º coeficiente '

# Descobrindo o valor da média ponderada
m = sum(list(map(lambda x, y: (x*y), valor, freq))) / sum(freq)
# Descobrindo o valor da mediana
Med = sorted([x for x, f in dicio.items() for i in range(f)])[sum(dicio.values()) // 2]
# Descobrindo o valor do desvio padrão
s = sum(list(map(lambda x, y: (((x - m)**2)*y) / (sum(freq)), valor, freq)))**0.5
# Calculando o 2º coeficiente de assimetria
Asp2 = 3*(m - Med) / s

Julia :

" 1º coeficiente "

# Descobrindo o valor da média ponderada
m = sum(valor .* freq) / sum(freq)
# Descobrindo o valor da moda
Moda = valor[argmax(freq)]
# Descobrindo o valor do desvio padrão
s = sum(((valor .- m).^2) .* freq / sum(freq))^0.5
# Calculando o 1º coeficiente de assimetria
Asp1 = (m - Moda) / s

" 2º coeficiente "

# Descobrindo o valor da média ponderada
m = sum(valor .* freq) / sum(freq)
# Descobrindo o valor da mediana 
Med = sort([x for (x, y) in zip(valor, freq) for i in 1:y])[floor(Int64, (sum(freq)/2))]
# Descobrindo o valor do desvio padrão
s = sum(((valor .- m).^2) .* freq / sum(freq))^0.5
# Calculando o 2º coeficiente de assimetria
Asp2 = 3 * (m - Med) / s

Atenção!
O primeiro coeficiente de assimetria de Pearson utiliza a moda. Se, em um conjunto de dados, a moda é definida por poucas unidades, ela não é uma boa medida de tendência central e não deve ser usada para calcular assimetria.
Por exemplo:  No conjunto de dados {1, 2, 3, 4, 5, 5} a moda não expressa bem a tendência central. Já no conjunto {1, 2, 3, 3, 3, 3, 3, 3, 4} a moda expressa a tendência central.
Por isso, o segundo coeficiente deve preferencialmente ser usado no cálculo.


Dados agrupados SEM intervalos de classe

Python

dicio = {5:1, 6:7, 7:10, 8:10, 9:2, 10:2, 11:1}
# Criando duas listas contendo os valores e frequências
valor = list(dicio.keys())
freq = list(dicio.values())

m = sum(list(map(lambda x, y: (x*y), valor, freq))) / sum(freq)
Moda = list(valor)[freq.index(max(freq))]
Med = sorted([x for x, f in dicio.items() for i in range(f)])[sum(dicio.values()) // 2]
s = sum(list(map(lambda x, y: (((x - m)**2)*y) / (sum(freq)), valor, freq)))**0.5

prim = (m - Moda) / s
seg = 3*(m - Med) / s

print(f'Asp1 = {prim} / Asp2 = {seg}')

Julia

dicionario = Dict(5=>1, 6=>7, 7=>10, 8=>10, 9=>2, 10=>2, 11=>1)
# Criando duas listas contendo os valores e frequências
valor = collect(keys(dicionario))
freq = collect(values(dicionario))

m = sum(valor .* freq) / sum(freq)
Moda = [k for (k, v) in dicionario if v == maximum(freq)][1]
Med = sort([x for (x, y) in zip(valor, freq) for i in 1:y])[floor(Int64, (sum(freq)/2))]
s = sum(((valor .- m).^2) .* freq / sum(freq))^0.5

Asp1 = (m - Moda) / s
Asp2 = 3 * (m - Med) / s

Dados agrupados COM intervalos de classe

Python

'''Calculando a assimetria de uma série de dados COM intervalos de classe'''

dicio ={'59.0 - 61.5':3,'61.5 - 64.0':5,'64.0 - 66.5':5,'66.5 - 69.0':7,
       '69.0 - 71.5':9,'71.5 - 74.0':11,'74.0 - 76.5':8,'76.5 - 79.0':7,
       '79.0 - 81.5':5,'81.5 - 84.0':6,'84.0 - 86.5':4}

valor = list(map(lambda x: (float(x.split(' - ')[0]) + float(x.split(' - ')[1])) / 2, list(dicio.keys()))) 
freq = list(dicio.values())

dicionario = dict(zip(valor, freq))

# Descobrindo o valor da média
m = sum(list(map(lambda x, y: (x*y), valor, freq))) / sum(freq)
# Descobrindo o valor da moda
Moda = list(valor)[freq.index(max(freq))]
# Descobrindo o valor da mediana
Med = sorted([x for x, f in dicionario.items() for i in range(f)])[sum(dicionario.values()) // 2]
# Descobrindo o valor do desvio padrão
s = sum(list(map(lambda x, y: (((x - m)**2)*y) / (sum(freq)), valor, freq)))**0.5

prim = (m - Moda) / s
seg = 3*(m - Med) / s

print(f'Asp1 = {prim} / Asp2 = {seg}')

Julia

" Calculando a assimetria de uma série de dados COM intervalos de classe "

dicio = Dict("59.0 - 61.5"=>3,"61.5 - 64.0"=>5,"64.0 - 66.5"=>5,"66.5 - 69.0"=>7,"69.0 - 71.5"=>9,"71.5 - 74.0"=>11, "74.0 - 76.5"=>8,"76.5 - 79.0"=>7,"79.0 - 81.5"=>5,"81.5 - 84.0"=>6,"84.0 - 86.5"=>4)

# Ordenando os valores pela ordem do dicionario
dicio = sort(collect(dicio))

# valores médio de cada intervalo de classe
valor = map(x -> (parse(Float64, split(x[1], " - ")[1]) + parse(Float64, split(x[1], " - ")[2]))/2, dicio)

# frequência de cada intervalo de classe
freq = [par.second for par in dicio]
# Descobrindo o valor da média
m = sum(valor .* freq) / sum(freq)
# Descobrindo o valor da moda
Moda = valor[argmax(freq)]
# Descobrindo o valor da mediana
Med = sort([x for (x, y) in zip(valor, freq) for i in 1:y])[floor(Int64, (sum(freq)/2))]
# Descobrindo o valor do desvio padrão
s = s = sum((valor .-m).^2 .* freq / sum(freq))^0.5

prim = (m - Moda) / s
seg = 3*(m - Med) / s

println("Asp1 = $prim / Asp2 = $segn")

Outro exemplo

" Calculando a assimetria de uma série de dados COM intervalos de classe, usando DataStructures "

using DataStructures

dicio = OrderedDict("59.0 - 61.5"=>3,"61.5 - 64.0"=>5,"64.0 - 66.5"=>5,"66.5 - 69.0"=>7,"69.0 - 71.5"=>9,"71.5 - 74.0"=>11, "74.0 - 76.5"=>8,"76.5 - 79.0"=>7,"79.0 - 81.5"=>5,"81.5 - 84.0"=>6,"84.0 - 86.5"=>4)

# valores médio de cada intervalo de classe
valor = map(x -> (parse(Float64, split(x, " - ")[1]) + parse(Float64, split(x, " - ")[2])) / 2, collect(keys(dicio)))

# frequência de cada intervalo de classe
freq = collect(values(dicio))

# Descobrindo o valor da média
m = sum(valor .* freq) / sum(freq)
# Descobrindo o valor da moda
Moda = valor[argmax(freq)]
# Descobrindo o valor da mediana
Med = sort([x for (x, y) in zip(valor, freq) for i in 1:y])[floor(Int64, (sum(freq)/2))]
# Descobrindo o valor do desvio padrão
s = s = sum((valor .-m).^2 .* freq / sum(freq))^0.5

prim = (m - Moda) / s
seg = 3*(m - Med) / s

println("Asp1 = $prim / Asp2 = $segn")

# RESPOSTA: Asp1 = 0.04221297937335779 / Asp2 = 0.12663893812007337

Dependendo do resultado do cálculo, classificamos a distribuição de dados conforme o estabelecido a seguir:

ClassificaçãoDescrição
AS = 0Distribuição simétrica
0 < As < 1Distribuição assimétrica positiva fraca
As ≥ 1Distribuição assimétrica positiva forte
-1 < As < 0Distribuição assimétrica negativa fraca
As ≤ -1Distribuição assimétrica negativa forte

Importante !
Quando não pudermos determinar o valor do desvio padrão, seja ele amostral ou populacional, não utilizaremos os coeficientes de Pearson para indicar o grau de assimetria dos dados.
Existem outras formas de se calcular o grau de assimetria. Uma alternativa é usarmos o cálculo do Coeficiente Quartílico de Assimetria (CQA) ou Fórmula de Bowley, que é:



Fórmula do Coeficiente Quartílico de Assimetria de Bowley:

$$\begin{matrix} CQA = \dfrac{Q_{3}-2 \cdot Q_{2}+Q_{1}}{Q_{3}-Q_{1}}\\ ou\\ CQA = \dfrac{(Q_{3}-Q_{2})-(Q_{2}-Q_{1})}{Q_{3}-Q_{1}} \end{matrix}$$

Sendo:

  • Q1: 1º quartil
  • Q2: 2º quartil
  • Q3: 3º quartil

Python / Julia :

CQA = (Q3-2*Q2+Q1) / (Q3-Q1)

Esta fórmula é mais sensível a valores extremos do que outras medidas de assimetria.


Python

# Calculando a assimetria de uma série de dados SEM intervalos de classe

dicio = {5:1, 6:7, 7:10, 8:10, 9:2, 10:2, 11:1}

# total da frequência
N = sum(list(dicio.values()))
# Frequência acumulada
fa = list(map(lambda x: sum(list(dicio.values())[:x + 1]), range(len(list(dicio.values())))))
lista = []

for n in [1,2,3]:
    pn = (n * (N + 1)) / 4
    if pn % 2 != 0:
        PD = pn - int(pn)
        trunc = int(pn)
    else:
        PD = 0
        trunc = pn
    posit_1 = list(filter(lambda x: x >= trunc, fa))[0]
    posit_2 = list(filter(lambda x: x >= trunc+1, fa))[0]
    VP = list(dicio.keys())[fa.index(posit_1)]
    VP1 = list(dicio.keys())[fa.index(posit_2)]

    Q = VP + PD * (VP1 - VP)
    lista.append(Q)

Q1 = lista[0]
Q2 = lista[1]
Q3 = lista[2]

CQA = (Q3-2*Q2+Q1) / (Q3-Q1)

print(CQA)

# Calculando a assimetria de uma série de dados COM intervalos de classe

dicionario ={'59.0 - 61.5':3,'61.5 - 64.0':5,'64.0 - 66.5':5,'66.5 - 69.0':7,
       '69.0 - 71.5':9,'71.5 - 74.0':11,'74.0 - 76.5':8,'76.5 - 79.0':7,
       '79.0 - 81.5':5,'81.5 - 84.0':6,'84.0 - 86.5':4}

lista = list(dicionario.values())
fa = list(map(lambda x: sum(lista[:x+1]), range(len(lista))))
val = []

for n in [1,2,3]:
    pn = (n * sum(list(dicionario.values()))) / 4
    num = list(filter(lambda x: x >= pn, fa))[0]
    interval = list(dicionario.keys())[fa.index(list(filter(lambda x: x == num, fa))[0])]
    li = float(interval.split(' - ')[0])
    h = float(interval.split(' - ')[1]) - float(interval.split(' - ')[0])
    m = list(filter(lambda x: x < pn, fa))[-1]
    fm = dicionario.get(interval)
    Q = li + ((h * (pn - m))/fm)
    val.append(Q)

Q1 = val[0]
Q2 = val[1]
Q3 = val[2]

CQA = (Q3-2*Q2+Q1) / (Q3-Q1)

print(CQA)

Julia

# Calculando a assimetria de uma série de dados SEM intervalos de classe

dicio = Dict(5=>1, 6=>7, 7=>10, 8=>10, 9=>2, 10=>2, 11=>1)

# Corrigindo a ordem das frequências de um dicionário e salvando uma variável
indices_e_valores = collect(enumerate(dicio))
indices_e_valores_ordenados = sort(indices_e_valores, by=x -> x[2])
indices = [indice for (indice, valor) in indices_e_valores_ordenados]
valor = map(y -> collect(keys(dicio))[y], indices)
freq = map(y -> collect(values(dicio))[y], indices)

# Frequência acumulada
fa = cumsum(freq)
# total da frequência
N = sum(freq)
valores = []

for n in [1,2,3]
    pn = n * (N + 1) / 4

    PD = pn % 2 != 0 ? pn - floor(Int64, pn) : 0
    trunc = pn % 2 != 0 ? floor(Int64, pn) : pn

    posit_1 = fa[findfirst(x -> x == 1, fa .>= trunc)]
    posit_2 = fa[findfirst(x -> x == 1, fa .>= trunc+1)]
    VP = valor[findfirst(x -> x == posit_1, fa)]
    VP1 = valor[findfirst(x -> x == posit_2, fa)]

    Q = VP + PD * (VP1 - VP)
    push!(valores, Q)
end

Q1 = valores[1]
Q2 = valores[2]
Q3 = valores[3]

CQA = (Q3-2*Q2+Q1) / (Q3-Q1)

Fórmula do Coeficiente de assimetria de Pearson ou O momento de terceira ordem padronizado:

$$\large As = \dfrac{\sum(x_{i}-\bar{x})^3}{(n-1) \cdot s^3}$$

Sendo:

  • $x_{i}$: Representa cada valor individual em seu conjunto de dados.
  • $\bar{x}$: A média aritmética dos valores do conjunto de dados.
  • $\sum(x_{i} – \bar{x})^3$: A soma de todas as diferenças elevadas ao cubo para cada $x_{i}$.
  • $n$: O número total de observações no conjunto de dados.
  • $s$: O desvio padrão da amostra, que é a medida da dispersão dos dados em torno da média.
  • $(n-1)$: O número de graus de liberdade do conjunto de dados.

Python :

As = sum(list(map(lambda x: (x - m)**3, lista))) / ((n-1) * s**3)

Julia :

As = sum(((valor .- m).^3) .* freq) / ((n-1) * s^3)

Exemplos

Python

dicio = {5:1, 6:7, 7:10, 8:10, 9:2, 10:2, 11:1}
valor = list(dicio.keys())
freq = list(dicio.values())

m = sum(list(map(lambda x, y: (x*y), valor, freq))) / sum(freq)
n = sum(freq)
s = sum(list(map(lambda x, y: (((x - m)**2)*y) / (sum(freq)-1), valor, freq)))**0.5

As = sum(list(map(lambda x, y: ((x - m)**3)*y, valor, freq))) / ((n-1) * s**3)

print(As)

Julia

valor = [5, 6, 7, 8, 9, 10, 11]
freq = [1, 7, 10, 10, 2, 2, 1]

n = sum(freq)
m = sum(valor .* freq) / n
s = (sum((valor .- m).^2 .* freq) / (n-1))^0.5

As = sum(((valor .- m).^3) .* freq) / ((n-1) * s^3)

Fórmula do Coeficiente de assimetria de Fisher:

$$\large As = \dfrac{\dfrac{\sum_{i=1}^{n}(x_{i}-\bar{x})^3}{n}}{\Bigg(\dfrac{\sum_{i=1}^{n}(x_{i}-\bar{x})^2}{n-1}\Bigg)^{3/2}}$$

Sendo:

  • $x_{i}$: Representa cada valor individual em seu conjunto de dados.
  • $\bar{x}$: A média aritmética dos valores do conjunto de dados.
  • $\sum(x_{i} – \bar{x})^3$: A soma de todas as diferenças elevadas ao cubo para cada $x_{i}$.
  • $n$: O número total de observações no conjunto de dados.
  • $s$: O desvio padrão da amostra, que é a medida da dispersão dos dados em torno da média.
  • $(n-1)$: O número de graus de liberdade do conjunto de dados.

Python :

As = (sum(list(map(lambda x: (x-m)**3, lista))) / n) / (sum(list(map(lambda x: (x-m)**2, lista))) / (n-1))**(3/2)

Julia :

As = (sum(((valor .- m).^3) .* freq) / n) / (sum(((valor .- m).^2) .* freq) / (n-1))^(3/2)

Exemplo

Python

dicio = {5:1, 6:7, 7:10, 8:10, 9:2, 10:2, 11:1}
valor = list(dicio.keys())
freq = list(dicio.values())

m = sum(list(map(lambda x, y: (x*y), valor, freq))) / sum(freq)
n = sum(freq)
s = sum(list(map(lambda x, y: (((x - m)**2)*y) / (sum(freq)), valor, freq)))**0.5

As = (sum(list(map(lambda x, y: ((x-m)**3)*y, valor, freq))) / n) / (sum(list(map(lambda x, y: ((x-m)**2)*y, valor, freq))) / (n-1))**(3/2)

print(As)

Julia

valor = [5, 6, 7, 8, 9, 10, 11]
freq = [1, 7, 10, 10, 2, 2, 1]

n = sum(freq)
m = sum(valor .* freq) / n
s = (sum((valor .- m).^2 .* freq) / (n-1))^0.5

As = (sum(((valor .- m).^3) .* freq) / n) / (sum(((valor .- m).^2) .* freq) / (n-1))^(3/2)

Fórmula do Coeficiente de assimetria de Fisher-Pearson:


Fórmula que entrega um resultado semelhante à função skew da biblioteca Scipy, no Python, e à função skewness da biblioteca StatsBase, em Julia.

$$\begin{matrix} \large As = \frac{\frac{1}{n} \sum_{i=1}^{n}(x_{i} – \bar{x})^3}{\bigg(\sqrt{\frac{1}{n} \sum_{i=1}^{n}(x_{i} – \bar{x})^2}\bigg)^3} \\ \small ou\\ \large As = \frac{m_{3}}{(\sqrt{m_{2}})^3} \end{matrix}$$

Sendo:

  • $x_{i}$: Representa cada valor individual em seu conjunto de dados.
  • $\bar{x}$: A média aritmética dos valores do conjunto de dados.
  • $n$: O número total de observações no conjunto de dados.
  • $s$: O desvio padrão da amostra, que é a medida da dispersão dos dados em torno da média.

Python :

As = ((1/n) * (sum(list(map(lambda x: (x-m)**3, lista))))) / ((((1/n) *(sum(list(map(lambda x: (x-m)**2, lista)))))**0.5)**3)

Julia :

As = (1/n) * (sum(((valor .- m).^3) .* freq)) / (((1/n) * (sum(((valor .- m).^2) .* freq)))^0.5)^3

Libs:

Linguagem Biblioteca Função
Python Scipy.stats sc.skew(values)
Julia StatsBase skewness(values)

Exemplos

Python

''' Utilizando somente o Python '''

dicio = {5:1, 6:7, 7:10, 8:10, 9:2, 10:2, 11:1}
valor = list(dicio.keys())
freq = list(dicio.values())

m = sum(list(map(lambda x, y: (x*y), valor, freq))) / sum(freq)
n = sum(freq)

As = ((1/n) * (sum(list(map(lambda x, y: ((x-m)**3)*y, valor, freq))))) / ((((1/n) *(sum(list(map(lambda x, y: ((x-m)**2)*y, valor, freq)))))**0.5)**3)

print(As)

''' Utilizando a função Skew da Biblioteca Scipy '''

import scipy.stats as sc

dicio = {5:1, 6:7, 7:10, 8:10, 9:2, 10:2, 11:1}
lista = list(k for k, v in dicio.items() for _ in range(v))

As = sc.skew(lista)

print(As)

Julia

valor = [5, 6, 7, 8, 9, 10, 11]
freq = [1, 7, 10, 10, 2, 2, 1]

n = sum(freq)
m = sum(valor .* freq) / n
s = (sum((valor .- m).^2 .* freq) / (n-1))^0.5

As = (1/n) * (sum(((valor .- m).^3) .* freq)) / (((1/n) * (sum(((valor .- m).^2) .* freq)))^0.5)^3

Fórmula do Coeficiente padronizado de assimetria de Fisher-Pearson:

$$As = \frac{n}{(n-1)(n-2)} \sum \bigg(\frac{x_{i}-\bar{x}}{s}\bigg)^3$$

Sendo:

  • $x_{i}$: Representa cada valor individual em seu conjunto de dados.
  • $\bar{x}$: A média aritmética dos valores do conjunto de dados.
  • $n$: O número total de observações no conjunto de dados.
  • $s$: O desvio padrão da amostra, que é a medida da dispersão dos dados em torno da média.

Python :

As = (n / ((n-1)*(n-2))) * sum(list(map(lambda x: ((x-m)/s)**3, lista)))

Julia :

As = n / ((n-1) * (n-2)) * sum(((valor .- m) ./ s).^3)

Esta é a fórmula que atualmente é utilizada no Excel / Calc, onde a assimetria é encontrada com a função = DISTORÇÃO(inicial, final)


Libs:

Linguagem Biblioteca Função
Python Pandas df.skew()

Exemplos

Python

dicio = {5:1, 6:7, 7:10, 8:10, 9:2, 10:2, 11:1}
lista = list(k for k, v in dicio.items() for _ in range(v))

m = sum(lista) / len(lista)
n = len(lista)
s = sum(list(map(lambda x: ((x - m)**2) / (n-1), lista)))**0.5

As = (n / ((n-1)*(n-2))) * sum(list(map(lambda x: ((x-m)/s)**3, lista)))

print(As)

Julia

dicio = Dict(5=>1, 6=>7, 7=>10, 8=>10, 9=>2, 10=>2, 11=>1)
valor = [k for (k,v) in dicio for _ in 1:v]

n = length(valor)
m = sum(valor) / n
s = (sum((valor .- m).^2) / (n-1))^0.5

As = n / ((n-1) * (n-2)) * sum(((valor .- m) ./ s).^3)