หน้าต่างสะสม
คำนวณสถิติสะสมที่รวมทุกแถวตั้งแต่เริ่มต้นจนถึงแต่ละจุดด้วย expanding().sum()
หน้าต่างสะสม เป็นบทเรียน Pandas & NumPy Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Pandas & NumPy Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน
หน้าต่างแบบขยายคืออะไร
หน้าต่างแบบขยาย จะรวมแถวทั้งหมดตั้งแต่จุดเริ่มต้นของ Series จนถึงแถวปัจจุบัน หน้าต่างจะขยายขึ้นเมื่อมีแถวใหม่ แทนที่จะคงขนาดเดิม เมื่ออยู่ที่แถว 0 จะมีค่าเพียงหนึ่งค่า เมื่ออยู่ที่แถว 5 จะมีหกค่า และเมื่ออยู่ที่แถว 100 จะมี 101 ค่า หน้าต่างแบบขยายใช้สำหรับคำนวณ สถิติสะสม ซึ่งแสดงยอดรวมสะสม ค่าเฉลี่ยสะสม หรือค่าสูงสุดสะสมตั้งแต่เริ่มชุดข้อมูลจนถึงเวลาปัจจุบัน
import pandas as pd
import numpy as np
sales = pd.Series(
[100, 150, 120, 200, 180, 160, 220, 190],
index=pd.date_range('2024-01-01', periods=8)
)
# Expanding mean — grows with each row
df = pd.DataFrame({'sales': sales})
df['cumulative_mean'] = df['sales'].expanding().mean()
print(df)เมธอด expanding()
Series.expanding(min_periods=1) จะส่งคืนออบเจ็กต์ Expanding พารามิเตอร์ min_periods (ค่าเริ่มต้นคือ 1) จะกำหนดจำนวนข้อมูลสังเกตขั้นต่ำที่ต้องมีก่อนจึงจะได้ผลลัพธ์ที่ไม่ใช่ NaN ค่าแรก ซึ่งต่างจาก rolling(n) หน้าต่างใน expanding() จะไม่คงขนาดเดิม แต่จะเริ่มต้นจากจุดเริ่มต้นเสมอ คุณสามารถต่อด้วยการรวมค่าใดก็ได้ เช่น .sum(), .mean(), .std(), .min(), .max()
import pandas as pd
import numpy as np
np.random.seed(42)
monthly_revenue = pd.Series(
np.random.randint(500, 1500, 12),
index=pd.date_range('2024-01', periods=12, freq='ME'),
name='revenue'
)
df = pd.DataFrame({'revenue': monthly_revenue})
df['cumsum'] = df['revenue'].expanding().sum()
df['cummean'] = df['revenue'].expanding().mean()
df['cummax'] = df['revenue'].expanding().max()
df['cummin'] = df['revenue'].expanding().min()
print(df)cumsum, cumprod, cummax, cummin ของ Pandas
สำหรับสถิติสะสมที่ใช้บ่อยที่สุด Pandas มีเมธอดโดยตรงใน Series และ DataFrame โดยไม่จำเป็นต้องใช้ expanding() ได้แก่ cumsum(), cumprod(), cummax() และ cummin() เมธอดเหล่านี้เป็นการใช้งานที่ปรับประสิทธิภาพมาแล้ว จึงเร็วกว่าวิธีที่เทียบเท่ากับ expanding() เล็กน้อย ให้ใช้ทางลัดเหล่านี้กับตัวชี้วัดทางธุรกิจทั่วไป เช่น รายได้สะสมตั้งแต่ต้นปี (cumsum) หรือราคาสูงสุดตลอดกาล (cummax)
import pandas as pd
import numpy as np
prices = pd.Series(
[100, 95, 110, 105, 120, 115, 130, 125],
index=pd.date_range('2024-01-01', periods=8)
)
df = pd.DataFrame({'price': prices})
df['cummax'] = df['price'].cummax() # all-time high
df['cummin'] = df['price'].cummin() # all-time low
df['cumsum'] = df['price'].cumsum() # cumulative total
df['cumprod'] = (1 + df['price'].pct_change()).cumprod() # growth index
print(df.round(3))การคำนวณตั้งแต่ต้นปีด้วย Expanding
การใช้งานหน้าต่างแบบขยายที่พบได้บ่อยคือรายได้แบบ ตั้งแต่ต้นปี (YTD) สำหรับแต่ละวัน คุณต้องการผลรวมรายได้ทั้งหมดตั้งแต่วันที่ 1 มกราคมของปีปัจจุบันจนถึงวันนั้น วิธีนี้ก็คือการใช้ cumsum() ภายในแต่ละกลุ่มของปี ให้ดำเนินการด้วย groupby(year).cumsum() โดย cumsum จะเริ่มนับใหม่เมื่อเริ่มปีปฏิทินแต่ละปี และสะสมต่อไปตลอดทั้งปี
import pandas as pd
import numpy as np
np.random.seed(0)
dates = pd.date_range('2023-01-01', '2024-06-30', freq='ME')
daily = pd.DataFrame({
'date': dates,
'revenue': np.random.randint(100, 500, len(dates))
})
# Year-to-date cumulative revenue
daily['year'] = daily['date'].dt.year
daily['ytd_revenue'] = daily.groupby('year')['revenue'].cumsum()
daily = daily.drop(columns='year')
print(daily.tail(10).to_string(index=False))ส่วนเบี่ยงเบนมาตรฐานแบบขยาย
expanding().std() จะคำนวณ ส่วนเบี่ยงเบนมาตรฐานสะสม โดยใช้ข้อมูลทั้งหมดตั้งแต่จุดเริ่มต้นจนถึงแถวปัจจุบัน วิธีนี้มีประโยชน์สำหรับติดตามว่าความแปรปรวนของตัวชี้วัดเพิ่มขึ้นหรือลดลงตามเวลาหรือไม่ เช่น ติดตามว่ายอดขายรายวันของสินค้ามีความคาดการณ์ได้มากขึ้นหรือน้อยลงเมื่อธุรกิจเติบโตหรือไม่ ต่างจาก rolling std ซึ่งสะท้อนเฉพาะความแปรปรวนล่าสุด expanding std จะแสดงการกระจายของข้อมูลในประวัติทั้งหมด
import pandas as pd
import numpy as np
np.random.seed(42)
sales = pd.Series(
np.concatenate([
np.random.normal(100, 5, 30), # stable period
np.random.normal(100, 25, 30) # volatile period
]),
index=pd.date_range('2024-01-01', periods=60)
)
df = pd.DataFrame({'sales': sales})
df['expanding_std'] = df['sales'].expanding().std()
df['rolling_30d_std'] = df['sales'].rolling(30).std()
print(df.tail(10).round(2))เปรียบเทียบ Rolling กับ Expanding
ความแตกต่างสำคัญคือ หน้าต่างแบบเลื่อน สะท้อนผลการดำเนินงานล่าสุด (n วันล่าสุด) และไม่ไวต่อข้อมูลที่เกิดขึ้นนานมาแล้ว ขณะที่ หน้าต่างแบบขยาย รวมข้อมูลจากประวัติทั้งหมด จึงค่อย ๆ เข้าใกล้ค่าที่มีเสถียรภาพ ใช้ rolling เมื่อต้องการดูแนวโน้ม ล่าสุด (ค่าเฉลี่ยเคลื่อนที่ 7 วันตอบสนองต่อการเปลี่ยนแปลงล่าสุดได้ดีกว่าค่าเฉลี่ย 90 วัน) และใช้ expanding เมื่อต้องการสถิติ ตลอดช่วงเวลา หรือค่าตัวชี้วัด YTD ที่ต้องไม่ลืมข้อมูลก่อนหน้า
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(10)
data = pd.Series(
np.random.randn(60).cumsum() + 50,
index=pd.date_range('2024-01-01', periods=60)
)
df = pd.DataFrame({'value': data})
df['rolling_10'] = data.rolling(10).mean()
df['expanding'] = data.expanding().mean()
df.plot(figsize=(12, 5), title='Rolling 10-day Mean vs. Expanding Mean')
plt.ylabel('Value')
plt.show()การใช้ Expanding Apply กับสถิติสะสมที่กำหนดเอง
expanding().apply(func) จะใช้ฟังก์ชันที่กำหนดเองกับข้อมูลทั้งหมดตั้งแต่จุดเริ่มต้นจนถึงแถวปัจจุบัน เช่นเดียวกับ rolling().apply() วิธีนี้ทำให้คำนวณสถิติสะสมที่ไม่มีฟังก์ชันสำเร็จรูปได้ เช่น สัมประสิทธิ์ความแปรผันสะสม (std/mean) มัธยฐานสะสม หรืออัตราส่วน Sharpe สะสม ฟังก์ชันจะได้รับอาร์เรย์ NumPy ที่มีค่าทั้งหมดที่พบจนถึงขณะนั้น และต้องส่งคืนค่าเดียว
import pandas as pd
import numpy as np
np.random.seed(0)
returns = pd.Series(
np.random.normal(0.001, 0.02, 60),
index=pd.date_range('2024-01-01', periods=60)
)
# Cumulative Sharpe ratio (mean/std of returns)
def sharpe(arr):
if len(arr) < 2:
return float('nan')
return arr.mean() / arr.std() * (252 ** 0.5) # annualised
df = pd.DataFrame({'returns': returns})
df['cum_sharpe'] = df['returns'].expanding().apply(sharpe, raw=True)
print(df.tail(8).round(4))หน้าต่างแบบขยายกับการจัดการ NaN
หน้าต่างแบบขยายจะข้ามค่า NaN โดยค่าเริ่มต้น หากมี NaN อยู่ตรงกลางของ Series ค่านั้นจะถูกละเว้นเมื่อคำนวณผลรวมสะสมหรือค่าเฉลี่ย คุณสามารถตรวจสอบการทำงานนี้ได้ด้วย skipna=True (ซึ่งเป็นค่าเริ่มต้นในการรวมค่าของ Pandas ส่วนใหญ่) เมื่อมีอนุกรมเวลาที่มีค่าหายไปจริง เช่น ไม่มีการซื้อขายในวันหยุดสุดสัปดาห์ สถิติแบบขยายจะคำนวณจากค่า non-NaN ที่พบจนถึงขณะนั้นเท่านั้น ซึ่งโดยทั่วไปเป็นพฤติกรรมที่ต้องการ
import pandas as pd
import numpy as np
data = pd.Series([10, np.nan, 20, 30, np.nan, 40, 50])
# cumsum skips NaN by default
df = pd.DataFrame({'value': data})
df['cumsum'] = df['value'].cumsum() # NaN propagates in cumsum!
df['expanding_sum'] = df['value'].expanding().sum() # NaN skipped
print(df)
print('\nNote: cumsum propagates NaN; expanding().sum() skips it.')หน้าต่างแบบขยายสำหรับค่ามาตรฐานสะสม
หน้าต่างแบบขยายเหมาะอย่างยิ่งสำหรับการคำนวณ ค่ามาตรฐานสะสม เช่น ค่าสูงสุดตลอดกาล ไตรมาสที่ดีที่สุดเท่าที่เคยมีมา หรืออัตราข้อผิดพลาดต่ำสุดนับตั้งแต่เปิดตัว ตัวชี้วัดสำคัญเหล่านี้ต้องจดจำค่าทางประวัติทั้งหมด เพราะหน้าต่างแบบเลื่อนจะลืมข้อมูลเก่า การใช้ cummax() หรือ cummin() จะส่งคืนค่าที่ดีที่สุด (หรือแย่ที่สุด) สะสม ณ แต่ละจุด ทำให้ติดตามได้ง่ายว่ามีการสร้างสถิติใหม่เมื่อใด
import pandas as pd
import numpy as np
np.random.seed(5)
sales = pd.Series(
np.random.randint(100, 300, 20),
index=pd.date_range('2024-01-01', periods=20),
name='daily_sales'
)
df = pd.DataFrame({'sales': sales})
df['all_time_max'] = df['sales'].cummax()
df['new_record'] = df['sales'] == df['all_time_max']
print('Days where a new sales record was set:')
print(df[df['new_record']].drop(columns='new_record'))ตัวอย่างเชิงปฏิบัติ: ผลตอบแทนสะสม
ในด้านการเงิน ผลตอบแทนสะสม แสดงให้เห็นว่าการลงทุนเติบโตขึ้นมากเพียงใดนับจากวันที่เริ่มต้นจนถึงแต่ละวันถัดไป เมื่อเริ่มจากผลตอบแทนเป็นเปอร์เซ็นต์รายวัน ผลคูณสะสมของ (1 + daily_return) จะให้ตัวคูณการเติบโตทั้งหมด การคูณแบบขยายเหมาะสมกว่าการคูณแบบเลื่อนในกรณีนี้ เพราะคุณต้องการติดตามการเติบโตทั้งหมดตั้งแต่เริ่มลงทุน ไม่ใช่เฉพาะใน n วันล่าสุด
import pandas as pd
import numpy as np
np.random.seed(7)
start_price = 100
daily_returns = pd.Series(
np.random.normal(0.0005, 0.015, 252),
index=pd.date_range('2024-01-01', periods=252)
)
# Cumulative return = product of (1 + r_i)
cum_returns = (1 + daily_returns).cumprod()
portfolio_value = start_price * cum_returns
print(f'Start value: ${start_price:.2f}')
print(f'End value: ${portfolio_value.iloc[-1]:.2f}')
print(f'Total return: {(portfolio_value.iloc[-1]/start_price - 1)*100:.1f}%')ควรใช้ Expanding, Rolling หรือ cumsum เมื่อใด
แนวทางเลือกวิธีที่เหมาะสม:
- ใช้
cumsum() / cummax() / cummin()สำหรับการรวมค่าสะสมแบบง่าย ๆ เพราะเป็นตัวเลือกที่เร็วที่สุด - ใช้
expanding().mean() / std()เมื่อต้องการค่าเฉลี่ยสะสมหรือความแปรปรวนสะสม - ใช้
expanding().apply(custom_func)สำหรับสถิติที่ซับซ้อนตลอดช่วงเวลา ซึ่งไม่มีฟังก์ชันสำเร็จรูปให้ใช้ - ใช้
rolling(n)แทน expanding เมื่อควรให้เฉพาะประวัติล่าสุดมีผลต่อค่าปัจจุบัน
ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจเกี่ยวกับหน้าต่างแบบขยายจากบทเรียนนี้
ทบทวนบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า expanding() คำนวณสถิติสะสมภายในหน้าต่างที่ขยายจากจุดเริ่มต้นของ Series, cumsum/cummax/cummin เป็นทางลัดที่ปรับประสิทธิภาพแล้วสำหรับการดำเนินการสะสมที่ใช้บ่อย และหน้าต่างแบบขยายเหมาะสำหรับสถิติตลอดช่วงเวลา ตัวชี้วัด YTD และผลตอบแทนการลงทุนสะสม ต่อไปเราจะสำรวจค่าเฉลี่ยเคลื่อนที่แบบถ่วงน้ำหนักเอ็กซ์โพเนนเชียล (EWMA) ซึ่งให้น้ำหนักกับข้อมูลสังเกตล่าสุดมากกว่า
เรียนรู้ Python ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 30
- บทเรียน
- 120
คำถามที่พบบ่อย
บทเรียน “หน้าต่างสะสม” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “หน้าต่างสะสม” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Pandas & NumPy Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “หน้าต่างสะสม”
คำนวณสถิติสะสมที่รวมทุกแถวตั้งแต่เริ่มต้นจนถึงแต่ละจุดด้วย expanding().sum() คุณปฏิบัติ Pandas & NumPy Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Pandas & NumPy Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Pandas & NumPy Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “หน้าต่างสะสม” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Pandas & NumPy Academy นี้ได้ไหม
ได้ บทเรียน Pandas & NumPy Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- หน้าต่างเลื่อน
- หน้าต่างสะสม
- ค่าเฉลี่ยเคลื่อนที่แบบถ่วงน้ำหนักเอ็กซ์โพเนนเชียล
- อันดับและเปอร์เซ็นไทล์ภายในกลุ่ม