Como dominar a principal biblioteca de análise de dados do Python em 20 minutos

Artigo traduzido para o português do original escrito por Fabian Bosler em 12/set/2019.
Você pode acessar o artigo original aqui.

Esse artigo trata de problemas e de desafios típicos que analistas de dados enfrentam regularmente. Iremos resolver esses problemas e tratar desses desafios com o uso da biblioteca de análise e manipulação de dados mais poderosa do Python, Pandas.

Nester artigo, iremos revisar os seguintes temas:

  • Setup
  • Carregando os dados
  • Inspecionar/Ordenar/Filtrar dados
  • Funções analíticas

Você pode achar o Notebook Jupyter completo aqui. Mas insisto que você passe por todos os passos do artigo. Afinal, a prática faz a perfeição.

Pré-requisitos:

Ambiente de trabalho Python (sugiro o Jupyter Notebook). Caso ainda não tenha feito esse setup, não se preocupe. Na semana passada, falamos sobre como instalar Anaconda e como abrir o seu primeiro notebook Jupyter. Caso ainda não o tenha feito, dê uma olhada no artigo. Arrumar tudo e ficar pronto para iniciar leva menos de 10 minutos.

1. Setup

Antes de qualquer manipulação de dados, vamos arrumar alguns dados. Vamos usar dados do Relatório de Felicidade Mundial de 2019. Irei fornecer uma versão levemente ajustada dos dados brutos, incluindo continentes.

Esse repo do GitHub contém os dados e o código. Se você não estiver familiarizado com o GitHub, você também pode baixar um arquivo zipado a partir desse link. Descomprima o arquivo e mova o conteúdo (especialmente o happiness_with_continent.csv) para o mesmo diretório do seu Jupyter Notebook (caso ainda não tenha, então crie um).

No novo notebook rode ‘import pandas as pd’ (i.e., importa a biblioteca Pandas no notebook para poder acessar suas funcionalidades.)

Eu gosto de ajustar um pouco as preferências do meu notebook dessa forma:

from IPython.core.display import display, HTML display(HTML(".container {width:90% !important;}"))

Esses comandos deixam o Notebook mais largo e por conseguinte utilizam mais espaço de tela (em geral, notebooks têm largura fixa, o que não fica bom com telas largas).

2. Carregando os dados

Pandas armazena dados como Series (uma coluna) ou como DataFrame (uma ou mais colunas), onde um DataFrame é apenas a combinação de uma ou mais Series.

Nota: Sempre que carregarmos dados com algumas das funções a seguir, o resultado será armazenado num DataFrame.

pd.read_csv

Para mim read_csv é o principal método de carregar dados do Pandas. Esse método simplesmente se alinha melhor com o modo como penso sobre dados, que é basicamente tabular.

Você pode carregar dados de um arquivo local dessa forma:

 data = pd.read_csv('happiness_with_continent.csv') 

Ou você pode ler dados da internet diretamente num DataFrame, dessa forma:

data = pd.read_csv('https://raw.githubusercontent.com/FBosler/you- datascientist/master/happiness_with_continent.csv') 

Do Excel ou do Google Sheets

Carregar dados do Excel é bem fácil. Do Google Sheets é um pouco mais complicado pois você precisa passar pelo processo de autenticação antes. Você pode ler sobre como extrair dados do Excel e do Google Sheets aqui.

pd.read_clipboard

Essa opção eu raramente uso, mas certamente funciona no caso de tabelas menores. Marque e copie (ctrl + c) a tabela do Google Sheets por exemplo e rode pd.read_clipboard().

Exemplo: navegue para essa página (primeira planilha pública que pude encontrar) e marque a área como indicado na imagem.

Depois do ctrl + c os dados irão para o seu clipboard, você poderá então usar pd.read_clipboard

Após rodar pd.read_clip_board nos dados copiados do Google sheet com parâmetro index_col=’name’

Alguns parâmetros importantes para as funções baseadas em read_csv (e read_clipboard):

  • sep: separador das colunas (padrão é vírgula mas também pode ser tab)
  • header: padrão é ‘infer’ (i.e., Pandas infere qual o seu header), alternativas são um inteiro or uma lista de inteiros (para nomes multi-nível). E.g., você poderia ter header=3 e o dataframe começaria na linha 4 (porque o Python é índice-0) como header. Se os dados não contiverem header use header=none
  • names: nomes das colunas. Se você quiser usar esse parâmetro para sobrescrever quaisquer nomes inferidos pelo Pandas, você deve especificar header=0 (or qualquer linha onde estão os nomes das colunas), caso não o faça, você terá os seus nomes como nomes das colunas e os nomes originais das colunas na primeira linha. O parâmetro names espera receber uma lista, e.g.g [‘sua col 1, ‘sua col 2’, …, ‘sua última col’]
  • index_col: carrega um índice (i.e., aplicamos um índice chamado name. Iremos ver mais sobre índices adiante)
  • skiprows: pula as primeiras x linhas, isso é útil quando o arquivos contem algum meta-dado no começo, como autor ou outras informações
  • skipfooter: pula as últimas x linhas, útil quando há meta-dados no final do arquivo
  • parse_date: esse parâmetro diz ao Pandas quais colunas deveriam ser interpretadas como data (e.g., pd.read_csv(happiness_with_continent.csv, parse_date=[‘Year’]). O parseador padrão funciona razoavelmente bem de largada. Em casos em que encontre alguma formatação esquisita, Pandas pode trabalhar com parseadores de datas customizados (para os quais você deveria especificar a lógica de parseamento)

Existem outros parâmetros, porém menos usados. Você pode checar ao rodar pd.read_csv? numa célula (adicionar o ponto de interrogação após um comando irá imprimir o texto de ajuda).

Não importa de que forma lemos os dados, queremos armazena-los numa variável. Fazemos isso determinando o resultado da leitura a uma variável dessa forma: data = pd.read_clipboard() ou data = pd.read_csv(‘nome_do_arquivo.csv’)

Métodos adicionais de leitura

Raramente uso esse métodos, mas também estão implementados no Pandas:

  • read_feather
  • read_fwf
  • read_gbq
  • read_hdf
  • read_html
  • read_json
  • read_msgpack
  • read_parquet
  • read_pickle
  • read_sas
  • read_sql
  • read_sql_query
  • read_sql_table
  • read_stata
  • read_table

3. Inspecionar/Ordenar/Filtrar dados

Inspecionando linhas – primeira, última e aleatoriamente

Existem três formas padrão de visualizar dados num Notebook: head, tail e sample. head mostra as primeiras linhas, tail mostra as últimas e sample mostra linhas aleatórias.

#revisando os dados: as cinco primeiras linhas
data.head(5)
data.head(x) traz as x primeiras linhas da base de dados
#revisando os dados: as cinco últimas linhas
data.tail(5)

data.tail(x) traz as x últimas linhas da base de dados

#revisando os dados: cinco linhas aleatórias
data.sample(5)

data.sample(x) traz X linhas aleatórias da base de dados

Note que há alguns pontos antes da coluna “gini household income reported in Gallop, by wp5-year”. Isso significa que há colunas que não estão visíveis. Para alterar a configuração do seu Notebook e mostrar mais colunas/linhas, rode o seguinte comando:

pd.set_option('display.max_columns', <number of columns you want>) pd.set_option('display.max_rows', <number of rows you want>)
# Eu geralmente uso
pd.set_option('display.max_columns', 50) pd.set_option('display.max_rows', 8)

Contudo, fique atento para o fato de que frequentemente os arquivos que você estiver carregando são tão grandes (1GB+) que não será possível mostrar todos os dados por questão de performance. Por isso, você deveria tentar se familiarizar com os dados em nível mais alto e não depender de passar visualmente pelas linhas.

Inspecionando – shape, columns, index, info, describe

data.shape retorna as dimensões do DataFrame. No nosso exemplo, 1704 linhas e 27 colunas.

IN:
data.shape
OUT:
(1704, 27)

data.columns retorna uma lista com os nomes de todas as colunas no DataFrame.

IN:
data.columns
OUT:
Index(['Country name', 'Year', 'Life Ladder', 'Log GDP per capita', 'Social support', 'Healthy life expectancy at birth', 'Freedom to make life choices', 'Generosity',
'Perceptions of corruption', 'Positive affect', 'Negative
affect',
'Confidence in national government', 'Democratic Quality',
'Delivery Quality', 'Standard deviation of ladder by country-
year',
'Standard deviation/Mean of ladder by country-year',
'GINI index (World Bank estimate)',
'GINI index (World Bank estimate), average 2000-16',
'gini of household income reported in Gallup, by wp5-year', 'Most people can be trusted, Gallup',
'Most people can be trusted, WVS round 1981-1984',
'Most people can be trusted, WVS round 1989-1993',
'Most people can be trusted, WVS round 1994-1998',
'Most people can be trusted, WVS round 1999-2004',
'Most people can be trusted, WVS round 2005-2009',
'Most people can be trusted, WVS round 2010-2014', 'Continent'],
dtype='object')

data.index retorna informação sobre o índice. Iremos falar sobre índices em mais detalhes na seção de ordenamento e filtro.

IN:
data.index
OUT:
RangeIndex(start=0, stop=1704, step=1)

data.info() retorna informação sobre os tipos e os números de observações não-nulas no DataFrame.

IN:
data.info()
OUT:
<class 'pandas.core.frame.DataFrame'> RangeIndex: 1704 entries, 0 to 1703 Data columns (total 27 columns):
Country name 1704 non-null object
Year 1704 non-null datetime64[ns]
Life Ladder 1704 non-null float64
Log GDP per capita 1676 non-null float64
Social support 1691 non-null float64
Healthy life expectancy at birth 1676 non-null float64
Freedom to make life choices 1675 non-null float64
Generosity 1622 non-null float64
Perceptions of corruption 1608 non-null float64
Positive affect 1685 non-null float64
Negative affect 1691 non-null float64
Confidence in national government 1530 non-null float64
Democratic Quality 1558 non-null float64
Delivery Quality 1559 non-null float64
Standard deviation of ladder by country-year 1704 non-null float64
Standard deviation/Mean of ladder by country-year 1704 non-null float64
GINI index (World Bank estimate) 643 non-null float64
GINI index (World Bank estimate), average 2000-16 1502 non-null float64
gini of household income reported in Gallup, by wp5-year 1335 non-null float64
Most people can be trusted, WVS round 1981-1984 125 non-null float64
Most people can be trusted, WVS round 1989-1993 220 non-null float64
Most people can be trusted, WVS round 1994-1998 618 non-null float64
Most people can be trusted, WVS round 1999-2004 491 non-null float64
Most people can be trusted, WVS round 2005-2009 630 non-null float64
Most people can be trusted, WVS round 2010-2014 671 non-null float64
Continent 1704 non-null object
dtypes: datetime64[ns](1), float64(24), object(3) memory usage: 372.8+ KB

data.describe() retorna algumas estatísticas descritivas (count, mean, std, min, 25%, 50%, 75%, max) a respeito das colunas numéricas do DataFrame:

Ordenando – data.sort_values()

Chamar sort_values sem qualquer parâmetro não servirá de muita coisa. Na verdade, vai chamar um erro dizendo que falta um argumento chamado by. Esse erro faz sentido. Temos que dizer ao Pandas qual ou quais colunas queremos ordenar.

Por exemplo, poderíamos ordenar por ano, ou por ano e nome de país, dessa forma:

data.sort_values(by='Year') 
data.sort_values(by=['Year','Country name'])
data.sort_values(by=['Country name','Year'])

Nota: caso passe múltiplos valores, o ordenamento será feito com base na ordem dos valores.

O ordenamento padrão é “do menor para o maior”. Contudo, é fácil mudar esse comportamento.

data.sort_values(by='Year', ascending=True)
data.sort_values( by=['Country name','Year'],ascending=[False,True])

Nota: “Ascending” é True por padrão, ie, o menor valor primeiro. Caso queira o maior valor primeiro então você terá que especificar ascending=False.

Ordenamento – data.sort_index()

Além de ordenar por coluna, é possível ordenar por índice. Para ordenar por índice, chame: data.sort_index() ou data.sort_index(ascending=False). A primeira é para ordem ascendente, a segunda para descendente.

Filtrando – colunas

Ordenamento é útil e tudo mais, porém muitas vezes precisamos ir mais a fundo num sub-conjunto particular dos dados. Às vezes você pode querer olhar para uma única coluna ou para múltiplas.

Selecionando uma coluna:
Há duas formas de selecionar uma coluna em particular. Digamos que você queira a coluna Year. Podemos fazer isso dessas formas:

  • data[‘Year’], ou
  • data.Year (não use essa forma)

Ambas fazem a mesma coisa.

Nota: Por que há duas maneiras de fazer exatamente a mesma coisa? A razão é conveniência. A segunda forma é um pouco mais rápida, pois você só precisa de dois pontos e do nome da coluna. Enquanto que na primeira você precisa do nome da coluna, duas aspas e dois colchetes.

Contudo, eu recomendo fortemente usar a primeira forma, pois evita alguns problemas mais a frente e é consistente com a seleção de múltiplas colunas.

Selecionando múltiplas colunas:
Caso você queira selecionar Country Name e Life Ladder, então é assim que você deverá fazer (cuidado: colchetes duplos):

Selecionando as colunas “Country name” e Life Ladder” e retornando cinco linhas de amostra.

Nota: preste especial atenção aos colchetes duplos antes da primeira e depois da última coluna que você quer selecionar! Sempre que usar colchetes duplos, o resultado será um DataFrame (mesmo quando selecionar apenas uma coluna com colchetes duplos). Quero enfatizar bem esse ponto pois mesmo eu às vezes cometo esse tipo de erro! Caso queira selecionar múltiplas colunas, mas abrir apenas um conjunto de colchetes, o conteúdo no meio dos colchetes será considerado como uma coluna. Desnecessário dizer que os seus dados não contém a coluna combinada.

Filtrando – linhas

Conseguir selecionar colunas específicas é apenas meio caminho andado. Contudo, selecionar linhas é tão fácil quanto.

No Pandas, as linhas são selecionadas por índice. Você pensar em índices como os nomes das linhas. Quando você selecionar linhas de um DataFrame, isso acontece pela sobreposição do DataFrame por uma Series de mesmo índice contendo apenas valores True ou False (True significa que a linha deve ser selecionada, False significa que não). Todavia, na maior parte do tempo, essa seleção explícita de índice é abstraída sem que o usuário note. Eu ainda acho muito importante entender como funciona todo o processo de seleção de linhas.

Você pode selecionar uma ou múltiplas linhas por índice. Existem dois métodos de fazer isso:

  • data.iloc ou
  • data.loc

iloc:
data.iloc permite selecionar linhas (e opcionalmente colunas) por posição (ie, pelo número da linha).

iloc – selecionando uma linha:
A sintaxe fica assim data.iloc[row_number (, col_number)] onde a parte em parêntesis é opcional.

Nota: a formatação parece pouco convencional, isso é porque quando se seleciona uma única linha, uma Series será retornada.

iloc – selecionando múltiplas linhas:
A sintaxe fica assim data.iloc[start_row:end_row, (,start_col:end_col)] onde a parte em parêntesis é opcional.

Como alternativa, você pode especificar quais colunas quer selecionar.

loc:
data.loc em contraste a iloc, permite selecionar linhas (e colunas) através de:

  • rótulo/índice ou
  • com uma procura booleana/condicional

Para melhor explicar o primeiro item e também melhor distinguir do iloc, iremos transformar o Country Name no índice do DataFrame. Para fazer isso, rodamos o seguinte comando:

data.set_index('Country name',inplace=True)

O comando set_index cria um novo índice no DataFrame. E também especificando inplace=True, asseguramos que o DataFrame será modificado. Caso inplace=True não seja especificado, apenas veríamos como o DataFrame foi modificado após aplicar a operação, porém não aconteceria nenhuma alteração nos dados subjacentes.

Agora o DataFrame deveria ter os nomes dos países como índice. O índice não é mais numérico e usa os nomes dos países.

loc – selecionando linha(s) por um rótulo de índice:
A sintaxe fica assim data.loc[index_label (.col_label)], onde a parte entre parêntesis é opcional.


loc – selecionando linhas e uma coluna por rótulo de índice e de coluna:

data.loc[‘United States’, ‘Life Ladder’] seleciona a coluna ‘Life Ladder’ para todas as linhas cujo índice é ‘United States’

loc – selecionando linha(s) por múltiplos rótulos de índice:

data.loc[[‘United States’, ‘Germany’]] seleciona todas as linhas cujos índices sejam ‘United States’ ou ‘Germany’

Notas:

  • Como antes, quando selecionando múltiplas colunas, temos que nos assegurar que colocamos colchetes duplos. Caso esqueça de fazer isso, as colunas serão consideradas como um nome longo e inexistente.
  • Usamos sample(5) para mostrar que há Germany no meio. Assumindo que usemos head(5) ao invés, somente começaríamos a ver Germany depois de 12 linhas de United States.
  • Loc retorna as linhas na ordem fornecida, independente da ordem verdadeira. Por exemplo, se tivéssemos especificado Germany primeiro e United States em segundo, teríamos 13 linhas de Germany e depois 12 linhas de United States.

loc – selecionando linhas e colunas por múltiplos rótulos de índice:

Você também pode especificar nomes de colunas para as linhas que você quer obter.

Nota: colocamos a seleção de linhas [‘Germany’, ‘United States’] e de colunas [‘Year’, ‘Life Ladder’] em duas linhas separadas.

loc – selecionando linha(s) por uma faixa de rótulos de índice:

Essa forma de selecionar pode parecer um pouco estranha, pois uma faixa de rótulos de índice (‘Denmark’:’Germany’) não é tão intuitiva quanto usar uma faixa numérica (903:907) pro iloc.

Especificar uma faixa de rótulos base-se na ordem original do índice, e não funcionará no caso de um índice não ordenado.

Contudo, assumindo que o seu índice esteja ordenado, ou que você o tenha ordenado antes de selecionar uma faixa, você pode fazer o seguinte:

loc – procura booleano/condicional:

Procura booleana ou condicional é realmente a parte mais interessante. Como dito antes, quando selecionando linhas, a procura condicional acontece pela sobreposição do DataFrame com uma máscara de valores Falsos (False) ou Verdadeiros (True).

No exemplo a seguir, criamos um pequeno DataFrame de índice [‘A’, ‘B’, ‘C’, ‘D’] e alguns valores aleatórios entre 0 e 10.

Então usamos df.loc[overlay] para selecionar apenas as linhas com valor True no índice.

IN:
from numpy.random import randint
index = ['A','B','A','D']

## cria o DataFrame ##
df = pd.DataFrame(
index = index,
data = { 'values':randint(10,size=len(index))
})
print('DataFrame:')
print(df)

OUT:
DataFrame:
values
A 8
B 2
A 3
D 2

IN:
## cria o overlay ##
overlay = pd.Series(
index=index,
data=[True,False,True,False]
)
print('\nOverlay:')
print(overlay)

OUT:
Overlay:
A True
B False
A True
D False
dtype: bool

IN:
## seleciona apenas as linhas True ##
print('\nNovo DataFrame:')
print(df.loc[overlay])

OUT:
Novo DataFrame:
values
A 8
A 3

A mesma lógica pode ser usada para selecionar linhas com base em múltiplas condições.

Primeiro criamos uma ‘máscara’ booleana, dessa forma:

Filtragem baseada no valor de ‘Life Ladder’ retorna uma Series com valores True/False

E então usamos essa ‘máscara’ para selecionar apenas as linhas que batem com a condição especificada. Dessa forma:

Essa primeira opção retorna precisamente o mesmo resultado que a outra alternativa. Contudo, essa alternativa é um pouco mais legível. A melhora na legibilidade fica ainda mais aparente quando aplicamos múltiplas condições.

Nota: Usamos ‘&’ para filtrar linhas onde múltiplas condições se aplicam ao mesmo tempo. Podemos usar ‘|’ para filtrar colunas onde múltiplas condições se aplicam.

loc – procura condicional avançada com fórmulas customizadas:

Também é possível e bem fácil usar fórmulas customizadas como condições e aplicá-las para selecionar colunas.

No exemplo a seguir, selecionamos apenas os anos divisíveis por 3 e os continentes que contiverem a palavra America. O caso é difícil de ser encontrado mas serve como exemplo.

Ao invés de funções lambda, você poderia também usar e definir funções muito mais complicadas. Você poderia até mesmo (embora eu não recomende) fazer chamadas a APIs a partir de uma função customizada e usar os resultados das chamadas para faltar o seu DataFrame.

4. Funções analíticas

Agora que estamos confortáveis filtrando e ordenando dados, vamos seguir em frente e ver algumas funcionalidades analíticas mais avançadas.

Funções padrão

Assim como as funções de leitura, existem muitas funções analíticas implementadas no Pandas.

Vou listar e detalhar as que uso com mais frequência. Contudo, e aí que está a beleza da coisa, mesmo eu consumo encontrar novas e úteis funções de vez em quando. Por isso, nunca pare de ler e explorar!

  • max/min
  • sum
  • mean/median/quartile
  • idxmin/idxmax

Nota: todas as funções podem ser aplicadas em sentido-coluna, mas também em sentido-linha. A aplicação sentido-linha faz pouco sentido no nosso exemplo. Contudo, é comum você ter em mãos dados onde você quer comparar colunas diferentes, onde então faz sentido a aplicação sentido-linha.

Sempre que chamarmos as funções mencionadas, o parâmetro default axis=0 é passado (para aplicação sentido-coluna). Todavia, podemos sobrescrever esse parâmetro e passar axis=1 (para aplicação sentido-linha).

max/min

Chamar a função max() irá retornar (sempre que possível) o valor máximo de cada coluna. A função min() irá retornar o mínimo.

sum

Chamar a função sum() irá retornar (sempre que possível) a soma de cada coluna.

Nota: Sum irá concatenar strings numa outra string, o que resulta em AsiaAsiaAsiaAsiaAsiaAsiaAsiaAsiaAsiaAsiaAsiaEu… no caso da coluna Continente.

mean/median/quantile

Chamar as funções mean, median ou quantile irá retornar a média ou a mediana, respectivamente.

idxmin/idxmax

Chamar as funções idxmax ou idxmin irá retornar o índice da linha onde o primeiro mínimo/máximo for encontrado. Contudo, somente é possível chamar essas funções em colunas que contenham números.

Isso significa, por exemplo, que Denmark tem o maior “Life Ladder”, Qatar tem o maior “Log GDP per capita” e New Zealand tem o maior valor de “Social support”.

idxmin funciona da mesma forma que idxmax.

Recap: não se esqueça que é possível aplicar essas funções tanto em sentido-coluna quanto em sentido-linha.

Funções customizadas

Você também pode escrever funções customizadas e usá-las nas suas linhas e colunas. Esses são dois tipos de funções customizadas:

  • Funções nomeadas
  • Funções Lambda

Funções nomeadas são funções definidas pelo usuário. Elas são definidas através do uso da palavra-chave reservada def, desse modo:

Funções nomeadas

Função: 
def above_1000_below_10(x):
try:
pd.to_numeric(x)
except:
return 'no number column'

if x > 1000:
return 'above_1000'
elif x < 10:
return 'below_10'
else:
return 'mid'

IN:
data['Year'].apply(above_1000_below_10)

OUT:
Country name
Afghanistan above_1000
Afghanistan above_1000
Afghanistan above_1000
Afghanistan above_1000
...
Zimbabwe above_1000
Zimbabwe above_1000
Zimbabwe above_1000
Zimbabwe above_1000

Name: Year, Length: 1704, dtype: object

Aqui criamos uma função chamada above_1000_below_10 e aplicamos na nossa base de dados.

A função inicialmente checa se o valor é conversível para a um número e caso não seja, retorna ‘no number column’ (coluna sem números). Caso contrário, a função retorna ‘above_1000’ se o valor for acima de 1000 e ‘below_10’ se o valor for abaixo de 10. Retorna ‘mid’ caso nenhum dois dois de aplique.

Funções Lambda

Para mim, funções Lambda são usadas muito mais frequentemente que funções customizadas. Em geral, essas são funções curtas usadas uma única vez. O nome soa um pouco esdrúxulo, mas uma vez que você entenda seu uso, são muito convenientes. Por exemplo, poderíamos separar a coluna de continente por espaço e daí pegar a última palavra dos resultados.

 
IN:
data['Continent'].apply(lambda x: x.split(' ')[-1])

OUT:
Country name
Afghanistan Asia
Afghanistan Asia
Afghanistan Asia
Afghanistan Asia
...
Zimbabwe Africa
Zimbabwe Africa
Zimbabwe Africa
Zimbabwe Africa
Name: Continent, Length: 1704, dtype: object

Nesse exemplo, também vamos de linha em linha (como especificada em axis=1). Nós retornamos o nome da linha (que na verdade é o índice) quando o ano da linha for menor que 2015 ou então o continente daquela linha. Tarefas como essas realmente são comuns quando você que fazer limpeza de dados condicional.

Combinando colunas

Às vezes você quer adicionar, subtrair ou apenas combinar duas ou mais colunas, algo que não poderia ser mais simples.

Digamos que você queira adicionar as colunas ‘Year’ e ‘Life Ladder’ (planejado, eu sei, mas vamos fazer para entender o ponto em questão).

O mesmo com -, *, / e muito mais que você pode fazer com operações string, assim:

Nota: no exemplo acima, queremos combinar duas colunas como strings. Para fazer isso, temos que interpretar data[‘Year’] como string. Fazemos isso usando .astype(str) na coluna. Mantendo a discussão breve, não iremos analisar tipos e conversão de tipos nesse artigo mas discutiremos esses tópicos num outro artigo.

groupby

Até agora, todos os cálculos foram aplicados ao conjunto inteiro de dados, uma linha ou uma coluna. Contudo, e aqui é onde fica interessante, também podemos agrupar nossos dados e calcular indicadores para grupos individuais.

Então digamos que queiramos saber o maior ‘Life Ladder’ por país.


Digamos que queiramos por ano o país com o maior Life Ladder.

Ou grupos multi-nível, digamos que queiramos da combinação continente/ano saber o país com o maior ‘Life Ladder’.

Como antes, podemos usar muitas funções padrão ou customizadas (nomeadas ou não nomeadas) para, por exemplo, retornar um país aleatório por grupo:

Nota: groupby sempre retorna um valor por grupo. Então a menos que você esteja agrupando por uma coluna que contém apenas valores únicos, o resultado será um conjunto de dados menor.

transform

Às vezes você não quer apenas um valor por grupo, ao invés disso você quer o valor calculado para o grupo para cada linha pertencente àquele grupo. Você pode fazer isso dessa forma:

Onde você consegue a soma de todos os valores ‘Life Ladder’ de um país. Você também poderia fazer dessa forma:

Para conseguir a mediana por país. Nós podemos então calcular a diferença do valor de cada ano assim (pois transform preserva o índice):

Este artigo deveria abrir várias possibilidades para você. Inicialmente, eu também queria incluir ‘accessors’, manipulação de tipos e concatenação, fusão e união de DataFrames, mas devido à extensão do artigo, movi esses tópicos para outro artigo.

Espero encontrá-lo em breve.

Veja também: