Pandas & NumPy Academy · leksjon

Ytelsesfordeler med sorterte indekser

Sorter en MultiIndex med sort_index(), mål ytelsen til utsnitt med timeit, og bruk is_monotonic_increasing som kontroll.

Leksjon 4 av 413 trinn

Ytelsesfordeler med sorterte indekser er en gratis leksjon i Pandas & NumPy Academy på CoddyKit. Dette er leksjon 4 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Pandas & NumPy Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Pandas & NumPy Academy inneholder totalt 4 leksjoner.

Hvorfor indekssortering er viktig for ytelsen

En sortert indeks gjør det mulig for Pandas å bruke binærsøk (O(log n)) i stedet for et fullstendig lineært søk (O(n)) ved oppslag i etikettområder. For en DataFrame med én million rader finner binærsøk målområdet med omtrent 20 sammenligninger, mot opptil én million sammenligninger med et lineært søk. Dette gjør utsnittoperasjoner på sorterte MultiIndex-er mange størrelsesordener raskere enn på usorterte indekser — og forskjellen blir avgjørende i produksjonspipelines som behandler millioner av rader.

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}')

Kontrollere om en indeks er sortert

Bruk df.index.is_monotonic_increasing for å kontrollere om indeksen er sortert i stigende rekkefølge. Dette returnerer en boolsk verdi. For en MultiIndex kontrollerer Pandas sorteringen leksikografisk på tvers av alle nivåer. Kontroller alltid dette før De utfører utsnittoperasjoner med .loc[start:end] på en MultiIndex — en usortert indeks utløser enten UnsortedIndexError eller returnerer i enkelte tilfeller feil resultater uten varsel, avhengig av Pandas-versjonen.

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)

Sortere med sort_index()

df.sort_index() returnerer en ny DataFrame med rader sortert etter indeksetikett i stigende rekkefølge. Bruk ascending=False for synkende rekkefølge. For en MultiIndex er sorteringen leksikografisk: først sorteres det ytterste nivået, deretter de indre nivåene innenfor hver ytre gruppe. Sorter alltid etter operasjoner som kan ha gjort indeksen usortert — for eksempel pd.concat, filtrering eller tilføying av nye rader.

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)

Måle oppslagstid med timeit

Pythons timeit-modul måler hvor lang tid en setning bruker på å kjøre, ved å kjøre den mange ganger og beregne et gjennomsnitt. Bruk den til å sammenligne oppslag i sorterte og usorterte indekser. I IPython/Jupyter gir magien %timeit samme funksjonalitet, med mer oversiktlig resultat. Måling er den eneste pålitelige måten å bekrefte at en ytelsesoptimalisering faktisk hjalp — anta aldri at en endring er raskere uten å måle den.

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 fra usortert MultiIndex

Pandas sender ut en PerformanceWarning når De tar et utsnitt av en MultiIndex som ikke er leksikografisk sortert: 'indexing past lexsort depth may impact performance'. Denne advarselen betyr at Pandas måtte falle tilbake til et lineært søk i stedet for binærsøk. Selv om dette fortsatt returnerer riktige resultater i enkle tilfeller, kan det returnere feil resultater ved utsnitt av indre nivåer i en usortert indeks med flere nivåer. Behandle denne advarselen som en feil, og rett den underliggende årsaken ved å sortere indeksen.

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__)

Sammenligne utsnitt av sortert og usortert MultiIndex

Utsnitt av en sortert MultiIndex er betydelig raskere fordi Pandas kan utføre binærsøk i både arrayene for det ytre og det indre nivået. La oss måle dette ved å ta et utsnitt av en stor MultiIndex med 1 million rader — en vanlig størrelse i produksjonspipelines for analyse. Den sorterte versjonen unngår det lineære søket og viser konsekvent 5–50 ganger høyere hastighet, avhengig av hvor selektivt utsnittet er.

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 med level-parameteren

For en MultiIndex kan De sortere etter et bestemt nivå i stedet for alle nivåene ved å bruke parameteren level: df.sort_index(level='year'). Dette er nyttig når De vil bevare grupperingen på det ytre nivået, men omorganisere radene innenfor hver ytre gruppe. Argumentet sort_remaining=True (standard) sorterer også eventuelle usorterte nivåer etter det angitte nivået, slik at hele indeksen blir leksikografisk sortert.

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 som pipeline-vakt

I produksjonspipelines bør De legge inn en sorteringsvakt i starten av alle funksjoner som mottar en DataFrame med en MultiIndex og utfører utsnitt. Hvis indeksen ikke er sortert, skal den sorteres automatisk, og en advarsel skal logges. Dette hindrer umerkelig ytelsesforringelse eller feil resultater når kode oppstrøms endrer rekkefølgen på DataFrame-en. En vakt ved funksjonsgrensen er mer pålitelig enn å anta at kallere alltid sender sorterte data.

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)

Sortert indeks for binærsøk på enkle indekser

Ytelsesfordelene ved sortering gjelder også for vanlige indekser (ikke-multiindekser). En DatetimeIndex som brukes i tidsserieanalyse, utfører utsnitt av datointervaller mye raskere når den er sortert. En strengindeks som er sortert alfabetisk, muliggjør binærsøk ved oppslag etter etiketter. For en stor Series med aksjekurser indeksert etter tidsstempel kan sortering av DatetimeIndex forvandle et utsnitt på 100 ms til en operasjon som tar under ett millisekund.

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')

Minnekostnaden ved sortering

Sortering er ikke kostnadsfri — sort_index() oppretter en ny kopi av DataFrame-en (med mindre De bruker inplace=True, som endrer den på stedet). For svært store DataFrame-er dobler dette det midlertidige toppnivået for minnebruk. En praktisk strategi er å sortere én gang ved innlasting og beholde den sorterte versjonen gjennom hele pipelinen, i stedet for å sortere gjentatte ganger. Hvis minnet er begrenset, kan De sortere på stedet med df.sort_index(inplace=True) for å unngå den midlertidige kopien.

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)

Oppsummering av beste praksis for sorterte indekser

Viktige regler for indeksytelse: 1) Kall alltid sort_index() etter operasjoner som kan gjøre indeksen usortert (concat, merge, append, filter). 2) Bruk is_monotonic_increasing som vakt i funksjoner som tar utsnitt av indeksen. 3) Sorter ved innlasting, og behold den sorterte DataFrame-en gjennom hele pipelinen for å unngå gjentatt sortering. 4) For DataFrame-er med MultiIndex må De sørge for at alle nivåer er sortert, ikke bare det ytterste. 5) Bruk timeit for å kontrollere at sorteringen faktisk gir den forventede hastighetsøkningen i akkurat Deres pipeline.

Hurtigsjekk

Test forståelsen Deres av ytelsen til sorterte indekser fra denne leksjonen.

Oppsummering av leksjonen

I denne leksjonen lærte De at is_monotonic_increasing kontrollerer om en indeks er sortert og om binærsøk er tilgjengelig, at sort_index() sorterer på stedet eller returnerer en sortert kopi, og at timeit måler den faktiske hastighetsøkningen for å bekrefte fordelen. Deretter skal vi se på vindusfunksjoner — rullerende og ekspanderende statistikk for tidsserier og finansielle data.

Gratis å komme i gang

Lær deg Python med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
30
Leksjoner
120

Ofte stilte spørsmål

Er leksjonen «Ytelsesfordeler med sorterte indekser» gratis?

Ja – hele teksten i «Ytelsesfordeler med sorterte indekser» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av Pandas & NumPy Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i Pandas & NumPy Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Ytelsesfordeler med sorterte indekser»?

Sorter en MultiIndex med sort_index(), mål ytelsen til utsnitt med timeit, og bruk is_monotonic_increasing som kontroll. Du øver på Pandas & NumPy Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Pandas & NumPy Academy?

Ingen tidligere erfaring er nødvendig. Pandas & NumPy Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 4 av 4.

Hvor lang tid tar leksjonen «Ytelsesfordeler med sorterte indekser»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Pandas & NumPy Academy-leksjonen?

Ja. Alle Pandas & NumPy Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Opprette en MultiIndex
  2. Velge data fra en MultiIndex
  3. Indeksjustering og reindeksering
  4. Ytelsesfordeler med sorterte indekser
← Tilbake til Pandas & NumPy Academy