import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
import pyspark.sql.functions as F
df = pd.read_csv('dados/dados_tratados.csv').drop('Unnamed: 0', axis=1)
df_spark = spark.read.format("csv").option("header","true").load('dados/dados_tratados.csv')
df_spark.createOrReplaceTempView('df_sql')
df.head()
ano_trabalho | nivel_experiencia | tipo_de_contrato | cargo | salario | moeda_salario | salario_em_dolares | pais_residencia | tipo_trabalho | local_companhia | tamanho_companhia | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2023 | Senior/Especialista | Tempo integral | Principal Data Scientist | 80000 | EUR | 85847 | ES | Home office | ES | Grande |
1 | 2023 | Pleno | Contrato | ML Engineer | 30000 | USD | 30000 | US | Home office | US | Pequeno |
2 | 2023 | Pleno | Contrato | ML Engineer | 25500 | USD | 25500 | US | Home office | US | Pequeno |
3 | 2023 | Senior/Especialista | Tempo integral | Data Scientist | 175000 | USD | 175000 | CA | Home office | CA | Medio |
4 | 2023 | Senior/Especialista | Tempo integral | Data Scientist | 120000 | USD | 120000 | CA | Home office | CA | Medio |
Uma distribuição de frequência é uma tabela que devolve todos os valores com suas respectivas frequências.
Exemplo: Numa empresa há 5 funcionários com os seguintes salários (em R$): 2000,00; 5030,00; 2588,00; 4005,00; 2900,00
Salário (em R$) | Frequência observada | Frequência Relativa (\%) | Frequência Acumulada |
---|---|---|---|
2000,00 ⊢ 3000,00 | 3 | 60 | 60 |
3000,00 ⊢ 4000,00 | 0 | 60 | 60 |
4000,00 ⊢ 5000,00 | 1 | 20 | 80 |
Acima de 5000,00 | 1 | 20 | 100 |
Total | 5 | 100 |
Onde:
OBS.:
⊢
significa que o intervalo compreende o valor da esquerda, mas não o da direita
Ex.: 2000,00 ⊢ 3000,00: Salários iguais ou maiores que 2000,00 e menores que 3000,00
tabela_frequencia = df[['nivel_experiencia', 'salario']].groupby('nivel_experiencia').agg({'salario': 'count'})
tabela_frequencia.columns = ['frequencia_observada']
tabela_frequencia['frequencia_relativa'] = tabela_frequencia['frequencia_observada'] / tabela_frequencia['frequencia_observada'].sum()
tabela_frequencia["frequencia_acumulada"] = tabela_frequencia["frequencia_relativa"].cumsum()
tabela_frequencia
frequencia_observada | frequencia_relativa | frequencia_acumulada | |
---|---|---|---|
nivel_experiencia | |||
Diretor | 114 | 0.030360 | 0.030360 |
Junior | 320 | 0.085220 | 0.115579 |
Pleno | 805 | 0.214381 | 0.329960 |
Senior/Especialista | 2516 | 0.670040 | 1.000000 |
Média Aritmética é a soma das observações dividida pela quantidade de observações.
$$\overline{x} = \frac{x_1 + x_2 + \cdot\cdot\cdot + x_n}{n} = \frac{1}{n}\sum_{i = 1}^{n}x_i$$Essa medida de tendência central não é útil se na amostra existirem valores discrepantes (outliers)
Exemplo: Temos na mesma equipe 4 funcionários, com salários de 5000,00 reais; 4000,00 reais; 4500,00 reais; e 25000,00 reais.
A média é: $$\overline{x} = \frac{5000 + 4000 + 4500 + 25000}{4} = \text{R\$} 9625,00$$
Esse salário médio é puxado pra cima por causa do salário discrepante de R$ 25.000,00.
Vamos ver como usar essa medida no Python.
media = (5000 + 4000 + 4500 + 25000) / 4
media
9625.0
# criando uma função na mão para calcular media
def media(valores):
return sum(valores) / len(valores)
lista = [5000, 4000, 4500, 25000]
media(lista)
9625.0
# para o nosso conjunto de dados
media(df['salario'])
190695.57177097205
# com pandas
df['salario'].mean()
190695.57177097205
# com pyspark
df_spark.select(F.mean('salario')).show()
+------------------+ | avg(salario)| +------------------+ |190695.57177097205| +------------------+
# no pyspark, uma forma de melhorar o nome da coluna que sai é usando o comando alias
df_spark.select(F.mean('salario').alias('media do salário')).show()
+------------------+ | media do salário| +------------------+ |190695.57177097205| +------------------+
# com sql
spark.sql('SELECT AVG(SALARIO) AS MEDIA_SALARIO FROM df_sql').show()
+------------------+ | MEDIA_SALARIO| +------------------+ |190695.57177097205| +------------------+
A média ponderada é uma média que recebe um valor que será multiplicado para cada observação, chamado de peso, que dará um determinado nível de importância para a observação.
Sua fórmula é: $$\overline{x}_p = \frac{\sum_{i = 1}^{n} \omega_i x_i}{\sum_{i = 1}^{n} \omega_i}$$
onde $\omega$ é o peso da observação.
Exemplo: Uma empresa quer saber qual sua média salarial. Sabe-se que há três cargos na empresa, que são:
Cargo | Quantidade de funcionário | Salario |
---|---|---|
Assistente Administrativo | 12 | 2500,00 |
Contador | 5 | 5000,00 |
Gerente | 1 | 8000,00 |
Qual a média salarial da empresa:
$$\overline{x}_p = \frac{(12 \cdot 2500) + (5 \cdot 5000) + (1 \cdot 8000}{12 + 5 + 1} = \frac{63000}{18} = \text{R\$}3500,00$$O salário médio da empresa é R$ 3500,00
Vamos ver como ficaria no Python
df_media_ponderada = (df[['nivel_experiencia', 'salario_em_dolares', 'salario']]
.groupby('nivel_experiencia')
.agg({'salario_em_dolares': 'mean',
'salario': 'count'})
.reset_index())
df_media_ponderada.columns = ['nivel_experiencia', 'media_salario', 'quantidade']
df_media_ponderada_spark = spark.createDataFrame(df_media_ponderada)
df_media_ponderada_spark.createOrReplaceTempView('df_media_ponderada_sql')
# na mão
def media_ponderada(df, valores, pesos):
return sum(df[valores] * df[pesos]) / df[pesos].sum()
media_ponderada(df_media_ponderada, 'media_salario', 'quantidade')
137570.38988015978
# com numpy
np.average(a=df_media_ponderada['media_salario'],
weights=df_media_ponderada['quantidade'])
137570.38988015978
# com spark
df_media_ponderada_spark.select(F.expr('SUM(media_salario * quantidade) / SUM(quantidade)').alias('media_ponderada')).show()
+------------------+ | media_ponderada| +------------------+ |137570.38988015978| +------------------+
# com sql
spark.sql('SELECT SUM(media_salario * quantidade) / SUM(quantidade) AS media_ponderada FROM df_media_ponderada_sql').show()
+------------------+ | media_ponderada| +------------------+ |137570.38988015978| +------------------+
A média geométrica é definida, para o conjunto de números positivos, como a raiz $n$-ésima do produto de $n$ elementos de um conjunto de dados. A propriedade principal dessa média é preservar o produto dos elementos de um conjunto de dados.
Sua fórmula é: $$G = (\prod^{n}_{i=1}x_i)^{1/n} =\sqrt[n]{x_1 x_2 \cdot \cdot \cdot x_n }$$
Uma das principais aplicações da média geométrica é nos cálculos que englobam taxas de crescimento (proporcionais, variados e exponenciais), ou seja, valores que passam por sucessivos aumentos ou permanecem de forma contínua.
Exemplo: O preço do kg do arroz sofreu aumentos sucessivos nos últimos 4 meses de 10%, 15%, 8% e 40%. Qual foi o aumento médio percentual nesse período?
$$G = \sqrt[n]{x_1 x_2 \cdot \cdot \cdot x_n }$$$$G = \sqrt[4]{10 \cdot 15 \cdot 8 \cdot 40}$$$$G = \sqrt[4]{4800}$$$$G = 14,8\text{%} $$#def media_geometrica(df, coluna):
# multiplicacao = 1
# contador = 0
# valores = list(df[coluna].values)
# n = len(valores)
# for valor in valores:
# multiplicacao = multiplicacao * valor
# return multiplicacao ** (1/n)
df_geometrica = df.iloc[0:10]
lista = list(df_geometrica['salario'].values)
multiplicacao = 1
# por algum motivo quando passamos no dataframe da erro, tanto na função como em for simples
for valor in [80000, 30000, 25500, 175000, 120000, 222200, 136000, 219000, 141000, 147100]:
multiplicacao = multiplicacao * valor
print(f'Média geométrica: {multiplicacao ** (1/len(df_geometrica.salario.values))}')
Média geométrica: 105840.76202833292
# com scipy
stats.gmean(df_geometrica['salario'])
105840.76202833273
A mediana é o valor que ocupa a posição central da série de observações, quando estão ordenadas em ordem crescente.
$$\text{mediana(x)} = \begin{cases} x_{(\frac{n+1}{2})},\text{se n ímpar}\\ \frac{x_{\frac{n}{2}} + x_{\frac{n}{2}+1}}{2}, \text{se n par} \end{cases}$$Essa medida de tendência central é bastante útil se tivermos na amostra outliers, pois a mediana é robusta para esses casos.
def mediana(valores):
ordem = sorted(list(valores))
if len(ordem) % 2 == 0:
meio = int(np.floor(len(ordem) / 2) - 1)
meio1 = meio + 1
mediana = (ordem[meio] + ordem[meio1]) / 2
else:
meio = int(np.floor(len(ordem) / 2))
mediana = ordem[meio]
return mediana
mediana(df['salario'])
138000
# com pandas
df['salario'].median()
138000.0
A moda é o valor que ocorre com maior frequência (aparece mais vezes na amostra). Em alguns casos pode haver mais de uma moda. Se for duas observações, será bimodal, três, trimodal e assim por diante.
Exemplo: Temos os seguintes dados : [1, 2, 3, 3, 4, 3, 5, 6, 7]
Nossa moda é o 3, que aparece três vezes na amostra.
# com pandas
df['salario'].mode()
0 100000 Name: salario, dtype: int64
É a média dos desvios dos valores a contar da média, colocando os valores em módulo para evitar um possível resultado igual a zero.
$$\text{DMA(x)} = \frac{\sum_{i=1}^{n}|{x_i - \overline{x}}|}{n} $$Exemplo: Um aluno fez três provas ao longo do ano, tirando respectivamente 8, 4 e 9. Qual é o desvio médio absoluto de suas notas?
primeiro precisamos achar a média
$\overline{x} = \frac{8 + 4 + 9}{3} = \frac{21}{3} = 7$
$\text{DMA(x)} = \frac{|8 - 7| + |4 - 7| + |9 - 7|}{3} = \frac{6}{3} = 2 $
# em python
def dma(valores):
media = sum(valores) / len(valores)
return sum(np.abs(valores - media))/ len(valores)
dma(df['salario'])
116197.07271554231
# usando pandas
df['salario'].mad()
116197.07271554231
A variância é determinada pela média dos quadrados dos desvios em relação a média aritmética. Por meio dessa medida, podemos avaliar o quanto os dados estão dispersos em relação à média aritmética. Logo, quanto maior for a variância, maior a dispersão dos dados.
fórmula:
$$var(X) = s²=\frac{\sum_{i = 1}^{n} (x_i - \overline{x})²}{n - 1}$$Uma dificuldade de trabalhar com a variância é que ela nos devolve a unidade ao quadrado, sendo difícil de observar quanto os dados estão dispersos.
# na mão
def variancia(valores):
media = sum(valores) / len(valores)
return sum((valores - media)**2)/ (len(valores) - 1)
variancia(df['salario'])
451149321334.5485
# no pandas
df['salario'].var()
451149321334.5485
De forma a melhorar a compreensão da dispersão dos dados, temos o desvio padrão, que é a raiz quadrada da variância. Dessa forma, o desvio padrão é capaz de apontar com maior precisão a dispersão dos valores em relação à média aritmética.
Fórmula:
$$dp(X) = \sqrt{var(X)} = \sqrt{\sigma²}$$$$dp(X)= \sigma = \sqrt{\frac{\sum_{i = 1}^{n} (x_i - \overline{x})²}{n - 1}}$$# na mão
def desvio_padrao(valores):
media = sum(valores) / len(valores)
return np.sqrt(sum((valores - media)**2)/ (len(valores) - 1))
desvio_padrao(df['salario'])
671676.5005079071
# no pandas
df['salario'].std()
671676.5005079071
Segundo Bussab e Morettin (2010) tanto a média como o desvio padrão podem não ser medidas adequadas para representar um conjunto de dados, pois:
Uma medida que pode ser considerada no lugar é o quantil.
Podemo definir uma medida, chamada quantil de ordem p ou p-quantil, indicada por q(p) onde p é uma proporção qualquer, $0 < p < 1$, tal que 100p% das observações sejam menores do que q(p). Os quantis mais famosos são os que veremos no box plots, que são:
$$\text{q(0,25)} = q_1 \text{: 1º Quartil = 25º Percentil} $$$$\text{q(0,50)} = q_2 \text{: Mediana = 2º Quartil = 50º Percentil} $$$$\text{q(0,75)} = q_3 \text{: 3º Quartil = 75º Percentil} $$Mostraremos como se calcula com um exemplo:
Exemplo: Temos o seguinte conjunto de valores: $10, 25, 23, 34, 8, 2, 7$
1º Passo: colocar os valores em ordem crescente: $2, 7, 8, 10, 23, 25, 34$
2º Passo: Achar a mediana (2º Quartil) dos valores. Como os valores são impares, a mediana será dada por $x_{\frac{n+1}{2}}$. Como $n$ é 7, $n+1$ será 8, $\frac{8}{2}=4$. Queremos o valor que está na posição 4, que em nosso caso é o 10.
3º Achando a mediana, agora temos dois conjuntos de dados, um abaixo da mediana e um acima. O conjunto abaixo é: $2, 7, 8$. E o acima é: $23, 25, 34$. Agora devemos achar a mediana de cada conjunto para acharmos o 1º e o 3º quartil respectivamente. Com isso temos que o 1º Quartil é 7 e o 3º Quartil é 25.
Quando o conjunto de valores tiver um n de tamanho par, usamos o cálculo da mediana quando n for par, que é dado por $\frac{x_{\frac{n}{2}} + x_{\frac{n}{2}+1}}{2}$
Exemplo: Temos o seguinte conjunto de valores: $10, 25, 23, 34, 8, 2, 7, 40$
1º Passo: colocar os valores em ordem crescente: $2, 7, 8, 10, 23, 25, 34, 40$
2º Passo: Achar a mediana (2º Quartil) dos valores. Como os valores são pares, a mediana será dada por $x_{\frac{n}{2}} + x_{\frac{n}{2}+1}$. Como $n$ é 8, os valores serão 4 e 5. Queremos os valores que estão na posição 4 e 5, que em nosso caso são os valores 10 e 23. Calculando a mediana deles temos: $\frac{10 + 23}{2} = 16,5$
4º Achando a mediana, agora temos dois conjuntos de dados, um abaixo da mediana e um acima. O conjunto abaixo é: $2, 7, 8, 10$. E o acima é: $23, 25, 34, 40$. Agora devemos achar a mediana de cada conjunto para acharmos o 1º e o 3º quartil respectivamente. Com isso temos que o 1º Quartil é 7,5 e o 3º Quartil é 29,5.
Um segundo método de achar os quartis é pela formula: $$Q_j = x_k + (\frac{j(n+1)}{4}-k)(x_{k+1}-x_k)$$ Onde:
Pegaremos o primeiro exemplo para usar a fórmula:
Valores: $10,25,23,34,8,2,7$
Valores ordenados: $2, 7, 8, 10, 23, 25, 34$
Vamos calcular o primeiro quartil:
sabemos que $\frac{j(n+1)}{4} = \frac{1(7+1)}{4} = \frac{8}{4} = 2$
Logo $k$ será igual a $2$. Substituindo na equação temos
$Q_1 = x_2 + (2-2)(x_{2+1}-x_2)$
$Q_1 = x_2 + (0)(x_{3}-x_2)$
$x_2$ = 7, vamos substituir
$Q_1 = 7 + (0)(8-7)$
$Q_1 = 7 + (0)(1)$
$Q_1 = 7$
OBS.: Por mais que o segundo método tenha uma fórmula, achar pelas medianas é uma forma mais simples.
Com Python, podemos utilizar a biblioteca pandas para achar os valores de forma fácil usando o método describe()
df['salario'].describe()
count 3.755000e+03 mean 1.906956e+05 std 6.716765e+05 min 6.000000e+03 25% 1.000000e+05 50% 1.380000e+05 75% 1.800000e+05 max 3.040000e+07 Name: salario, dtype: float64
Podemos também usar o método quantile()
# se não passar nada pro método, por padrão é o quantil 50º ou mediana
df['salario'].quantile()
138000.0
# 20º quantil
df['salario'].quantile(q=0.2)
85000.0
O box plot nos devolve, de forma gráfica, as principais medidas vistas até agora: Mediana, primeiro e terceiro quartil e os valores mínimo e máximo. Os valores de mínimo e máximo são importantes para entendermos o intervalo (range) dos nossos dados.
Segundo Bussab e Morettin (2010) o box plot dá uma ideia da posição, dispersão, assimetria, caudas e dados discrepantes.
Vamos ver um caso com dados discrepantes
conjunto = [10,25,23,34,8,2,7,60]
df_conjunto = pd.DataFrame({'valores': conjunto})
df_conjunto.boxplot(figsize=(5, 3))
plt.show()
As fórmulas abaixo são para calcular os limites inferior e superior, que serão o intervalo onde os valores adjacentes (valores que não são outliers) estarão:
$LI = q_1 - 1,5 \cdot IIQ$
$LS = q_3 + 1,5 \cdot IIQ$
$IIQ$ é intervalo interquartil, que é dado por
$IIQ = q_3 - q_1$
A simetria nos diz aonde nosso conjunto de dados está mais concentrado.
Distribuição Simétrica: Quando a distribuição for simétrica, nos temos um único valor para moda, média e mediana ($\overline{x} = M_d = M_o$)
Distribuições Assimétricas: Quando a distribuição for assimétrica, nos temos valores diferentes para moda, média e mediana ($\overline{x} = M_d = M_o$)
Sua fórmula é dada por: $$\text{assimetria} = M_3 = \frac{\sum_{i=1}^{n}(x_i - \overline{x})³}{n}$$
Uma desvantagem de utilizar a fórmula acima está na dependência da unidade de medida dos dados. Se tivermos trabalhando com dados em reais, a assimetria retornará reais ao cubo.
Para resolver isso, basta dividirmos pelo desvio padrão elevado ao cubo, trazendo o que chamamos de coeficiente momento de assimetria ($\alpha_3$)
$$\text{coeficiente momento de assimetria} = \alpha_3 = \frac{M_3}{s³}$$def coeficiente_assimetria(valores):
media = sum(valores) / len(valores)
assimetria = sum((valores - media)**3) / len(valores)
desvio_padrao = np.sqrt(sum((valores - media)**2) / (len(valores) - 1))
return assimetria / (desvio_padrao ** 3)
coeficiente_assimetria(df['salario'])
28.914816754066507
df['salario'].skew()
28.937932169111605
conjunto_simetrico = [1, 1, 3, 3, 5, 5, 5, 7, 7, 9, 9]
df_simetrico = pd.DataFrame({'valores': conjunto_simetrico})
df_simetrico.plot(kind='kde', figsize=(5, 3))
plt.show()
print(f'O coeficente de momento de assimetria é: {df_simetrico["valores"].skew()}')
O coeficente de momento de assimetria é: 0.0
conjunto_assimetrico_direita = [1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 5, 5, 5, 7, 7, 9]
df_assimetrico_direita = pd.DataFrame({'valores': conjunto_assimetrico_direita})
df_assimetrico_direita.plot(kind='kde', figsize=(5, 3))
plt.show()
print(f'O coeficente de momento de assimetria é: {df_assimetrico_direita["valores"].skew()}')
O coeficente de momento de assimetria é: 0.7436128024718242
conjunto_assimetrico_esquerda = [1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 9, 9]
df_assimetrico_esquerda = pd.DataFrame({'valores': conjunto_assimetrico_esquerda})
df_assimetrico_esquerda.plot(kind='kde', figsize=(5, 3))
plt.show()
print(f'O coeficente de momento de assimetria é: {df_assimetrico_esquerda["valores"].skew()}')
O coeficente de momento de assimetria é: -0.6554279508966395
df.head(2)
ano_trabalho | nivel_experiencia | tipo_de_contrato | cargo | salario | moeda_salario | salario_em_dolares | pais_residencia | tipo_trabalho | local_companhia | tamanho_companhia | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2023 | Senior/Especialista | Tempo integral | Principal Data Scientist | 80000 | EUR | 85847 | ES | Home office | ES | Grande |
1 | 2023 | Pleno | Contrato | ML Engineer | 30000 | USD | 30000 | US | Home office | US | Pequeno |
# vendo nos dados que estamos analisando desde o começo
# aqui utilizamos o gráfico de histograma, mas com ele também é possível ver assimetria
# sendo mais um tipo de gráfico que podemos usar com esse propósito
df['salario_em_dolares'].plot(kind='hist', figsize=(5,3))
plt.show()
Vemos com o gráfico acima, que o salário em dólares das pessoas que trabalham com dados é uma distribuição assimétrica à direita.
Curtose é o grau de achatamento de uma distribuição em relação a uma distribuição padrão. Essa medida mede o agrupamento de valores da distribuição em torno do centro. Quanto mais agrupados em torno do centro, maior será o valor da curtose.
Existem 3 classificações para a curtose:
Sua fórmula é dada por: $$\text{curtose} = M_4 = \frac{\sum_{i=1}^{n}(x_i - \overline{x})⁴}{n}$$
Dá mesma forma que dividimos no coeficiente de assimetria, dividiremos aqui para ajustar a unidade de medida.
Para resolver isso, basta dividirmos pelo desvio padrão elevado à quarta, trazendo o que chamamos de coeficiente momento de curtose ($\alpha_4$)
$$\text{coeficiente momento de curtose} = \alpha_4 = \frac{M_4}{s⁴}$$mesocurtica = [1, 3, 3, 5, 5, 5, 5, 7, 7, 9]
leptocurtica = [1, 3, 5, 5, 5, 5, 5, 5, 7, 9]
platicurtica = [1, 1, 3, 3, 5, 5, 7, 7, 9, 9]
df_curtose = pd.DataFrame({'mesocurtica': mesocurtica, 'leptocurtica': leptocurtica,
'platicurtica': platicurtica})
df_curtose.plot(kind='kde', figsize=(5, 3))
plt.show()
print(f"A curtose da mesocurtica é: {df_curtose['mesocurtica'].kurtosis()}")
print(f"A curtose da leptocurtica é: {df_curtose['leptocurtica'].kurtosis()}")
print(f"A curtose da platicurtica é: {df_curtose['platicurtica'].kurtosis()}")
A curtose da mesocurtica é: 0.08035714285714235 A curtose da leptocurtica é: 1.6714285714285717 A curtose da platicurtica é: -1.3339285714285714
def coeficiente_curtose(valores):
media = sum(valores) / len(valores)
assimetria = sum((valores - media)**4) / len(valores)
desvio_padrao = np.sqrt(sum((valores - media)**2) / (len(valores) - 1))
return assimetria / (desvio_padrao ** 4)
coeficiente_curtose(df['salario'])
1148.426386596344
# no pandas
df['salario'].kurtosis()
1147.5673898192115
Muitos procedimentos estatísticos são baseados nos dados estarem em um distribuição normal. Porém, em muitas situações, os dados possuem distribuições assimétricas, contém outliers, etc.
Uma forma de tentar transformar esses dados em um conjunto de dados com distribuição normal é a através de transformações.
Segundo Bussab e Morettin (2010), transformações frequentemente utilizadas são:
$$ x^{(p)} = \begin{cases} x^p,\text{se p > 0} \\ ln(x),\text{se p = 0} \\ -x^p,\text{se p < 0} \\ \end{cases}$$onde p são valores experimentados em uma sequência, por exemplo: ...,-3, -2, -1, 0, 1, 2, 3,...
Para valores assimétricos à direita, utilize transformações com $0 < p < 1$, pois valores grandes de x decrescem com valores de p pequenos. Para distribuições assimétricas à esquerda, utilize $p > 1$
Vamos ver no Python.
df['salario'].plot(kind='kde', figsize=(5,3))
plt.show()
print(df['salario'].skew())
print(df['salario'].iloc[0:5])
28.937932169111605 0 80000 1 30000 2 25500 3 175000 4 120000 Name: salario, dtype: int64
Temos acima uma distribuição com assimetria à direita. Vamos tentar transforma-lá em uma distribuição normal
salario_transformado = np.log1p(df['salario'])
salario_transformado.plot(kind='kde', figsize=(5,3))
plt.show()
print(salario_transformado.skew())
print(salario_transformado.iloc[0:5])
0.7874033806913452 0 11.289794 1 10.308986 2 10.146473 3 12.072547 4 11.695255 Name: salario, dtype: float64
Agora temos uma distribuição mais próxima da normal. Porém como eu saberei o valor real depois de alguma análise? Podemos voltar a mesma distribuição usando a função que seja inversa a que usamos, no caso usamos uma função logarítmica, temos que usar uma função exponencial para reverter.
salario_volta = np.expm1(salario_transformado)
salario_volta.plot(kind='kde', figsize=(5,3))
plt.show()
print(salario_volta.skew())
print(salario_volta.iloc[0:5])
28.937932169111598 0 80000.0 1 30000.0 2 25500.0 3 175000.0 4 120000.0 Name: salario, dtype: float64
Vemos que os valores voltaram ao normal.