Filtrar Linhas no Pandas: Selecionar Dados por Condição em Python
Updated on
Filtrar linhas em DataFrames pandas é uma das operações mais comuns em análise de dados. Seja limpando dados, explorando padrões ou preparando conjuntos de dados para aprendizado de máquina, você precisa selecionar linhas específicas com base em condições. O desafio é escolher o método certo entre as múltiplas abordagens de filtragem do pandas — cada uma com sintaxe, características de desempenho e casos de uso diferentes.
Muitos cientistas de dados lutam com a eficiência da filtragem, especialmente ao trabalhar com grandes conjuntos de dados ou condições complexas. Usar o método errado pode desacelerar sua análise em ordens de magnitude. Entender quando usar indexação booleana versus .query() ou .loc[] pode significar a diferença entre um script que executa em segundos versus um que leva minutos.
Este guia cobre todos os métodos de filtragem pandas com exemplos práticos, comparações de desempenho e melhores práticas. Você aprenderá indexação booleana, o método .query(), seleção .loc[], a função .where() e o método .filter(). No final, você saberá exatamente qual abordagem usar para qualquer cenário de filtragem.
Entendendo os Métodos de Filtragem de Linhas do Pandas
O Pandas fornece cinco métodos principais para filtrar linhas de DataFrame, cada um adequado para diferentes cenários:
| Método | Melhor Para | Exemplo de Sintaxe | Desempenho |
|---|---|---|---|
| Indexação Booleana | Condições simples, legibilidade | df[df['age'] > 25] | Rápido para dados pequenos-médios |
.query() | Condições complexas, baseado em string | df.query('age > 25 and city == "NYC"') | Mais rápido para dados grandes |
.loc[] | Baseado em rótulos com condições | df.loc[df['age'] > 25, ['name', 'age']] | Seleção flexível de colunas |
.where() | Manter estrutura, substituir valores | df.where(df['age'] > 25, np.nan) | Preserva forma do DataFrame |
.filter() | Filtrar por nomes de coluna/índice | df.filter(like='total', axis=1) | Padrões de nomes coluna/índice |
Vamos explorar cada método com exemplos detalhados.
Indexação Booleana: A Abordagem Mais Comum
A indexação booleana filtra linhas criando uma máscara booleana (valores True/False) e aplicando-a ao DataFrame. Este é o método mais intuitivo para iniciantes.
import pandas as pd
import numpy as np
# Criar DataFrame de exemplo
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'age': [25, 30, 35, 28, 32],
'city': ['NYC', 'LA', 'NYC', 'Chicago', 'LA'],
'salary': [70000, 80000, 90000, 75000, 85000]
})
# Filtrar linhas onde age é maior que 30
filtered = df[df['age'] > 30]
print(filtered)
# name age city salary
# 2 Charlie 35 NYC 90000
# 4 Eve 32 LA 85000
# Ver a máscara booleana
print(df['age'] > 30)
# 0 False
# 1 False
# 2 True
# 3 False
# 4 TrueA indexação booleana funciona avaliando a condição df['age'] > 30, que retorna uma Series de valores True/False. Quando você passa essa máscara para o DataFrame com df[mask], o pandas retorna apenas linhas onde a máscara é True.
Filtrando com Múltiplas Condições
Combine múltiplas condições usando operadores lógicos. Importante: Use & (e), | (ou), ~ (não) em vez das palavras-chave and, or, not do Python. Sempre envolva cada condição entre parênteses.
# Múltiplas condições com AND
filtered = df[(df['age'] > 25) & (df['city'] == 'NYC')]
print(filtered)
# name age city salary
# 2 Charlie 35 NYC 90000
# Múltiplas condições com OR
filtered = df[(df['age'] > 30) | (df['salary'] > 80000)]
print(filtered)
# name age city salary
# 2 Charlie 35 NYC 90000
# 4 Eve 32 LA 85000
# Operador NOT
filtered = df[~(df['city'] == 'NYC')]
print(filtered)
# name age city salary
# 1 Bob 30 LA 80000
# 3 David 28 Chicago 75000
# 4 Eve 32 LA 85000Usando .isin() para Múltiplos Valores
Filtre linhas onde uma coluna corresponde a qualquer valor em uma lista usando .isin():
# Filtrar linhas onde city é NYC ou LA
cities = ['NYC', 'LA']
filtered = df[df['city'].isin(cities)]
print(filtered)
# name age city salary
# 0 Alice 25 NYC 70000
# 1 Bob 30 LA 80000
# 2 Charlie 35 NYC 90000
# 4 Eve 32 LA 85000
# Inverso: cidades NÃO na lista
filtered = df[~df['city'].isin(cities)]
print(filtered)
# name age city salary
# 3 David 28 Chicago 75000Filtrando com .between()
O método .between() filtra valores dentro de um intervalo (inclusivo por padrão):
# Filtrar idades entre 28 e 32
filtered = df[df['age'].between(28, 32)]
print(filtered)
# name age city salary
# 1 Bob 30 LA 80000
# 3 David 28 Chicago 75000
# 4 Eve 32 LA 85000
# Limites exclusivos
filtered = df[df['age'].between(28, 32, inclusive='neither')]
print(filtered)
# name age city salary
# 1 Bob 30 LA 80000O Método .query(): Filtragem Baseada em String
O método .query() aceita uma expressão de string, tornando-o legível para condições complexas. É particularmente eficiente para DataFrames grandes porque usa numexpr para otimização.
# Consulta simples
filtered = df.query('age > 30')
print(filtered)
# name age city salary
# 2 Charlie 35 NYC 90000
# 4 Eve 32 LA 85000
# Múltiplas condições
filtered = df.query('age > 25 and city == "NYC"')
print(filtered)
# name age city salary
# 2 Charlie 35 NYC 90000
# Usando variáveis com símbolo @
min_age = 30
filtered = df.query('age > @min_age')
print(filtered)
# name age city salary
# 2 Charlie 35 NYC 90000
# 4 Eve 32 LA 85000Expressões .query() Avançadas
# Usando .isin() em query
cities = ['NYC', 'LA']
filtered = df.query('city in @cities')
print(filtered)
# Condições de intervalo
filtered = df.query('28 <= age <= 32')
print(filtered)
# Métodos de string
filtered = df.query('city.str.contains("LA")', engine='python')
print(filtered).loc[] para Filtragem Baseada em Rótulos
O indexador .loc[] combina filtragem de linhas com seleção de colunas. Use-o quando precisar de colunas específicas de linhas filtradas.
# Filtrar linhas e selecionar colunas
filtered = df.loc[df['age'] > 30, ['name', 'age']]
print(filtered)
# name age
# 2 Charlie 35
# 4 Eve 32
# Múltiplas condições
filtered = df.loc[(df['age'] > 25) & (df['salary'] > 75000), ['name', 'salary']]
print(filtered)
# name salary
# 1 Bob 80000
# 2 Charlie 90000
# 4 Eve 85000
# Todas as colunas
filtered = df.loc[df['city'] == 'NYC', :]
print(filtered)Método .where(): Substituição Condicional de Valores
Ao contrário de outros métodos, .where() preserva a forma do DataFrame substituindo valores que não atendem à condição por NaN (ou um valor especificado).
# Manter valores onde age > 30, substituir outros por NaN
result = df.where(df['age'] > 30)
print(result)
# name age city salary
# 0 NaN NaN NaN NaN
# 1 NaN NaN NaN NaN
# 2 Charlie 35.0 NYC 90000.0
# 3 NaN NaN NaN NaN
# 4 Eve 32.0 LA 85000.0
# Substituir por valor personalizado
result = df.where(df['age'] > 30, 'FILTERED')
print(result)
# Remover linhas com NaN após .where()
result = df.where(df['age'] > 30).dropna()
print(result)Método .filter(): Filtrar por Nomes de Coluna/Índice
O método .filter() filtra colunas ou linhas por seus rótulos (nomes), não por valores. Use-o para seleção de colunas baseada em padrões.
# Criar DataFrame com múltiplas colunas
df_wide = pd.DataFrame({
'total_sales': [100, 200, 300],
'total_profit': [20, 40, 60],
'monthly_sales': [10, 20, 30],
'yearly_sales': [120, 240, 360],
'region': ['East', 'West', 'North']
})
# Filtrar colunas contendo 'total'
filtered = df_wide.filter(like='total')
print(filtered)
# total_sales total_profit
# 0 100 20
# 1 200 40
# 2 300 60
# Filtrar colunas usando regex
filtered = df_wide.filter(regex=r'.*sales$')
print(filtered)
# total_sales monthly_sales yearly_sales
# 0 100 10 120
# 1 200 20 240
# 2 300 30 360
# Filtrar colunas por nomes exatos
filtered = df_wide.filter(items=['total_sales', 'region'])
print(filtered)Filtrando Dados de String
O Pandas fornece métodos de string através do acessor .str para filtrar colunas de texto.
# Criar DataFrame com dados de texto
df_text = pd.DataFrame({
'name': ['Alice Smith', 'Bob Johnson', 'Charlie Brown', 'David Lee'],
'email': ['alice@gmail.com', 'bob@yahoo.com', 'charlie@gmail.com', 'david@outlook.com']
})
# Filtrar linhas onde name contém 'Smith'
filtered = df_text[df_text['name'].str.contains('Smith')]
print(filtered)
# name email
# 0 Alice Smith alice@gmail.com
# Busca sem distinção de maiúsculas
filtered = df_text[df_text['name'].str.contains('smith', case=False)]
print(filtered)
# Filtrar por domínio de email
filtered = df_text[df_text['email'].str.endswith('gmail.com')]
print(filtered)
# name email
# 0 Alice Smith alice@gmail.com
# 2 Charlie Brown charlie@gmail.com
# Filtrar com regex
filtered = df_text[df_text['name'].str.match(r'^[A-C]')]
print(filtered)Filtrando Valores Nulos e Não Nulos
Use .isna(), .notna(), .isnull() e .notnull() para filtrar com base em dados ausentes.
# Criar DataFrame com valores ausentes
df_missing = pd.DataFrame({
'A': [1, 2, np.nan, 4],
'B': [5, np.nan, 7, 8],
'C': [9, 10, 11, 12]
})
# Filtrar linhas onde coluna A não é null
filtered = df_missing[df_missing['A'].notna()]
print(filtered)
# A B C
# 0 1.0 5.0 9
# 1 2.0 NaN 10
# 3 4.0 8.0 12
# Filtrar linhas onde QUALQUER coluna é null
filtered = df_missing[df_missing.isna().any(axis=1)]
print(filtered)
# A B C
# 1 2.0 NaN 10
# 2 NaN 7.0 11
# Filtrar linhas onde TODAS as colunas não são null
filtered = df_missing[df_missing.notna().all(axis=1)]
print(filtered)
# A B C
# 0 1.0 5.0 9
# 3 4.0 8.0 12Filtrando por Intervalos de Data
Ao trabalhar com colunas datetime, você pode filtrar por intervalos de data usando operadores de comparação padrão.
# Criar DataFrame com datas
df_dates = pd.DataFrame({
'date': pd.date_range('2026-01-01', periods=10, freq='D'),
'value': range(10)
})
# Filtrar datas após uma data específica
filtered = df_dates[df_dates['date'] > '2026-01-05']
print(filtered)
# Filtrar intervalo de datas
start_date = '2026-01-03'
end_date = '2026-01-07'
filtered = df_dates[(df_dates['date'] >= start_date) & (df_dates['date'] <= end_date)]
print(filtered)
# Usando .between() para datas
filtered = df_dates[df_dates['date'].between('2026-01-03', '2026-01-07')]
print(filtered)Comparação de Desempenho: DataFrames Grandes
Diferentes métodos de filtragem têm diferentes características de desempenho. Aqui está uma comparação para um DataFrame com 1 milhão de linhas:
import time
# Criar DataFrame grande
np.random.seed(42)
df_large = pd.DataFrame({
'A': np.random.randint(0, 100, 1000000),
'B': np.random.randint(0, 100, 1000000),
'C': np.random.choice(['X', 'Y', 'Z'], 1000000)
})
# Indexação booleana
start = time.time()
result = df_large[(df_large['A'] > 50) & (df_large['B'] < 30)]
print(f"Indexação booleana: {time.time() - start:.4f} segundos")
# Método .query()
start = time.time()
result = df_large.query('A > 50 and B < 30')
print(f"Método .query(): {time.time() - start:.4f} segundos")
# Método .loc[]
start = time.time()
result = df_large.loc[(df_large['A'] > 50) & (df_large['B'] < 30)]
print(f"Método .loc[]: {time.time() - start:.4f} segundos")Insights de desempenho:
- Indexação booleana: Rápida para condições simples, mais lenta para filtros complexos com múltiplas condições
- .query(): Mais rápida para DataFrames grandes com múltiplas condições (usa otimização numexpr)
- .loc[]: Similar à indexação booleana, mas mais flexível para seleção de colunas
- .where(): Mais lenta devido à travessia completa do DataFrame, use apenas quando precisar preservar a forma
Para conjuntos de dados acima de 100.000 linhas com múltiplas condições, .query() tipicamente supera a indexação booleana em 20-40%.
Erros Comuns e Como Evitá-los
Erro 1: Usando 'and' em Vez de '&'
# ERRADO - lança ValueError
# filtered = df[df['age'] > 25 and df['city'] == 'NYC']
# CORRETO
filtered = df[(df['age'] > 25) & (df['city'] == 'NYC')]Erro 2: Esquecendo Parênteses
# ERRADO - problemas de precedência de operador
# filtered = df[df['age'] > 25 & df['city'] == 'NYC']
# CORRETO - envolver cada condição
filtered = df[(df['age'] > 25) & (df['city'] == 'NYC')]Erro 3: Modificando DataFrame Original
# Filtragem cria uma visão, não uma cópia
filtered = df[df['age'] > 30]
# ERRADO - SettingWithCopyWarning
# filtered['new_col'] = 100
# CORRETO - criar cópia explícita
filtered = df[df['age'] > 30].copy()
filtered['new_col'] = 100Erro 4: Filtragem de String Sem Tratar NaN
df_with_nan = pd.DataFrame({
'name': ['Alice', np.nan, 'Charlie']
})
# ERRADO - lança erro se NaN presente
# filtered = df_with_nan[df_with_nan['name'].str.contains('li')]
# CORRETO - tratar NaN com parâmetro na
filtered = df_with_nan[df_with_nan['name'].str.contains('li', na=False)]Visualizar Dados Filtrados com PyGWalker
Após filtrar seu DataFrame pandas, visualizar os resultados ajuda a descobrir padrões e insights. PyGWalker (opens in a new tab) transforma DataFrames filtrados em uma interface interativa semelhante ao Tableau diretamente em notebooks Python — sem necessidade de exportar dados ou escrever código de plotagem complexo.
O PyGWalker é particularmente útil ao explorar conjuntos de dados filtrados porque permite:
- Arrastar e soltar colunas para criar gráficos instantaneamente
- Aplicar filtros adicionais visualmente sem escrever código
- Alternar entre tipos de gráficos (barra, linha, dispersão, mapa de calor) em segundos
- Exportar visualizações para relatórios ou apresentações
import pygwalker as pyg
# Filtrar DataFrame
filtered_df = df[(df['age'] > 25) & (df['salary'] > 75000)]
# Lançar visualização interativa
pyg.walk(filtered_df)Isso abre uma interface interativa onde você pode criar visualizações arrastando colunas filtradas para o construtor de gráficos. Para analistas de dados trabalhando com múltiplas condições de filtro, o PyGWalker elimina o ciclo de iteração de filtrar → plotar → ajustar → replotar.
Perguntas Frequentes
Como filtro linhas de DataFrame pandas por condição?
Use indexação booleana com df[df['column'] > value] para condições simples. Para múltiplas condições, use & (e), | (ou), ~ (não) com parênteses: df[(df['A'] > 10) & (df['B'] < 20)]. Alternativamente, use .query() para sintaxe legível: df.query('A > 10 and B < 20').
Qual é a diferença entre .loc[] e indexação booleana?
A indexação booleana (df[df['col'] > 5]) retorna todas as colunas para linhas filtradas. .loc[] permite seleção de colunas simultaneamente: df.loc[df['col'] > 5, ['col1', 'col2']]. Ambos os métodos têm desempenho similar, mas .loc[] é mais explícito e suporta seleção de linhas baseada em rótulos.
Como filtrar DataFrame pandas com múltiplas condições?
Combine condições usando operadores & (e), | (ou), ~ (não). Sempre envolva cada condição entre parênteses: df[(df['age'] > 25) & (df['city'] == 'NYC') | (df['salary'] > 80000)]. Para condições complexas, use .query(): df.query('age > 25 and (city == "NYC" or salary > 80000)').
Quando devo usar .query() em vez de indexação booleana?
Use .query() para DataFrames grandes (>100k linhas) com múltiplas condições — é 20-40% mais rápido devido à otimização numexpr. Também é mais legível para condições complexas. Use indexação booleana para filtros simples ou quando precisar de máxima compatibilidade (.query() requer expressões de string que são mais difíceis de depurar).
Como filtro linhas onde o valor da coluna está em uma lista?
Use o método .isin(): df[df['city'].isin(['NYC', 'LA', 'Chicago'])]. Para o inverso (não na lista), use o operador ~: df[~df['city'].isin(['NYC', 'LA'])]. Isso é mais eficiente do que encadear múltiplas condições | para listas grandes.
Conclusão
Filtrar linhas de DataFrame pandas é uma habilidade fundamental para análise de dados em Python. Agora você entende cinco métodos de filtragem: indexação booleana para simplicidade, .query() para desempenho, .loc[] para seleção flexível de colunas, .where() para substituição de valores e .filter() para padrões de nomes de colunas.
Principais conclusões:
- Use indexação booleana para filtros rápidos e legíveis em conjuntos de dados pequenos a médios
- Escolha .query() para grandes conjuntos de dados com condições complexas (20-40% mais rápido)
- Aplique .loc[] quando precisar tanto de filtragem de linhas quanto de seleção de colunas
- Lembre-se de usar operadores
&,|,~em vez deand,or,not - Sempre envolva condições entre parênteses para evitar problemas de precedência de operador
Domine essas técnicas de filtragem e você lidará com qualquer cenário de seleção de dados com eficiência. Para exploração interativa de dados filtrados, considere usar PyGWalker para visualizar seus resultados sem escrever código de plotagem adicional.