Photo on Pinterest

Corrigindo uma escala psicométrica com Python: manipulação, limpeza e análises descritivas

Dalton Costa
Datapsico
Published in
9 min readJul 24, 2020

--

O trabalho do cientista de dados não se resume apenas em análises. Talvez mais da metade do seu tempo é destinado a manipulação e limpeza dos dados. Somente após alguns incansáveis procedimentos de limpeza o dado poderá ser utilizado para análises.

Apropriando do fluxograma proposto por Wickham & Grolemund (2017) podemos observar que a exploração dos dados segue um constante ciclo de transformação e visualização. Assim, como um minerador em busca de peças valiosas, o cientista de dados minera seus dados em busca de valores importantes, removendo todos os resíduos que possam atrapalhar suas análises.

Processo de exploração de dados. Criado por Wickham & Grolemund (2017)

Esse texto foi construído para auxiliar você a manipular, limpar e realizar análises descritivas de uma escala psicométrica. Nesse texto, iremos utilizar como exemplo o banco de dados “Depression Anxiety Stress Scales Responses” disponível publicamente no site Kaggle. Especialmente, vamos nos ater sobre as variáveis do questionário, corrigi-lo e interpretá-lo utilizando Python e o Jupyter Notebook.

O banco de dados que será utilizado é fruto de uma coleta de dados com quase 40 mil pessoas de vários países com a Depression Anxiety Stress Scales (DASS42), além das variáveis com as respostas dos participantes há outras variáveis sociodemográficas. O principal objetivo da DASS42 é identificar a presença de sintomatologia de depressão, ansiedade e estresse na população.

Para executar os procedimentos descritos abaixo é necessário ter o banco de dados baixado no seu computador.

Mão na Massa

Importando bibliotecas

Neste experimento vamos utilizar as bibliotecas Pandas e Matplotlib.

import pandas as pd
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings(‘ignore’)

Lendo o banco de dados

Depois de baixar os dados no seu computador você poderá ler os dados utilizando a biblioteca Pandas. Note que os dados estão separados por um espaço “\t”. Para ler o banco de dados execute o código abaixo:

banco = pd.read_csv("data.csv", sep="\t")
banco

Output:

Criando sub-banco de dados

Nessa etapa vamos criar um novo dataframe somente com as variáveis que nos interessa, deixando de lado outras variáveis que não farão parte das nossas análises. Queremos resgatar do banco original apenas as variáveis referentes à escala DASS42 e às variáveis gender e age.

Na linguagem Python, para separar sub-bancos ou subsets podemos atribuir os dados a uma nova variável utilizando de colchetes duplos, veja o código abaixo:

subbanco = banco[[
'Q1A', 'Q2A', 'Q3A', 'Q4A', 'Q5A', 'Q6A', 'Q7A','Q8A', 'Q9A', 'Q10A', 'Q11A', 'Q12A', 'Q13A', 'Q14A', 'Q15A', 'Q16A', 'Q17A', 'Q18A', 'Q19A', 'Q20A', 'Q21A', 'Q22A', 'Q23A', 'Q24A', 'Q25A', 'Q26A', 'Q27A', 'Q28A', 'Q29A', 'Q30A', 'Q31A', 'Q32A', 'Q33A', 'Q34A', 'Q35A', 'Q36A', 'Q37A', 'Q38A', 'Q39A', 'Q40A', 'Q41A', 'Q42A', 'gender', 'age'
]]
subbanco

Output:

Recodificando variáveis

Para corrigir a escala DASS42 , deve-se somar os itens correspondente aos seus fatores, no entanto cada opção de resposta deve variar de 0 a 3. Utilizando a função .max() e .min(), podemos observar no nosso sub-banco que os itens da escala variam de 1 a 4.

print(subbanco[[‘Q1A’, ‘Q2A’, ‘Q3A’]].max())
print(subbanco[[‘Q1A’, ‘Q2A’, ‘Q3A’]].min())

Output:

Precisamos recodificar nossos dados para a escala correta, ou seja, precisamos alterar as variáveis da DASS42 de 1 a 4 para 0 a 3. Se não realizarmos isso, a interpretação dos resultados estará comprometida.

Para recodificar criaremos uma função e aplicaremos essa função em nossos dados posteriormente.

Vamos atribuir a seguinte função:

def mudarValores(x):
if x == 1:
return 0
if x == 2:
return 1
if x == 3:
return 2
return 3

O objetivo dessa função é substituir um valor x quando ele for igual algum valor. Por exemplo, se o valor de x for igual a 1 deverá retornar 0.

Agora que temos a função construída precisamos aplicá-la em todas as colunas e linhas da escala DASS42. Para isso, iremos utilizar o laço de repetição FOR e IN: o primeiro passo é separar quais colunas queremos alterar no nosso sub-banco e criar o laço de repetição.

Esse laço irá substituir os valores em cada coluna informada (em dassCol) e em cada linha do sub-banco tendo como base a lógica construída na função mudarValores(). Veja no exemplo abaixo:

#separando as colunas 
dassCol = [
'Q1A', 'Q2A', 'Q3A', 'Q4A', 'Q5A', 'Q6A', 'Q7A','Q8A', 'Q9A', 'Q10A', 'Q11A', 'Q12A', 'Q13A', 'Q14A', 'Q15A', 'Q16A', 'Q17A', 'Q18A', 'Q19A', 'Q20A', 'Q21A', 'Q22A', 'Q23A', 'Q24A', 'Q25A', 'Q26A', 'Q27A', 'Q28A', 'Q29A', 'Q30A', 'Q31A', 'Q32A', 'Q33A', 'Q34A', 'Q35A', 'Q36A', 'Q37A', 'Q38A', 'Q39A', 'Q40A', 'Q41A', 'Q42A'
]
#laço de repetiçãofor col in dassCol:
subbanco[col] = subbanco[col].map(mudarValores)

subbanco

Output:

Agora que substituímos os valores podemos novamente conferir os valores máximos e mínimos das variáveis referentes a escala DASS42.

print(subbanco[[‘Q1A’, ‘Q2A’, ‘Q3A’]].max())
print(subbanco[[‘Q1A’, ‘Q2A’, ‘Q3A’]].min())

Output:

Dica: É comum a inversão de itens ao corrigir escalas. Você pode usar o mesmos procedimentos apresentados nessa seção para inverter itens/variáveis de um instrumento utilizado.

Criando categorias: cálculo dos escores brutos

A escala que estamos trabalhando é composta por três fatores: depressão, ansiedade e estresse. O escore bruto desses fatores podem ser calculados somando todos os itens correspondentes a sua categoria:

  • Itens da Depressão: 2, 5, 12, 13, 16, 17, 20, 23, 25, 26, 31, 32, 36 e 41
  • Itens da Ansiedade: 1, 6, 8, 10, 11, 14, 21, 22, 27, 28, 34, 37, 40 e 42
  • Itens do Estresse: 3, 4, 7, 9, 15, 18, 19, 24, 29, 30, 33, 35 e 38

Vamos criar uma variável para cada categoria e atribuir a soma dos itens por cada linha (caso). Para isso iremos utilizar a função sum(). Veja o código abaixo:

# Depressão itens 2,5,12,13,16,17,20,23,25,26,31,32,36,41subbanco['depressao'] = subbanco[['Q2A', 'Q5A', 'Q12A', 'Q13A', 'Q16A', 'Q17A', 'Q20A', 'Q23A', 'Q25A', 'Q26A', 'Q31A', 'Q32A', 'Q36A', 'Q41A']].sum(axis=1)#ansiedade itens 1,6,8,10,11,14,21,22,27,28,34,37,40,42subbanco['ansiedade'] = subbanco[['Q1A', 'Q6A', 'Q8A', 'Q10A', 'Q11A', 'Q14A', 'Q21A', 'Q22A', 'Q27A', 'Q28A', 'Q34A', 'Q37A', 'Q40A', 'Q42A']].sum(axis=1)#estesse itens 3,4,7,9,15,18,19,24,29,30,33,35,38subbanco['estresse'] = subbanco[['Q3A', 'Q4A', 'Q7A', 'Q9A', 'Q15A', 'Q18A', 'Q19A', 'Q24A', 'Q29A', 'Q30A','Q33A', 'Q35A', 'Q38A','Q39A']].sum(axis=1)subbanco[['depressao', 'ansiedade', 'estresse']]

Output:

Criando classificações: classificando os escores

Agora que já temos os escores brutos podemos utilizar os pontos de corte para criar as classificações de cada categoria. Vamos tomar como base o estudo de Crawford & Henry (2003):

Pontos de corte da DASS42. Imagem criada por Višnjić, A., Veličković, V., Sokolović, D., Stanković, M., Mijatović, K., Stojanović, M., … & Radulović, O. (2018).

Para fazer a classificação vamos ter que construir uma função para cada categoria que terá como base os pontos de corte da DASS42. A função irá verificar se o valor bruto corresponde ao intervalo dos pontos de corte. Veja o código abaixo:

def depreClass(x):
if x < 10:
return 'Normal'
if x < 14:
return 'Leve'
if x < 21:
return 'Moderado'
if x < 28:
return 'Severo'
return 'Extremamente_Severo'
def ansiClass(x):
if x < 8:
return 'Normal'
if x < 10:
return 'Leve'
if x < 15:
return 'Moderado'
if x < 20:
return 'Severo'
return 'Extremamente_Severo'
def estrClass(x):
if x < 15:
return 'Normal'
if x < 19:
return 'Leve'
if x < 25:
return 'Moderado'
if x < 34:
return 'Severo'
return 'Extremamente_Severo'

Podemos ler essas funções da seguinte forma: considerando um valor x se ele for menor que determinador valor retorne uma classificação. Essas funções são muito parecidas com o que fizemos na seção de Recodificando Variáveis, no entanto, ao invés de substituir os valores na mesma variável do banco, vamos substituir valores e atribuir a eles uma nova variável, portanto, não precisamos executar essas funções dentro de um laço de repetição.

Para executar as funções criadas precisamos criar uma variável nova para cada categoria que irá receber as classificações com base na lógica das funções criadas. Veja como executar no código abaixo:

subbanco['depressaoClas'] = subbanco['depressao'].map(depreClass)
subbanco['ansiedadeClas'] = subbanco['ansiedade'].map(ansiClass)
subbanco['estresseClas'] = subbanco['estresse'].map(estrClass)
subbanco[['depressaoClas','ansiedadeClas', 'estresseClas']]

Output:

Análise de missing

É recorrente ao analisar um banco de dados a existência de dados faltantes ou missing. Antes de iniciar nossa exploração estatística vamos verificar se no nosso dataframe existe algum missing. Para isso iremos utilizar a função isna() para identificar missing e sum() para somar os missing. Veja como é fácil:

subbanco.isna().sum()

Output:

Dica: Por sorte, com nossos dados não há dados faltantes, mas se no seu banco houver dados faltantes você pode excluir os casos incompletos utilizando a função dropna():

subbanco.dropna()

Excluindo casos

Agora vamos trabalhar com as outras duas variaveis do nosso sub-banco: age e gender (idade e gênero). No site do Kaggle há a descrição dos dados e diz que a idade fonecida é um número inteiro e que o gênero poderia variar de 1 a 3 (1 = masculino, 2= feminino e 3 = outro).

Assim como fizemos com as variaveis da escala DASS42, vamos verificar os valores maximos e minimos das variaveis idade e gênero:

print(subbanco.age.min())
print(subbanco.age.max())
print(subbanco.gender.min())
print(subbanco.gender.max())

Output:

Perceba que a idade há valores muito altos e que a idade tem uma categoria a mais além das esperadas. Isso pode ter ocorrido por um erro de digitação, mas como não sabemos o real contexto desse erro e nem como corrigi-lo vamos excluir esses casos. Para excluir vamos usar os operadores lógicos, vamos excluir todos so casos que tenha mais de 100 anos e todos os casos de gênero que tenha a categoria maior que 0. Veja como fazer isso no código abaixo:

subbanco = subbanco[subbanco.age < 120]
subbanco = subbanco[subbanco.gender > 0]
subbanco

Output:

Perceba que 72 casos foram excluídos do nosso banco.

Análise descritiva

Agora no nosso objeto subbanco temos um dataframe com todos os itens da escala DASS42, categorização da DASS para cada participante, gênero e idade; todos devidamente configurados e livres de missing. Podemos começar a descrição e exploração.

Podemos descrever nossas variáveis contínuas utilizando a função describe(). No output é possível observar algumas estatísticas descritivas como média e desvio padrão.

subbanco[['depressao', 'ansiedade', 'estresse','age']].describe()

Output:

Já para as variáveis categóricas podemos utilizar a função value_counts(). Com essa função é possível ver a frequência de cada classificação:

subbanco[['depressaoClas', 'ansiedadeClas', 'estresseClas', 'gender']].apply(pd.Series.value_counts)

Output:

É possível ainda extrair mais informações estatísticas dos dados, como: mediana, quartil, moda e variância. Veja o exemplo abaixo com a variável depressao:

print('Mediana:')
print(subbanco['depressao'].median()) #mediana
print('Quartil:')
print(subbanco['depressao'].quantile()) #quartil
print('Moda:')
print(subbanco['depressao'].mode()) #moda
print('Variância:')
print(subbanco['depressao'].var()) #variância

Output:

Podemos utilizar a função groupby() para comparar diferentes segmentos da amostra. Por exemplo, se eu quero saber: “quem tem os maiores índices de depressão: homens ou mulheres?”

Usando a função groupby() eu consigo visualizar determinado resultado filtrando pela variável escolhida. Veja um exemplo:

subbanco.groupby('gender')['depressao', 'ansiedade', 'estresse'].mean()

Output:

Nesse exemplo é possível visualizar a média do escore total dos participantes divididos pelas categorias de gênero.

Agora iremos contabilizar o número de participantes separados por gênero e que tenha apresentado escore de depressão acima de 9:

subbanco[subbanco.depressao > 9].groupby('gender')['depressao'].count()

Output:

Também podemos utilizar de gráficos para visualizar e descrever nossos dados. Por exemplo, podemos nos utilizar dos histogramas para visualizar como os dados estão distribuídos.

subbanco[['depressao', 'ansiedade', 'estresse', 'age']].hist(figsize=(4, 5), bins=50, xlabelsize=8, ylabelsize=8);

Output:

Por fim, podemos visualizar as classificações finais utilizando o gráfico de barras e a biblioteca matplotlib:

plt.figure(figsize=(15, 4))ax = plt.subplot(1, 3, 1)
subbanco['depressaoClas'].value_counts().plot(ax=ax, kind='bar')
ax.set_title('Depressão')
ax = plt.subplot(1, 3, 2)
subbanco['ansiedadeClas'].value_counts().plot(ax=ax, kind='bar')
ax.set_title('Ansiedade')
ax = plt.subplot(1, 3, 3)
subbanco['estresseClas'].value_counts().plot(ax=ax, kind='bar')
ax.set_title('Estresse')

Output:

Todos os métodos descritos acima podem ser estendidos para criar análises muito mais ricas e complexas. O código completo está disponível no notebook aqui.

Espero que tenha gostado e qualquer dúvida, comentário ou observação é muito bem-vinda! Fique à vontade para se manifestar e vamos aprender juntos! Se preferir, você pode me contatar pelo dalton.bc96@gmail.com

Obrigado pela leitura!

--

--