# Selecionar e filtrar dados

Distinguir loc de iloc, combinar máscaras e selecionar linhas e colunas sem ambiguidade.

Página: https://resumos.rgo.pt/cadeiras/ct-iadp/selecao-filtros/

Selecionar escolhe linhas ou colunas; filtrar escolhe as linhas que cumprem uma condição. Primeiro identifica se o enunciado fala de rótulos, posições ou valores. Esta decisão determina a operação.

## Rótulos com loc, posições com iloc

Imagina uma tabela com índices 10, 20 e 30. `df.loc[20]` procura o rótulo 20. `df.iloc[1]` procura a segunda posição. Os dois podem coincidir nesta tabela, mas representam pedidos diferentes.

| Pedido | Expressão |
| --- | --- |
| Linha com rótulo 20 | `df.loc[20]` |
| Segunda linha | `df.iloc[1]` |
| Duas primeiras linhas | `df.iloc[:2]` |
| Rótulos de 10 até 20, incluídos | `df.loc[10:20]` |
| Coluna quantidade | `df["quantidade"]` |
| Colunas produto e quantidade | `df[["produto", "quantidade"]]` |

O slice de `iloc` exclui o limite final. O slice de rótulos de `loc` inclui normalmente ambos os extremos existentes. Para slices de rótulos ordenados de forma irregular ou repetidos, confere se a seleção é bem definida.

## Construir uma máscara

```python
import pandas as pd
vendas = pd.DataFrame({
    "cidade": ["Porto", "Porto", "Braga", "Braga"],
    "produto": ["pão", "leite", "pão", "arroz"],
    "quantidade": [2, 3, 5, 4],
}, index=[10, 20, 30, 40])
mascara = (vendas["cidade"] == "Braga") & (vendas["quantidade"] >= 5)
print(mascara.to_list())
print(vendas.loc[mascara, ["produto", "quantidade"]].to_string())
print(vendas.iloc[:2, 1].to_list())
```

A máscara é `[False, False, True, False]`. Só a linha 30 cumpre ambas as condições, pelo que o resultado contém pão com quantidade 5. A última seleção usa as duas primeiras posições e a coluna de posição 1, dando pão e leite.

Uma máscara deve ter a forma e, quando é uma Series, os rótulos adequados à tabela. Uma máscara construída noutra tabela pode alinhar por rótulos ou dar erro. Constrói-a a partir da tabela que estás a selecionar.

## Combinar condições

Em Series, usa `&` para e, `|` para ou e `~` para negar. Coloca cada comparação entre parênteses. `and` e `or` tentam obter um único valor lógico da Series e dão erro por ambiguidade.

```
mascara = (df["quantidade"] >= 2) & (df["quantidade"] <= 5)
mascara = df["quantidade"].between(2, 5)
```

As duas expressões incluem os extremos 2 e 5. `df["cidade"].isin(["Porto", "Braga"])` testa pertença a um conjunto de valores. `~df["cidade"].isin(...)` seleciona as restantes cidades, tendo em conta o tratamento dos valores em falta.

## Selecionar sem mudar os dados

`df.loc[mascara, colunas]` devolve uma seleção. Para alterares a tabela original, atribui numa operação:

```
df.loc[df["quantidade"] < 0, "quantidade"] = 0
```

A alteração faz sentido apenas se zero for a correção definida no problema. Evita `df[mascara]["quantidade"] = 0`: são duas seleções e a atribuição pode atingir um objeto intermédio. Em versões com Copy-on-Write, esta atribuição encadeada não atualiza o original.

Quando queres uma tabela independente, usa `filtradas = df.loc[mascara].copy()`. Assim, o destino da alteração fica explícito.

## Selecionar um valor

`df.at[rotulo, coluna]` procura uma célula por rótulos. `df.iat[linha, coluna]` procura-a por posições. São úteis quando esperas um escalar. Não substituem uma máscara para selecionar várias linhas.

## Exercícios

Separar posição de rótulo

O índice tem 10, 20 e 30 e a coluna x tem 2, 4 e 6. Quanto vale df.iloc\[1\]\[“x”\]?

Primeira pista

iloc usa posições começadas em zero.

Mais uma pista

A posição 1 é a segunda linha, com rótulo 20.

Ver solução

O valor é 4. df.loc\[1\] procuraria o rótulo 1 e falharia nesta tabela.

#### Erros frequentes

Usar o rótulo como se fosse uma posição.

[Voltar à explicação](https://resumos.rgo.pt/cadeiras/ct-iadp/selecao-filtros/#r%C3%B3tulos-com-loc-posi%C3%A7%C3%B5es-com-iloc)

Escolher a combinação válida

Qual é a máscara para quantidades positivas na cidade Porto?

Primeira pista

O pedido exige as duas condições ao mesmo tempo.

Mais uma pista

Em pandas, e elemento a elemento escreve-se &.

Ver solução

A máscara correta usa & com cada comparação entre parênteses. Depois podes selecionar df.loc\[mascara\].

*   **(df\["quantidade"\] > 0) & (df\["cidade"\] == "Porto").** Combina comparações de Series com & e parênteses.
*   **df\["quantidade"\] > 0 and df\["cidade"\] == "Porto".** and tenta obter um único valor lógico das Series.
*   **(df\["quantidade"\] > 0) | (df\["cidade"\] == "Porto").** Seleciona quantidades positivas noutras cidades e Porto mesmo sem quantidade positiva.

#### Erros frequentes

Usar and ou trocar e por ou.

[Voltar à explicação](https://resumos.rgo.pt/cadeiras/ct-iadp/selecao-filtros/#combinar-condi%C3%A7%C3%B5es)
