Capítulo 7, Básico
Selecionar colunas e linhas
Quase nunca você precisa da tabela inteira. Precisa de certas colunas, de certas linhas, de um pedaço. O Pandas tem uma ferramenta por rótulo, outra por posição, e a diferença entre elas é a causa de quase todo bug de seleção.
Colunas
Um nome devolve uma Series, e uma lista de nomes devolve um DataFrame. Os colchetes duplos não são enfeite: o externo é "selecionar de df" e o interno é "uma lista de nomes":
import pandas as pd
pd.set_option("display.width", 170)
pd.set_option("display.max_columns", 20)
df = pd.read_csv("dados/funcionarios_15.csv")
print(type(df["salario"]).__name__, type(df[["salario"]]).__name__)
print(df[["nome", "departamento", "salario"]].head(3))
Series DataFrame
nome departamento salario
0 Ana Souza Engenharia 4500
1 Bruno Lima Marketing R$ 4650
2 Carla Mendes engenharia 4800
Uma lista com um nome ainda é uma lista, e devolve um DataFrame com uma coluna. É a pegadinha mais comum desta parte.
`.loc` e `.iloc`
O .loc seleciona por rótulo e o .iloc, por posição inteira. Em uma tabela com o índice padrão, parecem a mesma coisa, mas com outro índice a diferença aparece:
print(len(df.loc[0:3]), len(df.iloc[0:3]))
print(df.iloc[-1]["nome"])
4 3
Ana Souza
.loc[] | .iloc[] | |
|---|---|---|
| Seleciona por | Rótulos | Posições inteiras |
| Linhas | Rótulos do índice | 0, 1, 2... |
| Fim da fatia | Geralmente incluído | Excluído |
O df.loc[0:3] devolve 4 linhas (0, 1, 2 e 3), e o df.iloc[0:3] devolve 3. Uma fatia que parece igual dá um resultado diferente, e essa assimetria pega quase todo mundo que vem das fatias do Python.
Um índice que não é 0, 1, 2
Com o id_funcionario como índice, a mesma entrada cai em linhas diferentes:
por_id = df.set_index("id_funcionario")
print(por_id.loc[103, "nome"], por_id.iloc[2]["nome"])
print(por_id.loc[103:105, "nome"].tolist())
Carla Mendes Carla Mendes
['Carla Mendes', 'Diego Rocha', 'Elisa Fernandes']
O .loc[103] busca o rótulo 103 (Carla), e o .iloc[2] busca a posição 2, que por acaso é a mesma pessoa. A fatia .loc[103:105] traz os três rótulos, inclusive o 105. Com o iloc, um número como 103 seria uma posição que não existe.
Um índice pode repetir, e aqui ele repete: o id 101 aparece duas vezes. O .loc devolve todas as linhas com aquele rótulo, e o tipo do resultado muda de Series para DataFrame:
print(type(por_id.loc[103]).__name__, type(por_id.loc[101]).__name__)
print(por_id.loc[101].shape)
print(por_id.index.is_unique)
Series DataFrame
(2, 9)
False
Um código que assume "um id, uma linha" e usa .loc[id] quebra (ou, pior, passa silenciosamente com um resultado de outro tipo) assim que há um id repetido. O capítulo 10 resolve a repetição.
Linhas e colunas juntas
O .loc aceita linhas e colunas na mesma chamada, e a condição pode ser uma máscara:
print(df.loc[df["experiencia"] > 6, ["nome", "salario"]])
print(df.loc[2:4, "nome":"cidade"])
nome salario
6 Gabriela Nunes 5400
7 Henrique Costa R$ 5550
14 Ana Souza 6600
nome departamento cidade
2 Carla Mendes engenharia Porto Alegre
3 Diego Rocha Ciência de Dados Rio de Janeiro
4 Elisa Fernandes RH NaN
Para um valor só, at (por rótulo) e iat (por posição) são mais diretos e mais rápidos do que loc e iloc:
print(df.at[0, "nome"], df.iat[0, 1])
Ana Souza Ana Souza
Selecionar também cria uma tabela nova
Uma seleção devolve um objeto independente. Alterar o resultado não altera a tabela original, e isso é uma garantia do Pandas 3 (a cópia sob escrita, que o capítulo 27 detalha):
parte = df[["nome", "idade"]]
parte.loc[0, "nome"] = "ALTERADO"
print(df.at[0, "nome"])
Ana Souza
Exercício 1
Um recorte por posição e outro por rótulo
Escreva terceiro_a_quinto(tabela), que devolva as linhas na posição 2, 3 e 4, só com as colunas nome e departamento, usando iloc e loc de forma que o resultado tenha 3 linhas e 2 colunas.