0Pricing
Pandas & NumPy Academy · บทเรียน

ประโยชน์ด้านประสิทธิภาพของดัชนีที่เรียงแล้ว

เรียง MultiIndex ด้วย sort_index() วัดประสิทธิภาพของการเลือกช่วงด้วย timeit และใช้ is_monotonic_increasing เป็นตัวตรวจสอบ

ประโยชน์ด้านประสิทธิภาพของดัชนีที่เรียงแล้ว เป็นบทเรียน Pandas & NumPy Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Pandas & NumPy Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดการเรียงลำดับดัชนีจึงสำคัญต่อประสิทธิภาพ

ดัชนีที่เรียงลำดับแล้วช่วยให้แพนด้าส์ใช้ การค้นหาแบบทวิภาค (O(log n)) แทนการไล่ค้นหาเชิงเส้นทั้งหมด (O(n)) เมื่อต้องค้นหาช่วงป้ายกำกับ สำหรับ DataFrame ที่มีหนึ่งล้านแถว การค้นหาแบบทวิภาคจะพบช่วงเป้าหมายด้วยการเปรียบเทียบประมาณ 20 ครั้ง เทียบกับการเปรียบเทียบได้ถึงหนึ่งล้านครั้งในการไล่ค้นหาเชิงเส้น ด้วยเหตุนี้ การตัดช่วงบน MultiIndexes ที่เรียงลำดับแล้วจึงเร็วกว่าแบบที่ไม่ได้เรียงลำดับหลายระดับความสำคัญ และความแตกต่างนี้มีความสำคัญอย่างยิ่งในไปป์ไลน์การใช้งานจริงที่ประมวลผลข้อมูลหลายล้านแถว

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

ตรวจสอบว่าดัชนีเรียงลำดับแล้วหรือไม่

ใช้ df.index.is_monotonic_increasing เพื่อตรวจสอบว่าดัชนีเรียงจากน้อยไปมากหรือไม่ ค่านี้จะคืนค่าแบบบูลีน สำหรับ MultiIndex แพนด้าส์จะตรวจสอบการเรียงตามลำดับพจนานุกรมในทุกระดับ ควรตรวจสอบค่านี้เสมอก่อนดำเนินการตัดช่วงด้วย .loc[start:end] บน MultiIndex — ดัชนีที่ไม่ได้เรียงลำดับอาจทำให้เกิด UnsortedIndexError หรือคืนผลลัพธ์ที่ไม่ถูกต้องโดยไม่แจ้งข้อผิดพลาด ทั้งนี้ขึ้นอยู่กับรุ่นของแพนด้าส์

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)

การเรียงลำดับด้วย sort_index()

df.sort_index() จะคืนค่า DataFrame ใหม่ที่แถวเรียงตามป้ายกำกับดัชนีจากน้อยไปมาก ใช้ ascending=False หากต้องการเรียงจากมากไปน้อย สำหรับ MultiIndex การเรียงจะเป็นไปตามลำดับพจนานุกรม โดยเรียงระดับนอกสุดก่อน แล้วจึงเรียงระดับด้านในภายในแต่ละกลุ่มของระดับนอกสุด ควรเรียงลำดับเสมอหลังการดำเนินการใด ๆ ที่อาจทำให้ดัชนีไม่เป็นระเบียบ เช่น pd.concat การกรอง หรือการเพิ่มแถวใหม่

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)

การวัดเวลาค้นหาด้วย timeit

โมดูล timeit ของไพทอนใช้วัดว่าคำสั่งหนึ่งใช้เวลาทำงานนานเท่าใด โดยเรียกใช้คำสั่งนั้นหลายครั้งแล้วหาค่าเฉลี่ย ใช้โมดูลนี้เปรียบเทียบเวลาค้นหาดัชนีที่เรียงลำดับแล้วกับดัชนีที่ไม่ได้เรียงลำดับ ใน IPython/Jupyter คำสั่งพิเศษ %timeit ให้ความสามารถแบบเดียวกันพร้อมผลลัพธ์ที่อ่านง่ายกว่า การวัดประสิทธิภาพเป็นวิธีเดียวที่เชื่อถือได้ในการยืนยันว่าการปรับปรุงประสิทธิภาพช่วยได้จริง — อย่าคิดไปเองว่าการเปลี่ยนแปลงใดเร็วขึ้นโดยไม่วัดผล

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 จาก MultiIndex ที่ไม่ได้เรียงลำดับ

แพนด้าส์จะแสดง PerformanceWarning เมื่อคุณตัดช่วง MultiIndex ที่ไม่ได้เรียงตามลำดับพจนานุกรม: 'indexing past lexsort depth may impact performance' คำเตือนนี้หมายความว่าแพนด้าส์ต้องย้อนกลับไปใช้การไล่ค้นหาเชิงเส้นแทนการค้นหาแบบทวิภาค แม้ในกรณีง่าย ๆ จะยังคืนผลลัพธ์ที่ถูกต้อง แต่การตัดช่วงระดับด้านในของดัชนีหลายระดับที่ไม่ได้เรียงลำดับอาจให้ ผลลัพธ์ไม่ถูกต้องได้ ให้ถือว่าคำเตือนนี้เป็นข้อผิดพลาด และแก้สาเหตุที่แท้จริงด้วยการเรียงลำดับดัชนี

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

การเปรียบเทียบเวลาการตัดช่วง MultiIndex ที่เรียงลำดับกับไม่ได้เรียงลำดับ

การตัดช่วง MultiIndex ที่เรียงลำดับแล้วเร็วขึ้นอย่างมาก เพราะแพนด้าส์สามารถค้นหาแบบทวิภาคได้ทั้งอาร์เรย์ของระดับนอกและระดับใน มาลองวัดเวลาการตัดช่วง MultiIndex ขนาดใหญ่ที่มีหนึ่งล้านแถว ซึ่งเป็นขนาดที่พบได้ทั่วไปในไปป์ไลน์วิเคราะห์ข้อมูลจริง รุ่นที่เรียงลำดับแล้วจะหลีกเลี่ยงการไล่ค้นหาเชิงเส้น และแสดงความเร็วที่เพิ่มขึ้นอย่างสม่ำเสมอประมาณ 5–50 เท่า ขึ้นอยู่กับความจำเพาะของช่วงที่ตัด

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 กับพารามิเตอร์ level

สำหรับ MultiIndex คุณสามารถเรียงตามระดับที่ระบุแทนการเรียงทุกระดับได้โดยใช้พารามิเตอร์ level: df.sort_index(level='year') วิธีนี้มีประโยชน์เมื่อคุณต้องการคงการจัดกลุ่มตามระดับนอกสุดไว้ แต่จัดเรียงแถวใหม่ภายในแต่ละกลุ่มของระดับนอกสุด อาร์กิวเมนต์ sort_remaining=True (ค่าเริ่มต้น) จะเรียงระดับอื่นที่ยังไม่ได้เรียงซึ่งอยู่ถัดจากระดับที่ระบุด้วย เพื่อให้การเรียงตามลำดับพจนานุกรมสมบูรณ์

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 ในฐานะตัวป้องกันของไปป์ไลน์

ในไปป์ไลน์การใช้งานจริง ให้เพิ่ม ตัวตรวจสอบการเรียงลำดับไว้ที่จุดเริ่มต้นของฟังก์ชันใด ๆ ที่รับ DataFrame ซึ่งมี MultiIndex และดำเนินการตัดช่วง หากดัชนีไม่ได้เรียงลำดับ ให้เรียงลำดับโดยอัตโนมัติและบันทึกคำเตือนไว้ วิธีนี้ช่วยป้องกันประสิทธิภาพที่ลดลงโดยไม่มีการแจ้งเตือน หรือผลลัพธ์ที่ไม่ถูกต้องเมื่อโค้ดต้นทางเปลี่ยนลำดับของ DataFrame การมีตัวตรวจสอบที่ขอบเขตฟังก์ชันเชื่อถือได้มากกว่าการคาดว่าผู้เรียกจะส่งข้อมูลที่เรียงลำดับแล้วเสมอ

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)

ดัชนีที่เรียงลำดับเพื่อการค้นหาแบบทวิภาคบนดัชนีทั่วไป

ประโยชน์ด้านประสิทธิภาพจากการเรียงลำดับนั้นใช้ได้กับ ดัชนีทั่วไป (ไม่ใช่ดัชนีหลายระดับ) เช่นกัน DatetimeIndex ที่ใช้ในการวิเคราะห์อนุกรมเวลาจะตัดช่วงวันที่ได้เร็วขึ้นมากเมื่อเรียงลำดับแล้ว ดัชนีสตริงที่เรียงตามตัวอักษรช่วยให้ค้นหาป้ายกำกับด้วยการค้นหาแบบทวิภาคได้ สำหรับ Series ขนาดใหญ่ของราคาหุ้นที่ใช้เวลาเป็นดัชนี การเรียง DatetimeIndex อาจเปลี่ยนการตัดช่วงที่ใช้เวลา 100 มิลลิวินาทีให้กลายเป็นการดำเนินการที่ใช้เวลาไม่ถึงหนึ่งมิลลิวินาที

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

ต้นทุนหน่วยความจำของการเรียงลำดับ

การเรียงลำดับไม่ได้ไม่มีต้นทุน — sort_index() จะสร้างสำเนาใหม่ของ DataFrame (เว้นแต่ใช้ inplace=True ซึ่งจะแก้ไขข้อมูลเดิมโดยตรง) สำหรับ DataFrame ที่มีขนาดใหญ่มาก การดำเนินการนี้จะทำให้การใช้หน่วยความจำสูงสุดเพิ่มขึ้นเป็นสองเท่าชั่วคราว แนวทางที่เหมาะสมคือ เรียงลำดับเพียงครั้งเดียวขณะโหลดข้อมูล และใช้รุ่นที่เรียงแล้วตลอดทั้งไปป์ไลน์ แทนการเรียงซ้ำหลายครั้ง หากหน่วยความจำมีจำกัด ให้เรียงโดยตรงด้วย df.sort_index(inplace=True) เพื่อหลีกเลี่ยงการสร้างสำเนาชั่วคราว

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)

สรุปแนวปฏิบัติที่ดีสำหรับดัชนีที่เรียงลำดับแล้ว

กฎสำคัญด้านประสิทธิภาพของดัชนี: 1) เรียกใช้ sort_index() เสมอหลังการดำเนินการใด ๆ ที่อาจทำให้ดัชนีไม่เป็นระเบียบ (การต่อ การผสาน การเพิ่ม การกรอง) 2) ใช้ is_monotonic_increasing เป็นตัวตรวจสอบในฟังก์ชันที่ตัดช่วงดัชนี 3) เรียงลำดับขณะโหลดข้อมูล และใช้ DataFrame ที่เรียงแล้วตลอดทั้งไปป์ไลน์เพื่อหลีกเลี่ยงการเรียงซ้ำ 4) สำหรับ DataFrame ที่มี MultiIndex ตรวจสอบให้แน่ใจว่า ทุกระดับเรียงลำดับแล้ว ไม่ใช่เฉพาะระดับนอกสุด 5) ใช้ timeit เพื่อยืนยันว่าการเรียงลำดับช่วยเพิ่มความเร็วได้ตามที่คาดไว้จริงในไปป์ไลน์เฉพาะของคุณ

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับประสิทธิภาพของดัชนีที่เรียงลำดับแล้วจากบทเรียนนี้

สรุปบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า การเพิ่มขึ้นแบบโมโนโทนใช้ตรวจสอบว่าดัชนีเรียงลำดับแล้วและสามารถใช้การค้นหาแบบทวิภาคได้หรือไม่ sort_index()ใช้เรียงลำดับโดยตรงหรือคืนสำเนาที่เรียงลำดับแล้ว และ timeitใช้วัดความเร็วที่เพิ่มขึ้นจริงเพื่อยืนยันประโยชน์ ต่อไปเราจะสำรวจฟังก์ชันหน้าต่าง — สถิติแบบ rolling และแบบขยายสำหรับอนุกรมเวลาและข้อมูลการเงิน

คำถามที่พบบ่อย

บทเรียน “ประโยชน์ด้านประสิทธิภาพของดัชนีที่เรียงแล้ว” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ประโยชน์ด้านประสิทธิภาพของดัชนีที่เรียงแล้ว” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Pandas & NumPy Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ประโยชน์ด้านประสิทธิภาพของดัชนีที่เรียงแล้ว”

เรียง MultiIndex ด้วย sort_index() วัดประสิทธิภาพของการเลือกช่วงด้วย timeit และใช้ is_monotonic_increasing เป็นตัวตรวจสอบ คุณปฏิบัติ Pandas & NumPy Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Pandas & NumPy Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Pandas & NumPy Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “ประโยชน์ด้านประสิทธิภาพของดัชนีที่เรียงแล้ว” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Pandas & NumPy Academy นี้ได้ไหม

ได้ บทเรียน Pandas & NumPy Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การสร้าง MultiIndex
  2. การเลือกข้อมูลจาก MultiIndex
  3. การจัดแนวดัชนีและการสร้างดัชนีใหม่
  4. ประโยชน์ด้านประสิทธิภาพของดัชนีที่เรียงแล้ว
← กลับไปที่ Pandas & NumPy Academy