Benefícios de desempenho de índices ordenados
Ordene um MultiIndex com sort_index(), meça o desempenho de fatias com timeit e use is_monotonic_increasing como verificação de segurança.
Benefícios de desempenho de índices ordenados é uma aula grátis de Pandas & NumPy Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Pandas & NumPy Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Pandas & NumPy Academy inclui 4 aulas no total.
Por que a ordenação do índice é importante para o desempenho
Um índice ordenado permite que o Pandas use a busca binária (O(log n)) em vez de uma varredura linear completa (O(n)) ao procurar intervalos de rótulos. Para um DataFrame com um milhão de linhas, a busca binária encontra o intervalo de destino com cerca de 20 comparações, contra até um milhão de comparações em uma varredura linear. Isso torna as operações de fatiamento em MultiIndexes ordenados muitas ordens de grandeza mais rápidas do que em índices não ordenados — e a diferença se torna crítica em pipelines de produção que processam milhões de linhas.
import pandas as pd
import numpy as np
np.random.seed(42)
# Create a large DataFrame with a MultiIndex
countries = ['DE', 'UK', 'USA', 'FR', 'JP']
dates = pd.date_range('2020-01-01', periods=200)
mi = pd.MultiIndex.from_product([countries, dates], names=['country', 'date'])
df = pd.DataFrame({'value': np.random.randn(len(mi))}, index=mi)
print(f'DataFrame shape: {df.shape}')
print(f'Index is sorted: {df.index.is_monotonic_increasing}')Verificando se um índice está ordenado
Use df.index.is_monotonic_increasing para verificar se o índice está ordenado em ordem crescente. Isso retorna um booleano. Para um MultiIndex, o Pandas verifica a ordenação lexicograficamente em todos os níveis. Verifique sempre essa condição antes de realizar operações de fatiamento com .loc[start:end] em um MultiIndex — um índice não ordenado poderá gerar um UnsortedIndexError ou retornar silenciosamente resultados incorretos, dependendo da versão do Pandas.
import pandas as pd
# Sorted MultiIndex
tuples_sorted = [('A', 1), ('A', 2), ('B', 1), ('B', 2)]
mi_sorted = pd.MultiIndex.from_tuples(tuples_sorted)
df_sorted = pd.DataFrame({'v': [10, 20, 30, 40]}, index=mi_sorted)
# Unsorted MultiIndex
tuples_unsorted = [('B', 2), ('A', 1), ('B', 1), ('A', 2)]
mi_unsorted = pd.MultiIndex.from_tuples(tuples_unsorted)
df_unsorted = pd.DataFrame({'v': [10, 20, 30, 40]}, index=mi_unsorted)
print('Sorted index is_monotonic_increasing:', df_sorted.index.is_monotonic_increasing)
print('Unsorted index is_monotonic_increasing:', df_unsorted.index.is_monotonic_increasing)Ordenando com sort_index()
df.sort_index() retorna um novo DataFrame com as linhas ordenadas pelo rótulo do índice em ordem crescente. Use ascending=False para obter ordem decrescente. Em um MultiIndex, a ordenação é lexicográfica: primeiro ordena pelo nível mais externo e, depois, pelos níveis internos dentro de cada grupo externo. Ordene sempre após qualquer operação que possa desorganizar o índice — como pd.concat, filtragem ou acréscimo de novas linhas.
import pandas as pd
import numpy as np
np.random.seed(0)
countries = ['USA', 'UK', 'DE']
years = [2021, 2022, 2023]
mi = pd.MultiIndex.from_product([countries, years], names=['country', 'year'])
df = pd.DataFrame({'gdp': np.random.randint(3000, 26000, 9)}, index=mi)
print('Before sort_index():')
print(df.head(4))
df_sorted = df.sort_index()
print('\nAfter sort_index():')
print(df_sorted.head(4))
print('Is sorted:', df_sorted.index.is_monotonic_increasing)Medindo o tempo de consulta com timeit
O módulo timeit do Python mede quanto tempo uma instrução leva para ser executada, executando-a várias vezes e calculando a média. Use-o para comparar consultas em índices ordenados e não ordenados. No IPython/Jupyter, a mágica %timeit oferece a mesma funcionalidade com uma saída mais clara. A avaliação comparativa é a única maneira confiável de confirmar que uma otimização de desempenho realmente ajudou — nunca presuma que uma alteração é mais rápida sem medi-la.
import pandas as pd
import numpy as np
import timeit
np.random.seed(0)
N = 500000
idx = np.random.choice(['A','B','C','D','E'], N)
df_unsorted = pd.DataFrame({'v': np.random.randn(N)}, index=idx)
df_sorted = df_unsorted.sort_index()
# Time label lookup: sorted vs unsorted
t_unsorted = timeit.timeit(lambda: df_unsorted.loc['C'], number=100)
t_sorted = timeit.timeit(lambda: df_sorted.loc['C'], number=100)
print(f'Unsorted lookup (100 runs): {t_unsorted:.3f}s')
print(f'Sorted lookup (100 runs): {t_sorted:.3f}s')
print(f'Speedup: {t_unsorted/t_sorted:.1f}x')PerformanceWarning de MultiIndex não ordenado
O Pandas emite um PerformanceWarning quando você fatia um MultiIndex que não está ordenado lexicograficamente: 'indexing past lexsort depth may impact performance'. Esse aviso significa que o Pandas precisou recorrer a uma varredura linear em vez de uma busca binária. Embora ainda retorne resultados corretos em casos simples, ele pode retornar resultados incorretos ao fatiar níveis internos de um índice multinível não ordenado. Trate esse aviso como um erro e corrija a causa raiz ordenando o índice.
import pandas as pd
import warnings
# Create an unsorted MultiIndex and trigger the warning
tuples = [('B', 2), ('A', 1), ('B', 1), ('A', 2)]
mi = pd.MultiIndex.from_tuples(tuples, names=['letter', 'num'])
df = pd.DataFrame({'v': [10, 20, 30, 40]}, index=mi)
print('Index sorted?', df.index.is_monotonic_increasing)
# This may trigger PerformanceWarning in some Pandas versions
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
try:
result = df.loc['A':'B', :]
print('Result:', result)
if w:
print('Warning:', str(w[0].message))
except Exception as e:
print('Error (common with newer Pandas):', type(e).__name__)Avaliação comparativa do fatiamento de MultiIndex ordenado e não ordenado
O fatiamento de um MultiIndex ordenado é muito mais rápido porque o Pandas pode realizar uma busca binária tanto nos vetores do nível externo quanto nos do nível interno. Vamos avaliar o fatiamento de um MultiIndex grande com 1 milhão de linhas — um tamanho comum em pipelines de análise de produção. A versão ordenada evita a varredura linear e apresenta consistentemente ganhos de velocidade de 5 a 50 vezes, dependendo da seletividade do fatiamento.
import pandas as pd
import numpy as np
import timeit
np.random.seed(42)
countries = ['DE', 'UK', 'USA', 'FR', 'JP']
dates = pd.date_range('2010-01-01', periods=200000)
# Sample a random subset for timing test
sample_countries = np.random.choice(countries, 100000)
sample_dates = np.random.choice(dates, 100000)
df = pd.DataFrame({
'country': sample_countries,
'date': sample_dates,
'value': np.random.randn(100000)
}).set_index(['country', 'date'])
df_sorted = df.sort_index()
print('Dataset size:', len(df))
print('Sorted:', df_sorted.index.is_monotonic_increasing)
t = timeit.timeit(lambda: df_sorted.loc['USA'], number=50)
print(f'Sorted lookup (50 runs): {t:.3f}s')sort_index com o parâmetro level
Em um MultiIndex, você pode ordenar por um nível específico em vez de ordenar todos os níveis usando o parâmetro level: df.sort_index(level='year'). Isso é útil quando você deseja preservar o agrupamento do nível externo, mas reordenar as linhas dentro de cada grupo externo. O argumento sort_remaining=True (padrão) também ordena quaisquer níveis não ordenados além do nível especificado, garantindo uma ordenação lexicográfica completa.
import pandas as pd
import numpy as np
countries = ['USA', 'UK']
years = [2023, 2021, 2022] # deliberately unordered
mi = pd.MultiIndex.from_product([countries, years], names=['country', 'year'])
df = pd.DataFrame({'v': range(6)}, index=mi)
print('Before sorting by year level:')
print(df)
# Sort by the inner level (year) only
df_ysorted = df.sort_index(level='year')
print('\nAfter sort_index(level="year"):')
print(df_ysorted)is_monotonic_increasing como proteção do pipeline
Em pipelines de produção, adicione uma proteção de ordenação no início de qualquer função que receba um DataFrame com um MultiIndex e realize fatiamento. Se o índice não estiver ordenado, ordene-o automaticamente e registre um aviso. Isso evita uma degradação silenciosa do desempenho ou resultados incorretos quando o código upstream altera a ordem do DataFrame. Uma proteção no limite da função é mais confiável do que presumir que os chamadores sempre fornecem dados ordenados.
import pandas as pd
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def safe_slice(df, key):
'''Slice a MultiIndex DataFrame, sorting if necessary.'''
if not df.index.is_monotonic_increasing:
logger.warning('Index not sorted — sorting now. This is a performance cost.')
df = df.sort_index()
return df.loc[key]
# Test with an unsorted DataFrame
tuples = [('B', 2), ('A', 1), ('B', 1), ('A', 2)]
mi = pd.MultiIndex.from_tuples(tuples, names=['letter', 'num'])
df = pd.DataFrame({'v': [10, 20, 30, 40]}, index=mi)
result = safe_slice(df, 'A')
print('Slice result for A:')
print(result)Índice ordenado para busca binária em índices simples
Os benefícios de desempenho da ordenação também se aplicam a índices regulares (não multiníveis). Um DatetimeIndex usado em análises de séries temporais realiza o fatiamento de intervalos de datas muito mais rapidamente quando está ordenado. Um índice de strings ordenado alfabeticamente permite a busca binária de rótulos. Para uma Series grande de preços de ações indexada por marcas de tempo, ordenar o DatetimeIndex pode transformar um fatiamento de 100 ms em uma operação de menos de um milissegundo.
import pandas as pd
import numpy as np
import timeit
np.random.seed(0)
# Random timestamps — unsorted
timestamps = pd.date_range('2020-01-01', periods=500000, freq='min')
shuffled = np.random.permutation(timestamps)
prices = pd.Series(np.random.randn(500000), index=shuffled)
prices_sorted = prices.sort_index()
# Time a date range slice
t_unsorted = timeit.timeit(lambda: prices['2020-06-01':'2020-06-30'], number=20)
t_sorted = timeit.timeit(lambda: prices_sorted['2020-06-01':'2020-06-30'], number=20)
print(f'Unsorted: {t_unsorted:.3f}s')
print(f'Sorted: {t_sorted:.3f}s')
print(f'Speedup: {t_unsorted/t_sorted:.0f}x')Custo de memória da ordenação
A ordenação não é gratuita — sort_index() cria uma nova cópia do DataFrame (a menos que você use inplace=True, que modifica o objeto no próprio lugar). Para DataFrames muito grandes, isso duplica temporariamente o uso máximo de memória. Uma estratégia prática é ordenar uma vez no carregamento e manter a versão ordenada durante todo o pipeline, em vez de ordenar repetidamente. Se a memória estiver limitada, ordene no próprio lugar com df.sort_index(inplace=True) para evitar a cópia temporária.
import pandas as pd
import numpy as np
np.random.seed(0)
countries = ['DE', 'UK', 'USA']
years = [2021, 2022, 2023]
mi = pd.MultiIndex.from_product([countries, years], names=['country', 'year'])
df = pd.DataFrame({'v': np.random.randn(9)}, index=mi)
# Sort once at load time — best practice
df.sort_index(inplace=True) # no temporary copy
assert df.index.is_monotonic_increasing, 'Index must be sorted!'
print('Pipeline-ready DataFrame (sorted in place):')
print(df)Resumo das práticas recomendadas para índices ordenados
Regras principais para o desempenho dos índices: 1) Sempre chame sort_index() após qualquer operação que possa desorganizar o índice (concatenação, mesclagem, acréscimo ou filtragem). 2) Use is_monotonic_increasing como proteção em funções que fatiam o índice. 3) Ordene no carregamento e mantenha o DataFrame ordenado durante todo o pipeline para evitar ordenações repetidas. 4) Em DataFrames com MultiIndex, garanta que todos os níveis estejam ordenados, não apenas o mais externo. 5) Use timeit para verificar se a ordenação realmente proporciona o ganho de velocidade esperado no seu pipeline específico.
Verificação rápida
Teste sua compreensão sobre o desempenho de índices ordenados nesta lição.
Recapitulação da lição
Nesta lição, você aprendeu que is_monotonic_increasing verifica se um índice está ordenado e se a busca binária está disponível; sort_index() ordena no próprio lugar ou retorna uma cópia ordenada; e timeit mede o ganho de velocidade real para confirmar o benefício. A seguir, exploraremos funções de janela — estatísticas móveis e expansivas para séries temporais e dados financeiros.
Perguntas Frequentes
A aula “Benefícios de desempenho de índices ordenados” é grátis?
Sim — o texto completo de “Benefícios de desempenho de índices ordenados” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Pandas & NumPy Academy, atualize para CoddyKit PRO. O curso de Pandas & NumPy Academy inclui 4 aulas no total.
O que vou aprender em “Benefícios de desempenho de índices ordenados”?
Ordene um MultiIndex com sort_index(), meça o desempenho de fatias com timeit e use is_monotonic_increasing como verificação de segurança. Você pratica Pandas & NumPy Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Pandas & NumPy Academy?
Nenhuma experiência prévia é necessária. Pandas & NumPy Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.
Quanto tempo leva a aula “Benefícios de desempenho de índices ordenados”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Pandas & NumPy Academy?
Sim. Cada aula de Pandas & NumPy Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Criando um MultiIndex
- Selecionando dados de um MultiIndex
- Alinhamento e reindexação de índices
- Benefícios de desempenho de índices ordenados