Pular para o conteúdo

    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":

    basico/cap07_selecionar.pylinhas 10 a 17
    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))
    
    Saída
    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:

    basico/cap07_selecionar.pylinhas 22 a 23
    print(len(df.loc[0:3]), len(df.iloc[0:3]))
    print(df.iloc[-1]["nome"])
    
    Saída
    4 3
    Ana Souza
    
    .loc[].iloc[]
    Seleciona porRótulosPosições inteiras
    LinhasRótulos do índice0, 1, 2...
    Fim da fatiaGeralmente incluídoExcluí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:

    basico/cap07_selecionar.pylinhas 28 a 30
    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())
    
    Saída
    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:

    basico/cap07_selecionar.pylinhas 32 a 34
    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)
    
    Saída
    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:

    basico/cap07_selecionar.pylinhas 39 a 40
    print(df.loc[df["experiencia"] > 6, ["nome", "salario"]])
    print(df.loc[2:4, "nome":"cidade"])
    
    Saída
                  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:

    basico/cap07_selecionar.pylinha 42
    print(df.at[0, "nome"], df.iat[0, 1])
    
    Saída
    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):

    basico/cap07_selecionar.pylinhas 47 a 49
    parte = df[["nome", "idade"]]
    parte.loc[0, "nome"] = "ALTERADO"
    print(df.at[0, "nome"])
    
    Saída
    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.