Traduzido de: 12 Useful Pandas Techniques in Python for Data Manipulation
por:
Introdução
Python está se tornando a linguagem preferida para ‘data scientists’ – e por boas razões. Python fornece o maior ecossistema entre linguagens de programação e a profundidade de suas bibliotecas de computação científica é muito boa. Se você está começando a aprender Python, dê uma olhada no caminho de aprendizagem em Python.
Entre suas bibliotecas de computação científica, eu creio que Pandas seja a mais útil para operações de ‘Data Science’. Pandas e Scikit-learn fornecem quase tudo necessário para um ‘data scientist’. Este artigo se concentra em fornecer 12 maneiras de manipulação de dados em Python. Eu também compartilhei algumas dicas e truques que permitirão que você trabalhe mais rápido.
Gostaria de recomendar que você olhe para os códigos de exploração de dados antes de começar. Para ajudá-lo a entender melhor, tomei um conjunto de dados para executar essas operações e manipulações.
Conjunto de dados: Eu usei o conjunto de dados do problema de previsão de empréstimo. Faça o download do conjunto de dados e comece.
Vamos começar
Começarei por importar módulos e carregar o conjunto de dados no ambiente Python:
import pandas as pd import numpy as np data = pd.read_csv("train.csv", index_col="Loan_ID")
# 1 – Indexação booleana
O que fazer se você quiser filtrar os valores de uma coluna com base nas condições de outro conjunto de colunas? Por exemplo, queremos uma lista de todas as mulheres que não têm pós-graduação e têm um empréstimo. A indexação booleana pode ajudar aqui. Você pode usar o seguinte código:
data.loc[(data["Gender"]=="Female") & (data["Education"]=="Not Graduate") & (data["Loan_Status"]=="Y"), ["Gender","Education","Loan_Status"]]
Saiba Mais: Selecionando e Indexando com Pandas
# 2 – Função apply()
É uma das funções mais usadas para manipular dados e criar novas variáveis. Através de uma função, apply() retorna um valor depois de ler cada linha/coluna de uma tabela de dados. A função pode ser padrão ou definida pelo usuário. Por exemplo, aqui ele pode ser usado para encontrar os valores nulos em cada linha e coluna.
#Cria nova função: def num_missing(x): return sum(x.isnull()) #Aplica por coluna: print "Missing values per column:" print data.apply(num_missing, axis=0) #axis=0 define que a função deve ser aplicada em cada coluna #Aplica por linha: print "\nMissing values per row:" print data.apply(num_missing, axis=1).head() #axis=1define que a função deve ser aplicada em cada linha
Desse jeito, temos o resultado desejado.
Nota: a função head() é usada na segunda saída porque contém muitas linhas. Sabia mais: Referência Pandas (apply)
# 3 – Imputar valores ausentes
fillna() faz isso de uma só vez. Ela é usado para atualizar valores ausentes com a média, moda ou mediana da coluna. Vamos imputar as colunas “Gender”, “Married” e “Self_Employed” com suas respectivas modas.
#Primeiro importamos a função para achar a moda
from scipy.stats import mode
mode(data['Gender'])
Retorno: ModeResult(mode=array([‘Male’], dtype=object), count=array([489]))
Isso retorna tanto a moda quanto a contagem. Lembre-se que a moda pode ser um array, pois pode haver vários valores com alta freqüência. Tomaremos o primeiro por padrão sempre usando:
mode(data['Gender']).mode[0]
‘Male’
Agora podemos preencher os valores ausentes e verificar usando a técnica # 2.
#Insira os valores: data['Gender'].fillna(mode(data['Gender']).mode[0], inplace=True) data['Married'].fillna(mode(data['Married']).mode[0], inplace=True) data['Self_Employed'].fillna(mode(data['Self_Employed']).mode[0], inplace=True) #Agora verifique o número de valores ausentes para confirmar: print data.apply(num_missing, axis=0)
Assim, fica confirmado que os valores ausentes foram inseridos. Note que esta é a forma mais primitiva de inserção. Outras técnicas sofisticadas incluem a modelagem dos valores ausentes, usando médias agrupadas (média / modo / mediana). Vou cobrir essa parte em meus próximos artigos.
Saiba mais: Pandas Reference (fillna)
# 4 – Pivot table
Você pode usar pandas para criar tabelas dinâmicas no estilo MS Excel. Por exemplo, neste caso, tome-se a coluna “LoanAmount” que tem valores ausentes. Podemos imputá-los usando o valor médio de cada grupo de “Gender”, “Married” e “Self_Employed”. A média de ‘LoanAmount’ de cada grupo pode ser determinada como:
#Determine a tabela pivot
impute_grps = data.pivot_table(values=["LoanAmount"], index=["Gender","Married","Self_Employed"], aggfunc=np.mean)
print(impute_grps)
Saiba mais: Referência Pandas (Tabela Pivô)
# 5 – Multi-Indexação
Se você notar o resultado do passo 3, ele tem uma propriedade estranha. Cada índice é composto por uma combinação de 3 valores. Isso é chamado Multi-Indexação e ajuda a executar operações muito rápido.
Continuando o exemplo do # 3, temos os valores para cada grupo, mas eles não foram imputados. Isso pode ser feito usando as técnicas aprendidas até agora.
#itere somente as linhas com valores ausentes em LoanAmount
for i,row in data.loc[data['LoanAmount'].isnull(),:].iterrows():
ind = tuple([row['Gender'],row['Married'],row['Self_Employed']])
data.loc[i,'LoanAmount'] = impute_grps.loc[ind].values[0]
#Cheque de novo os valores ausentes para confirmar:
print data.apply(num_missing, axis=0)
Nota:
- Multi-indexação requer uma tupla para definir grupos de índices na instrução loc. Esta é uma tupla usada em função.
- O sufixo .values[0] é necessário porque, por padrão, é retornado um elemento de série que tem um índice que não corresponde ao do frame de dados. Neste caso, uma atribuição direta dá um erro.
# 6. Crosstab
Esta função é usada para obter uma “sensação” (visão) inicial dos dados. Aqui, podemos validar algumas hipóteses básicas. Por exemplo, neste caso, “Credit_History” deverá afetar significativamente o status do empréstimo. Isso pode ser testado usando tabulação cruzada como mostrado abaixo:
pd.crosstab(data["Credit_History"],data["Loan_Status"],margins=True)
Estes são números absolutos. Mas, as porcentagens podem ser mais intuitivas para ganhar noções rápidas. Podemos fazer isso usando a função apply:
def percConvert(ser): return ser/float(ser[-1]) pd.crosstab(data["Credit_History"],data["Loan_Status"],margins=True).apply(percConvert, axis=1)
Agora, é evidente que as pessoas com um histórico de crédito têm chances muito maiores de obter um empréstimo, posto que 80% das pessoas com histórico de crédito tem um empréstimo em comparação com apenas 9% sem histórico de crédito.
Mas não é bem isso. Temos aqui uma história interessante. Desde que eu sei que ter um histórico de crédito é super importante, e se eu prever o status do empréstimo como Y para aqueles com histórico de crédito e N caso contrário? Surpreendentemente, estaremos certos em 82 + 378 = 460 vezes de 614, ou seja 75% das vezes!
Eu não vou culpá-lo se você está se perguntando por que então precisamos de modelos estatísticos. Mas confie em mim, aumentar a precisão de até 0,001% para além desta marca é uma tarefa desafiadora. Você aceitaria esse desafio?
Nota: 75% está no conjunto de treinamento. O conjunto de teste será ligeiramente diferente, mas próximo. Além disso, espero que isso dê alguma intuição sobre por que mesmo um aumento de 0,05% na precisão pode resultar em salto de 500 posições no ranking Kaggle.
Saiba mais: Pandas Reference (crosstab)
# 7 – Merge DataFrames
A fusão de dataframes torna-se essencial quando temos informações provenientes de fontes diferentes a serem agrupadas. Considere um caso hipotético onde as taxas de propriedade médias (INR por metro quadrado) estão disponíveis para diferentes tipos de propriedade. Vamos definir um dataframe como:
prop_rates = pd.DataFrame([1000, 5000, 12000], index=['Rural','Semiurban','Urban'],columns=['rates']) prop_rates
Agora podemos mesclar esta informação com o dataframe original:
data_merged = data.merge(right=prop_rates, how='inner',left_on='Property_Area',right_index=True, sort=False) data_merged.pivot_table(values='Credit_History',index=['Property_Area','rates'], aggfunc=len)
A tabela dinâmica valida a operação de mesclagem como bem-sucedida. Observe que o argumento ‘values’ é irrelevante aqui porque simplesmente estamos contando os valores.
Saiba mais: Pandas Reference (merge)
# 8 – Ordenando DataFrames
Pandas permite facilmente ordenar com base em várias colunas. Isso pode ser feito assim:
data_sorted = data.sort_values(['ApplicantIncome','CoapplicantIncome'], ascending=False) data_sorted[['ApplicantIncome','CoapplicantIncome']].head(10)
Nota: A função Pandas “sort” agora ficou obsoleta. Devemos usar “sort_values” em vez disso.
Saiba mais: Pandas Reference (sort_values)
# 9 – Plotando (Boxplot & Histograma)
Muitos de vocês podem não saber que boxplots e histogramas podem ser plotados diretamente em Pandas, sem necessidade de chamar matplotlib separadamente. Basta um único comando de 1 linha. Por exemplo, se quisermos comparar a distribuição de ApplicantIncome por Loan_Status:
import matplotlib.pyplot as plt %matplotlib inline data.boxplot(column="ApplicantIncome",by="Loan_Status")
data.hist(column="ApplicantIncome",by="Loan_Status",bins=30)
Isso mostra que a renda não é um fator decisivo por conta própria, pois não há diferença apreciável entre as pessoas que receberam e as que foram negadas o empréstimo.
Saiba mais: Pandas Reference (hist) | Pandas Referência (boxplot)
# 10 – Função de corte para binning
Às vezes, os valores numéricos fazem mais sentido se agrupados. Por exemplo, se tentarmos modelar o tráfego (#carros na estrada) com a hora do dia (minutos). O minuto exato de uma hora pode não ser relevante para a previsão de tráfego, em comparação com o período real do dia, como “Manhã”, “Tarde”, “Noite”, “Noite”, “Tarde da noite”. Modelar o tráfego desta forma será mais intuitivo e evitará o overfitting.
Aqui definimos uma função simples que pode ser reutilizada facilmente como binning qualquer variável.
#Binning: def binning(col, cut_points, labels=None): #Define min and max values: minval = col.min() maxval = col.max() #cria lista adicionando min e max a cut_points break_points = [minval] + cut_points + [maxval] #se nenhum rótulo for definido, use rótulos default 0 ... (n-1) if not labels: labels = range(len(cut_points)+1) #Binning usando a função cut colBin = pd.cut(col,bins=break_points,labels=labels,include_lowest=True) return colBin #Binning idade: cut_points = [90,140,190] labels = ["low","medium","high","very high"] data["LoanAmount_Bin"] = binning(data["LoanAmount"], cut_points, labels) print pd.value_counts(data["LoanAmount_Bin"], sort=False)
Saiba mais: Pandas Reference (cut)
# 11 – Codificação de dados nominais
Muitas vezes, encontramos um caso em que temos de modificar as categorias de uma variável nominal. Isso pode ser devido a várias razões:
- Alguns algoritmos (como Regressão Logística) exigem que todas as entradas sejam numéricas. Assim, as variáveis nominais são, em sua maioria, codificadas como 0, 1 …. (N-1)
- Às vezes, uma categoria pode ser representada de duas maneiras. Por exemplo, a temperatura pode ser gravada como “Alta”, “Média”, “Baixa”, “A”, “baixa”. Aqui, tanto “Alta” e “A” referem-se à mesma categoria. Similarmente, em “Baixa” e “baixa” há apenas uma diferença de maiúscula para minúscula. Mas, python iria lê-los como sendo diferentes níveis.
- Algumas categorias podem ter freqüências muito baixas e geralmente é uma boa idéia combiná-las.
Aqui eu defini uma função genérica que recebe entrada como um dicionário e codifica os valores usando a função replace em Pandas.
#Define uma função genérica usando a função replace def coding(col, codeDict): colCoded = pd.Series(col, copy=True) for key, value in codeDict.items(): colCoded.replace(key, value, inplace=True) return colCoded #Codificando LoanStatus como Y=1, N=0: print('Before Coding:') print(pd.value_counts(data["Loan_Status"])) data["Loan_Status_Coded"] = coding(data["Loan_Status"], {'N':0,'Y':1}) print('\nAfter Coding:') print(pd.value_counts(data["Loan_Status_Coded"]))
Contagens semelhantes antes e depois comprovam a codificação.
Saiba mais: Pandas Reference (substituir)
# 12 – Iterando sobre linhas de um dataframe
Esta não é uma operação frequentemente utilizada. Ainda assim, você não quer ficar estancado, certo? Às vezes você pode precisar iterar através de todas as linhas usando um loop for. Por exemplo, um problema comum que enfrentamos é o tratamento incorreto de variáveis em Python. Isso geralmente acontece quando:
- Variáveis nominais com categorias numéricas são tratadas como numéricas.
- Variáveis numéricas com caracteres inseridos em uma das linhas (devido a um erro de dados) são consideradas categóricas.
Portanto, geralmente é uma boa ideia definir manualmente os tipos de coluna. Para verificar os tipos de dados de todas as colunas:
#Checa os tipos: data.dtypes
Aqui vemos que Credit_History é uma variável nominal, mas que aparece como float. Uma boa maneira de resolver esses problemas é criar um arquivo csv com nomes e tipos de colunas. Desta forma, podemos fazer uma função genérica para ler o arquivo e atribuir tipos de dados de coluna. Por exemplo, aqui eu criei um arquivo csv chamado datatypes.
#Carregar o arquivo: colTypes = pd.read_csv('datatypes.csv') print colTypes
Depois de carregar este arquivo, podemos iterar através de cada linha e atribuir o tipo de dados usando a coluna ‘tipo’ para o nome da variável definida na coluna ‘recurso’.
#Iterar cada linha e aplicar o tipo de variável
#Nota: astype é utilizado para aplicar os tipos
for i, row in colTypes.iterrows(): #i: dataframe index; row: each row in series format
if row['type']=="categorical":
data[row['feature']]=data[row['feature']].astype(np.object)
elif row['type']=="continuous":
data[row['feature']]=data[row['feature']].astype(np.float)
print(data.dtypes)
Agora a coluna de histórico de crédito é modificada para o tipo ‘objeto’, que é usado para representar variáveis nominais em Pandas.
Saiba mais: Pandas Reference (iterrows)
Notas finais
Neste artigo, nós cobrimos várias funções de Pandas que podem tornar nossa vida mais fácil ao explorar dados. Além disso, definimos algumas funções genéricas que podem ser reutilizadas para atingir objetivos semelhantes em diferentes conjuntos de dados.
Veja também: Se você tem alguma dúvida relacionada a Pandas ou Python em geral, sinta-se livre para discutir conosco.
Você achou o artigo útil? Você usa algumas técnicas melhores (mais fáceis / mais rápidas) para executar as tarefas discutidas acima? Você acha que há melhores alternativas para Pandas em Python? Compartilhe suas ideias nos comentários abaixo.
Veja também:
Bela lista/resumo!
Conteúdo bem escrito!
Ajudou bastante!
Vou colocar o link nos meus favoritos.
Obrigado.