Todo mundo que trabalha usando o pandas às vezes se depara com uma linha de código com uma centena de caracteres, que na prática só faz uma série de filtros aninhados com condições de “e” e “ou” quase que infinitas.
df[
(df['Classificação'] != "Normal")
&
(df['Altura'] < 1.70)
&
(df['Peso'] > 60)
]
O Grande problema disso é que é muito fácil se perder nesses filtros com indexação booleana e é bem trabalhoso para dar manutenção em caso de bugs ou se houver a necessidade de complementar os filtros.
Para criar colunas em função de outras, geralmente usamos uma série de caracteres repetidos e isso nos soa um alerta de que talvez haja ou deveria haver uma forma mais simples de fazer isso.
df2['IMC'] = df2['Peso'] / df2['Altura'] ** 2
Então eu vou demonstrar a melhor forma que eu encontrei para fazer essas operações ficarem mais legíveis:
import pandas as pd
# Criando dois dataframes para os exemplos:
df = pd.DataFrame({"Altura":[1.75, 1.64, 1.50, 1.45, 1.90],
"Peso": [90,85,70,60,75]})
df2 = pd.DataFrame({"Altura":[1.75, 1.64, 1.50, 1.45, 1.90],
"Peso": [90,85,70,60,75]})
# Fazendo um cálculo com base nos valores de duas colunas:
df2['IMC'] = df2['Peso'] / df2['Altura'] ** 2
Altura | Peso | IMC | |
---|---|---|---|
0 | 1.75 | 90 | 29.3878 |
1 | 1.64 | 85 | 31.6032 |
2 | 1.5 | 70 | 31.1111 |
3 | 1.45 | 60 | 28.5375 |
4 | 1.9 | 75 | 20.7756 |
O Jeito mais legível é com o método eval. Basta montar a expressão como uma string simples:
df.eval("IMC = Peso / Altura ** 2", inplace=True)
```
{% endraw %}
| | Altura | Peso | IMC |
|---:|---------:|-------:|--------:|
| 0 | 1.75 | 90 | 29.3878 |
| 1 | 1.64 | 85 | 31.6032 |
| 2 | 1.5 | 70 | 31.1111 |
| 3 | 1.45 | 60 | 28.5375 |
| 4 | 1.9 | 75 | 20.7756 |
Também podemos criar colunas usando funções, selecionando a coluna e com o metodo apply passar o nome da função como parâmetro. Geralmente é a minha última alternativa e só compensa em casos envolvendo muitos "ifs".
{% raw %}
```python
def classificacao_imc(imc):
if imc < 18.5:
return "Magro"
elif imc >= 18.5 and imc <= 24.9:
return "Normal"
elif imc > 24.9 and imc < 29.9:
return "Sobrepeso"
elif imc >= 30.0 and imc < 39.9:
return "Obesidade"
elif imc >= 40:
return "Obesidade Grave"
# e então:
df["Classificação"] = df['IMC'].apply(classificacao_imc)
print(df)
```
{% endraw %}
| | Altura | Peso | IMC | Classificação |
|---:|---------:|-------:|--------:|:----------------|
| 0 | 1.75 | 90 | 29.3878 | Sobrepeso |
| 1 | 1.64 | 85 | 31.6032 | Obesidade |
| 2 | 1.5 | 70 | 31.1111 | Obesidade |
| 3 | 1.45 | 60 | 28.5375 | Sobrepeso |
| 4 | 1.9 | 75 | 20.7756 | Normal |
{% raw %}
````python
df2["Classificação"] = df2['IMC'].apply(classificacao_imc)
df.eval("Peso_ideal = 24.9 * Altura ** 2", inplace=True)
df2.eval("Peso_ideal = 24.9 * Altura ** 2", inplace=True)
print(df)
```
{% endraw %}
| | Altura | Peso | IMC | Classificação | Peso_ideal |
|---:|---------:|-------:|--------:|:----------------|-------------:|
| 0 | 1.75 | 90 | 29.3878 | Sobrepeso | 76.2562 |
| 1 | 1.64 | 85 | 31.6032 | Obesidade | 66.971 |
| 2 | 1.5 | 70 | 31.1111 | Obesidade | 56.025 |
| 3 | 1.45 | 60 | 28.5375 | Sobrepeso | 52.3522 |
| 4 | 1.9 | 75 | 20.7756 | Normal | 89.889 |
Filtro do jeito clássico (indexação booleana):
{% raw %}
````python
df[df['Classificação'] != 'Normal']
```
{% endraw %}
| | Altura | Peso | IMC | Classificação | Peso_ideal |
|---:|---------:|-------:|--------:|:----------------|-------------:|
| 0 | 1.75 | 90 | 29.3878 | Sobrepeso | 76.2562 |
| 1 | 1.64 | 85 | 31.6032 | Obesidade | 66.971 |
| 2 | 1.5 | 70 | 31.1111 | Obesidade | 56.025 |
| 3 | 1.45 | 60 | 28.5375 | Sobrepeso | 52.3522 |
#### Filtro do jeito mais legível, com o método query.
Você só precisa passar uma string com os nomes de colunas e comparar com strings (coloque ' ao redor), números ou variáveis. Para comparar com variáveis, basta usar @nome_da_variável.
{% raw %}
```python
df2.query("Classificação != 'Normal'")
```
| | Altura | Peso | IMC | Classificação | Peso_ideal |
|---:|---------:|-------:|--------:|:----------------|-------------:|
| 0 | 1.75 | 90 | 29.3878 | Sobrepeso | 76.2562 |
| 1 | 1.64 | 85 | 31.6032 | Obesidade | 66.971 |
| 2 | 1.5 | 70 | 31.1111 | Obesidade | 56.025 |
| 3 | 1.45 | 60 | 28.5375 | Sobrepeso | 52.3522 |
```python
variavel = 'Obesidade'
df2.query("Classificação == @variavel")
```
| | Altura | Peso | IMC | Classificação | Peso_ideal |
|---:|---------:|-------:|--------:|:----------------|-------------:|
| 1 | 1.64 | 85 | 31.6032 | Obesidade | 66.971 |
| 2 | 1.5 | 70 | 31.1111 | Obesidade | 56.025 |
Filtro aninhado e com indexação booleana:
```python
df[
(df['Classificação'] != "Normal")
&
(df['Altura'] < 1.70)
&
(df['Peso'] > 60)
]
```
| | Altura | Peso | IMC | Classificação | Peso_ideal |
|---:|---------:|-------:|--------:|:----------------|-------------:|
| 1 | 1.64 | 85 | 31.6032 | Obesidade | 66.971 |
| 2 | 1.5 | 70 | 31.1111 | Obesidade | 56.025 |
Com o método query:
```python
df.query("Classificação != 'Normal'and Altura < 1.70 and Peso > 60")
```
| | Altura | Peso | IMC | Classificação | Peso_ideal |
|---:|---------:|-------:|--------:|:----------------|-------------:|
| 1 | 1.64 | 85 | 31.6032 | Obesidade | 66.971 |
| 2 | 1.5 | 70 | 31.1111 | Obesidade | 56.025 |
Você também pode fazer:
```python
query_string = (
"Classificação != 'Normal'"
"and Altura < 1.70"
"and Peso > 60"
)
df.query(query_string)
```
| | Altura | Peso | IMC | Classificação | Peso_ideal |
|---:|---------:|-------:|--------:|:----------------|-------------:|
| 1 | 1.64 | 85 | 31.6032 | Obesidade | 66.971 |
| 2 | 1.5 | 70 | 31.1111 | Obesidade | 56.025 |
Por fim:
```python
query_string = (
"Classificação != 'Normal'"
"and Altura < 1.70"
"and Peso > 60"
)
df.query(query_string)
```
É mais legível e organizado do que:
```python
df[
(df['Classificação'] != "Normal")
&
(df['Altura'] < 1.70)
&
(df['Peso'] > 60)
]
```
Não?
Top comments (0)