import pandas as pd
import numpy as np
from scipy import stats
import seaborn as sns
import matplotlib.pyplot as plt
import pyspark.sql.functions as F
import warnings
warnings.filterwarnings('ignore')
df = pd.read_csv('dados/dados_tratados.csv').drop('Unnamed: 0', axis=1)
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 |
Quando consideramos analisar duas variáveis, podemos ter três situações:
Em todas essas situações, o objetivo é encontrar possíveis relações ou associações entre as duas variáveis.
Segundo Bussab e Morettin (2010) podemos entender a existência de associação como a mudança de opinião sobre o comportamento de uma variável na presença ou não de informação sobre a segunda variável.
As tabelas de contingência são tabelas onde estarão as frequências absolutas ou contagens de observações que pertencem simultaneamente as categorias de uma e outra variável.
Vamos criar uma com Python.
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 |
dcf = pd.crosstab(df['nivel_experiencia'], df['tipo_de_contrato'])
dcf_total = dcf.copy()
dcf_total['Total'] = dcf.sum(axis=1, numeric_only=True)
dcf2 = pd.DataFrame({dcf.columns[0]: dcf['Contrato'].sum(),
dcf.columns[1] : dcf['Freelance'].sum(),
dcf.columns[2]: dcf['Tempo integral'].sum(),
dcf.columns[3]: dcf['Tempo parcial'].sum()}, index=['Total'])
dcf_total = dcf_total.append(dcf2)
dcf_total
dcf_total.style.set_caption("Tabela 1 - Distribuição conjunta das proporções de tipo de contrato e o nível de experiência")
Contrato | Freelance | Tempo integral | Tempo parcial | Total | |
---|---|---|---|---|---|
Diretor | 1 | 0 | 113 | 0 | 114.000000 |
Junior | 2 | 2 | 302 | 14 | 320.000000 |
Pleno | 5 | 5 | 792 | 3 | 805.000000 |
Senior/Especialista | 2 | 3 | 2511 | 0 | 2516.000000 |
Total | 10 | 10 | 3718 | 17 | nan |
Em vez de trabalharmos com as frequências absolutas, podemos construir tabelas com as frequências relativas (proporções), como foi feito no caso unidimensional.
Na tabela de contingência podemos ter três possibilidade de análise:
De acordo com o objetivo do problema, uma delas será mais adequada.
Os totais nas margens (última linha e última coluna) fornecem as distribuições unidimensionais de cada uma das variáveis
Outra forma de comparar duas variáveis é através de gráficos. Vamos mostrar abaixo.
dcf.plot(kind='bar', stacked=True)
plt.show
<function matplotlib.pyplot.show(close=None, block=None)>
Quando construímos uma distribuição conjunta de frequências, um dos principais objetivos é entender a associação entre as variáveis. Essa associação é o grau de dependência entre as variáveis, fazendo com que sejamos capazes de prever o melhor resultado de uma delas quando tivermos a informação sobre a outra.
Vamos passar os valores da tabela 1
para porcentagem para analisarmos.
dcf_porcentagem = dcf.copy()
for coluna in dcf.columns:
dcf_porcentagem[coluna] = (dcf[coluna] / len(df))
dcf_porcentagem['Total'] = dcf_porcentagem.sum(axis=1, numeric_only=True)
dcf2 = pd.DataFrame({dcf_porcentagem.columns[0]: dcf_porcentagem['Contrato'].sum(),
dcf_porcentagem.columns[1] : dcf_porcentagem['Freelance'].sum(),
dcf_porcentagem.columns[2]: dcf_porcentagem['Tempo integral'].sum(),
dcf_porcentagem.columns[3]: dcf_porcentagem['Tempo parcial'].sum()}, index=['Total'])
dcf_porcentagem = pd.concat([dcf_porcentagem, dcf2])
dcf_porcentagem['Total'].iloc[-1:] = dcf_porcentagem.iloc[-1:].sum(axis=1, numeric_only=True)
dcf_porcentagem
dcf_porcentagem.style.set_caption("Tabela 2 - Distribuição conjunta das proporções (em porcentagem) de tipo de contrato e o nível de experiência")
Contrato | Freelance | Tempo integral | Tempo parcial | Total | |
---|---|---|---|---|---|
Diretor | 0.000266 | 0.000000 | 0.030093 | 0.000000 | 0.030360 |
Junior | 0.000533 | 0.000533 | 0.080426 | 0.003728 | 0.085220 |
Pleno | 0.001332 | 0.001332 | 0.210919 | 0.000799 | 0.214381 |
Senior/Especialista | 0.000533 | 0.000799 | 0.668708 | 0.000000 | 0.670040 |
Total | 0.002663 | 0.002663 | 0.990146 | 0.004527 | 1.000000 |
Baseado na tabela 2, parece que as variáveis possuem associação. Isso se deve ao fato de que a proporção esperada das variáveis de tipo de contrato
são diferentes da proporção total de cada nível de experiência
. Exceto a variável Tempo Integral
todas as outras possuem valores muito diferentes da proporção total, sugerindo uma possível associação.
No item anterior, avaliamos a associação através da avaliação da tabela, porém existem formas de quantificar isso.
Segundo Bussab e Morettin (2010) a quantificação do grau de associação entre duas variáveis é feita, de modo geral, pelos chamados coeficientes de associação ou correlação.
Essas são medidas que descrevem, por meio de um único número, a associação (ou dependência) entre duas variáveis. Para maior facilidade de compreensão, esses coeficientes usualmente variam entre 0 e 1, ou entre –1 e +1, e a proximidade de zero indica falta de associação.
Uma das medidas que quantificam essa associação é o coeficiente de contingência
Para acharmos o coeficiente de contingência, precisamos primeiro achar o $\chi²$ (qui-quadrado) de Pearson. Vamos entender primeiro ele intuitivamente antes de mostrarmos a fórmula.
Primeiro, vamos ver a mesma tabela acima, porém em porcentagens:
A partir da tabela 2
vamos construir uma tabela com os valores esperados assumindo a independência entre as variáveis. Isso significa que vamos pegar a última linha (Total) e considerar aquela porcentagem como a porcentagem para todos os valores (Porcentagem da coluna).
No nosso exemplo, vamos considerar a coluna Tempo Integral
. Sabemos que 99% dos funcionários trabalham em tempo integral. O que faremos é considerar então que 99% dos funcionários de cada nível de experiência (Diretor, Júnior, Pleno, Sênior/Especialista) como trabalhando em tempo integral. Com essa porcentagem, vamos multiplicar pelos valores totais de cada nível de experiência (coluna total da tabela 1
).
dcf_esperados = dcf.copy()
for coluna in dcf.columns:
valor = dcf_porcentagem[coluna].iloc[-1:].values.item()
dcf_esperados[coluna].iloc[0:] = valor
dcf_esperados[coluna] = dcf_esperados[coluna] * dcf_total['Total']
dcf_esperados['Total'] = dcf_total['Total']
dcf_esperados
dcf_esperados.style.set_caption("Tabela 3 - Distribuição conjunta das proporções esperadas de tipo de contrato e o nível de experiência")
tipo_de_contrato | Contrato | Freelance | Tempo integral | Tempo parcial | Total |
---|---|---|---|---|---|
nivel_experiencia | |||||
Diretor | 0.303595 | 0.303595 | 112.876698 | 0.516112 | 114.000000 |
Junior | 0.852197 | 0.852197 | 316.846871 | 1.448735 | 320.000000 |
Pleno | 2.143808 | 2.143808 | 797.067909 | 3.644474 | 805.000000 |
Senior/Especialista | 6.700399 | 6.700399 | 2491.208522 | 11.390679 | 2516.000000 |
Com a tabela 1
e a tabela 3
somos capazes de calcular uma medida que é capaz de nos dizer qual é o desvio entre o valor observado (valores da tabela 1
) e valor esperado (valores da tabela 3
).
onde:
medida_afastamento = ((dcf - dcf_esperados) ** 2) / dcf_esperados
medida_afastamento = medida_afastamento.drop('Total', axis=1)
medida_afastamento
tipo_de_contrato | Contrato | Freelance | Tempo integral | Tempo parcial |
---|---|---|---|---|
nivel_experiencia | ||||
Diretor | 1.597455 | 0.303595 | 0.000135 | 0.516112 |
Junior | 1.545947 | 1.545947 | 0.695697 | 108.739176 |
Pleno | 3.805299 | 3.805299 | 0.032223 | 0.113966 |
Senior/Especialista | 3.297379 | 2.043603 | 0.157234 | 11.390679 |
Porém, com a medida acima temos apenas para cada observação. Como saberemos a medida do afastamento total? Para isso basta somar todas as medidas. Esse medida do afastamento total chamamos de $\chi²$ de Pearson.
Vamos somar as medida e achar nosso $\chi²$.
qui_quadrado_pearson = 0
for coluna in medida_afastamento.columns:
qui_quadrado_pearson += medida_afastamento[coluna].sum()
qui_quadrado_pearson
139.5897460517641
# validando o resultado com scipy
stats.chi2_contingency(dcf)[0]
139.5897460517641
Valores grandes de $\chi^2$ indicam associação entre as variáveis. Logo no nosso caso, as variáveis tem uma associação.
Vamos formalizar o conceito que vimos acima:
Para uma tabela de contingência qualquer, dada pela seguinte notação
$B_1$ | $B_2$ | ... | $B_s$ | Total | |
---|---|---|---|---|---|
$A_1$ | $n_{11}$ | $n_{12}$ | ... | $n_{1s}$ | $n_{1.}$ |
$A_2$ | $n_{21}$ | $n_{22}$ | ... | $n_{2s}$ | $n_{2.}$ |
$\cdot$ | $\cdot$ | $\cdot$ | $\cdot$ | $\cdot$ | $\cdot$ |
$\cdot$ | $\cdot$ | $\cdot$ | $\cdot$ | $\cdot$ | $\cdot$ |
$A_r$ | $n_{r1}$ | $n_{r2}$ | ... | $n_{rs}$ | $n_{r.}$ |
Total | $n_{.1}$ | $n_{.2}$ | ... | $n_{.s}$ | $n_{..}$ |
Para ficar claro, vamos lembrar que $n_{ij}$ é o valor ($n$) que está na i-ésima linha ($i$) e j-ésima coluna ($j$), logo $n_{12}$ significa o valor que está na primeira linha e segunda coluna. pegando o $n_{12}$ da tabela 1 seria o 0 (linha de índice Diretor, coluna de Freelance)
A fórmula é dada por: $$\sum_{i=1}^{r}\sum_{j=1}^{s}\frac{(n_{ij} - n_{ij}^{*})²}{n_{ij}^{*}}$$
onde:
A fórmula acima significa que vamos achar todas as medidas de afastamento da tabela e depois somar todas elas.
Com o $\chi²$ conseguimos achar o coeficiente de contingência, que é dado pela fórmula:
$$C = \sqrt{\frac{\chi^2}{\chi^2 + n}}$$Porém, o coeficiente de contingência não varia entre 0 e 1, o que pode ser díficil de analisar. Para evitar isso, definiu-se o coeficiente de contingência modificado, dado por: $$T = \sqrt{\frac{\frac{\chi^2}{n}}{(r-1)(s-1)}}$$
Vamos calcular os dois para nossos dados.
def coeficiente_contigencia(qui_quadrado, n):
return np.sqrt((qui_quadrado / (qui_quadrado + n)))
coeficiente_contigencia(qui_quadrado_pearson, len(df))
0.1893197405150074
# validando o resultado com scipy
from scipy import stats
stats.contingency.association(dcf, method='pearson')
0.1893197405150074
def coeficiente_contigencia_modificado(qui_quadrado, n, r, s):
return np.sqrt(((qui_quadrado / n) / ((r - 1) * (s - 1))))
coeficiente_contigencia_modificado(qui_quadrado_pearson, len(df), len(dcf), len(dcf.columns))
0.06426885063589059
Quando as variáveis envolvidas são ambas do tipo quantitativo, pode-se usar o mesmo tipo de análise feita anteriormente. Para isso, a distribuição conjunta pode ser resumida em tabelas de contingência e, por meio das distribuições, é possível estudar a associação das variáveis. Algumas vezes, para evitar um grande número de entradas, agrupamos os dados em intervalos de classes, de modo semelhante ao feito no caso unidimensional. Mas, além desse tipo de análise, as variáveis quantitativas são passíveis de procedimentos analíticos e gráficos mais refinados.
Um dispositivo bastante útil para se verificar a associação entre duas variáveis quantitativas, ou entre dois conjuntos de dados, é o gráfico de dispersão, que veremos por meio de exemplos.
Vamos importar dados da B3 (Bolsa de valores Brasileira) para fazer a análise.
df_b3 = pd.read_csv('dados/b3_stocks_1994_2020.csv')
df_b3['datetime'] = pd.to_datetime(df_b3['datetime'])
df_b3['ano'] = df_b3['datetime'].dt.year
df_b3.head()
datetime | ticker | open | close | high | low | volume | ano | |
---|---|---|---|---|---|---|---|---|
0 | 1994-07-04 | ACE 3 | 48.00 | 48.00 | 48.00 | 47.00 | 46550.0 | 1994 |
1 | 1994-07-04 | ALP 3 | 155.27 | 156.00 | 156.00 | 155.27 | 163405.8 | 1994 |
2 | 1994-07-04 | ALP 4 | 131.00 | 131.00 | 131.00 | 131.00 | 6550.0 | 1994 |
3 | 1994-07-04 | IBP 6 | 600.00 | 600.00 | 600.00 | 600.00 | 7800.0 | 1994 |
4 | 1994-07-04 | AQT 4 | 0.89 | 0.99 | 0.99 | 0.85 | 13137.0 | 1994 |
Vamos ver somente o preço de abertura das ações do Google desde até 2020, para desconsiderar a pandemia.
google = df_b3[df_b3['ticker'] == 'GOGL34']
google = google[google['datetime'].dt.year < 2020]
google
datetime | ticker | open | close | high | low | volume | ano | |
---|---|---|---|---|---|---|---|---|
1441222 | 2016-05-09 | GOGL34 | 102.00 | 103.25 | 103.40 | 101.00 | 5747536.0 | 2016 |
1441527 | 2016-05-10 | GOGL34 | 102.80 | 101.70 | 102.80 | 100.96 | 3609032.0 | 2016 |
1441832 | 2016-05-11 | GOGL34 | 101.50 | 100.85 | 101.50 | 100.85 | 810700.0 | 2016 |
1442141 | 2016-05-12 | GOGL34 | 100.95 | 101.02 | 101.36 | 100.95 | 851247.0 | 2016 |
1442468 | 2016-05-13 | GOGL34 | 101.50 | 101.65 | 101.73 | 101.50 | 864020.0 | 2016 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
1751406 | 2019-12-20 | GOGL34 | 222.75 | 223.83 | 224.00 | 221.45 | 956565.0 | 2019 |
1751808 | 2019-12-23 | GOGL34 | 223.20 | 221.43 | 223.20 | 220.57 | 2266240.0 | 2019 |
1752221 | 2019-12-26 | GOGL34 | 220.65 | 221.65 | 221.65 | 219.00 | 727578.0 | 2019 |
1752638 | 2019-12-27 | GOGL34 | 221.22 | 220.42 | 222.28 | 220.00 | 3086500.0 | 2019 |
1753070 | 2019-12-30 | GOGL34 | 217.66 | 215.80 | 217.66 | 215.00 | 2076811.0 | 2019 |
864 rows × 8 columns
plt.figure(figsize=(14, 5))
sns.scatterplot(data=google, x="datetime", y="open")
plt.show()
Vemos que parece haver uma associação com as variáveis tempo e preço de abertura, por mais que tenhamos quedas ao longo do tempo, vemos que há uma tendência de aumento do preço ao longo dos anos. Isso seria uma associação positiva. Vamos ver agora as ações da IRB Brasil
nos últimos 3 anos.
irbr = df_b3[df_b3['ticker'] == 'IRBR3']
irbr = irbr[irbr['datetime'].dt.year >= 2020]
plt.figure(figsize=(14, 5))
sns.scatterplot(data=irbr, x="datetime", y="open")
plt.show()
Vemos que parece haver uma associação com as variáveis tempo e preço de abertura, vemos que há uma tendência à queda ao longo dos últimos 3 anos.
ano = [2016, 2017, 2018, 2019, 2020]
valor = [343, 368, 355, 334, 337]
df_criada = pd.DataFrame(list(zip(ano, valor)), columns=['Ano', 'Valor'])
plt.figure(figsize=(14, 5))
sns.scatterplot(data=df_criada, x="Ano", y="Valor")
plt.show()
No caso acima, não sabemos se temos ou não uma possível associação, pois não conseguimos saber se com o passar dos anos as ações sobem ou descem.
Uma forma de entender se há associação é através do calculo do coeficiente de correlação.
Vamos entender como é calculado.
Nós temos as seguintes variáveis, Ano e valor.
Ano | Valor |
---|---|
2016 | 343 |
2017 | 368 |
2018 | 355 |
2019 | 334 |
2020 | 337 |
Primeira coisas que temos que fazer é achar as medias de cada variável e seu desvio padrão.
print(f'A média do ano é: {df_criada["Ano"].mean()}')
print(f'O desvio padrão do ano é: {df_criada["Ano"].std():.2f}')
print(f'A média do valor é: {df_criada["Valor"].mean()}')
print(f'O desvio padrão do valor é: {df_criada["Valor"].std():.2f}')
A média do ano é: 2018.0 O desvio padrão do ano é: 1.58 A média do valor é: 347.4 O desvio padrão do valor é: 14.05
Agora vamos achar o valor de cada observação menos a média da variável.
Ano | Valor | Ano - media do ano | Valor - média do valor | |
---|---|---|---|---|
2016 | 343 | -2 | -4,4 | |
2017 | 368 | -1 | 20,6 | |
2018 | 355 | 0 | 7,6 | |
2019 | 334 | 1 | -13,4 | |
2020 | 337 | 2 | -10,4 | |
Total |
Agora vamos dividir os valores subtraídos da média pelo seu desvio padrão. Esse valor de z que vamos achar é chamado de Z-score
$z_x = \frac{\text{Ano} - \text{media do ano}}{\text{desvio padrao do ano} } $, $z_y = \frac{\text{Valor} - \text{media do valor}}{\text{desvio padrao do valor} } $
Vamos chamar o resultado de $z_x$ para o ano e $z_y$ para o valor.
Ano | Valor | Ano - media do ano | Valor - média do valor | $z_x$ | $z_y$ | |
---|---|---|---|---|---|---|
2016 | 343 | -2 | -4,4 | -1,27 | -0,31 | |
2017 | 368 | -1 | 20,6 | -0,63 | 1,47 | |
2018 | 355 | 0 | 7,6 | 0 | 0,54 | |
2019 | 334 | 1 | -13,4 | 0,63 | -0,95 | |
2020 | 337 | 2 | -10,4 | 1,27 | -0,74 | |
Total |
Agora vamos multiplicar o $z_x$ pelo $z_y$ e somar todos os resultados e colocar na linha total
$\text{produto} = z_x \cdot z_y $
Ano | Valor | Ano - media do ano | Valor - média do valor | $z_x$ | $z_y$ | produto | |
---|---|---|---|---|---|---|---|
2016 | 343 | -2 | -4,4 | -1,27 | -0,31 | 0,3937 | |
2017 | 368 | -1 | 20,6 | -0,63 | 1,47 | -0,9261 | |
2018 | 355 | 0 | 7,6 | 0 | 0,54 | 0 | |
2019 | 334 | 1 | -13,4 | 0,63 | -0,95 | -0,5985 | |
2020 | 337 | 2 | -10,4 | 1,27 | -0,74 | -0,93 | |
Total | -2,0707 |
Portanto, temos que o grau de associação linear desse exemplo é de $-20,7\%$.
Agora vamos dividir o valor do grau de associação linear pelo número de observações, lembrando que numa amostra é sempre $n-1$. Como nosso $n$ é 5, vamos dividir por 4
$\frac{-2,0707}{4} = 0.518 $
Esse valor que achamos acima é o coeficiente de correlação de Pearson. Sua fórmula é dada por:
$$\text{corr}(X,Y) = \frac{1}{n}\sum_{i=1}^{n}(\frac{x_i - \overline{x}}{\sigma(X)})(\frac{y_i - \overline{y}}{\sigma(Y)})$$Lembrando que $\sigma$ é o desvio padrão da variável.
O coeficiente de correlação fica entre o intervalo -1 e 1. Quando -1 é porque quando uma variável aumenta a outra diminui. Quando 1 é porque quando uma variável aumenta a outra também aumenta.
OBS.:
Uma forma bem comum de achar a fórmula da correlação de Pearson é assim:
$$\text{corr}(X,Y) = \frac{\text{cov(X,Y)}}{\sigma(X) \cdot \sigma(Y)} $$Isso se deve ao fato da covariância ser dada pela fórmula: $$\text{cov(X,Y)} = \frac{\sum_{i=1}^{n}(x_i - \overline{x})(y_i - \overline{y})}{n}$$
Para chegar na equação 6, vamos voltar na equação 4:
$$\text{corr}(X,Y) = \frac{1}{n}\sum_{i=1}^{n}(\frac{x_i - \overline{x}}{\sigma(X)})(\frac{y_i - \overline{y}}{\sigma(Y)})$$$$ \text{corr}(X,Y) = \frac{\sum_{i=1}^{n}(\frac{x_i - \overline{x}}{\sigma(X)})(\frac{y_i - \overline{y}}{\sigma(Y)})}{n}$$ $$\text{corr}(X,Y) = {\sum_{i=1}^{n}(\frac{x_i - \overline{x}}{\sigma(X)})(\frac{y_i - \overline{y}}{\sigma(Y)})} \cdot \frac{1}{n}$$ $$\text{corr}(X,Y) = \frac{\sum_{i=1}^{n} (x_i - \overline{x})(y_i - \overline{y})}{n\cdot\sigma(X)\sigma(Y)}$$
Chegamos a uma situação onde podemos substituir pela fórmula da covariância. Trocando pelo valor da covariância, temos: $$\text{corr}(X,Y) = \frac{\text{cov(X,Y)}}{\sigma(X) \cdot \sigma(Y)} $$
def correlacao_pearson(df, variavel_x, variavel_y):
z_score_x = (df[variavel_x] - (sum(df[variavel_x]) / len(df[variavel_x]))) / df[variavel_x].std()
z_score_y = (df[variavel_y] - (sum(df[variavel_y]) / len(df[variavel_y]))) / df[variavel_y].std()
return sum(z_score_x * z_score_y) / (len(df) - 1)
correlacao_pearson(df_criada, 'Ano', 'Valor')
-0.5178026794057726
df_criada.corr(method='pearson')
Ano | Valor | |
---|---|---|
Ano | 1.000000 | -0.517803 |
Valor | -0.517803 | 1.000000 |
A correlação de Pearson não é uma boa medida para variáveis que possuem dados discrepantes, pois não possui robustez para observações dessa natureza. Uma medida de associação mais robusta é o coeficiente de correlação de Spearman.
Na correlação de Spearman as variáveis $X$ e $Y$ são substituídos pelos seus respectivos postos. Postos são os índices correspondentes à sua posição no conjunto ordenado. Por exemplo, se temos um conjunto de observações $x_1 = 2$, $x_2 = 7$, $x_3 = 4$, $x_4 = 10$, $x_5 = 6$, ordenando teriamos $x_1 < x_3 < x_5 < x_2 < x_4$, logo o posto de $x_5$ é $3$.
Seu cálculo é dado pela expressão:
$$r_s = \frac{\sum_{i=1}^{n}(R_i - \overline{R})(S_i - \overline{S})}{[\sum_{i=1}^{n}(R_i - \overline{R})²\sum_{i=1}^{n}(S_i - \overline{S})²]^{1/2}}$$O coeficiente de correlação fica entre o intervalo -1 e 1. Quando -1 é porque quando uma variável aumenta a outra diminui. Quando 1 é porque quando uma variável aumenta a outra também aumenta.
A correlação de Spearman é mais apropriada para avaliar associações não lineares, desde que sejam monotônicas. Monotônicas são quando valores de uma das variáveis só aumenta ou diminui quando o valor de uma segunda variável aumenta ou diminui.
df_criada_rank = df_criada.copy()
df_criada_rank.loc[df_criada_rank["Ano"].sort_values().index, "Rank_Ano"] = np.arange(df_criada_rank.shape[0])
df_criada_rank.loc[df_criada_rank["Valor"].sort_values().index, "Rank_Valor"] = np.arange(df_criada_rank.shape[0])
df_criada_rank["Rank_Ano"] = df_criada_rank["Rank_Ano"].astype(int)
df_criada_rank["Rank_Valor"] = df_criada_rank["Rank_Valor"].astype(int)
df_criada_rank
Ano | Valor | Rank_Ano | Rank_Valor | |
---|---|---|---|---|
0 | 2016 | 343 | 0 | 2 |
1 | 2017 | 368 | 1 | 4 |
2 | 2018 | 355 | 2 | 3 |
3 | 2019 | 334 | 3 | 0 |
4 | 2020 | 337 | 4 | 1 |
def correlacao_spearman(df, X, Y):
df.loc[df[X].sort_values().index, "Rank_X"] = np.arange(df.shape[0])
df.loc[df[Y].sort_values().index, "Rank_Y"] = np.arange(df.shape[0])
df[X] = df[X].astype(int)
df[Y] = df[Y].astype(int)
numerador = sum((df["Rank_X"] - df["Rank_X"].mean()) * (df["Rank_Y"] - df["Rank_Y"].mean()))
denominador = np.sqrt(sum(((df["Rank_X"] - df["Rank_X"].mean()))**2) * sum(((df["Rank_Y"] - df["Rank_Y"].mean()))**2))
return numerador / denominador
df_criada[['Ano', 'Valor']].corr(method='spearman')
Ano | Valor | |
---|---|---|
Ano | 1.0 | -0.6 |
Valor | -0.6 | 1.0 |
correlacao_spearman(df_criada, 'Ano', 'Valor')
-0.6
Esse tipo de análise pode ser conduzida por meio de medidas resumo, histogramas, box plots, etc.
df.head(3)
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 |
sns.boxplot(data=df, x="nivel_experiencia", y="salario_em_dolares")
<AxesSubplot:xlabel='nivel_experiencia', ylabel='salario_em_dolares'>
Por mais que conseguimos verificar as diferenças salariais, não conseguimos quantificar. Para isso vamos ver uma medida que nos mostre a associação entre as variáveis.
Usaremos a variância para construir essa medida
$$\overline{\text{var}(S)} = \frac{\sum_{i=1}^{k}n_i\text{var}_i(S)}{\sum_{i=1}^{k}n_i}$$Onde:
Com a média das variâncias podemos chegar o grau de associação.
$$R² = 1 - \frac{\overline{\text{var}(S)}}{\text{var}(S)}$$Vamos ver no Python.
def r_quadrado(df, X, Y):
variancia = df[[X, Y]].groupby(X).var()
quantidade = df[[X, Y]].groupby(X).count()
media_variancia = sum((quantidade[Y] * variancia[Y])) / sum(quantidade[Y])
variancia_total = df[Y].var()
return 1 - (media_variancia / variancia_total)
r_quadrado(df, 'nivel_experiencia', 'salario_em_dolares')
0.19839004764069046
O $R²$ nos diz que $19,8\%$ da variação total dos salários é explicada pela variável Nível de experiência
.