การรวมค่าแบบเพิ่มทีละส่วนระหว่างชิ้นข้อมูล
สะสมจำนวน ผลรวม และค่าต่ำสุด/สูงสุดที่คำนวณต่อเนื่องระหว่างชิ้นข้อมูล โดยไม่เก็บไฟล์ทั้งหมดไว้ในหน่วยความจำ
การรวมค่าแบบเพิ่มทีละส่วนระหว่างชิ้นข้อมูล เป็นบทเรียน Pandas & NumPy Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Pandas & NumPy Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงต้องหาค่ารวมแบบทยอยเพิ่ม
การหาค่ารวมแบบทยอยเพิ่ม เป็นกุญแจสำคัญในการวิเคราะห์ชุดข้อมูลที่มีขนาดใหญ่กว่า RAM โดยไม่ต้องกระจายการคำนวณไปยังหลายเครื่อง แทนที่จะโหลดข้อมูลทั้งหมดเพื่อคำนวณสถิติสุดท้าย ให้รักษา ตัวสะสมแบบต่อเนื่อง ได้แก่ ผลรวมบางส่วน จำนวน และค่าต่ำสุด/สูงสุด แล้วอัปเดตตัวสะสมเหล่านี้เมื่อประมวลผลแต่ละส่วน ผลลัพธ์สุดท้ายจะประกอบขึ้นจากตัวสะสมขนาดเล็กเหล่านี้หลังจากสแกนไฟล์ทั้งหมดแล้ว รูปแบบนี้รองรับไฟล์ขนาดเทราไบต์ได้บนแล็ปท็อปเครื่องเดียว
การนับแถวและการคำนวณค่าเฉลี่ย
การคำนวณ ค่าเฉลี่ย ข้ามส่วนจำเป็นต้องติดตามผลรวมสะสมและจำนวนสะสมแยกกัน คุณไม่สามารถนำค่าเฉลี่ยของแต่ละส่วนมาเฉลี่ยตรง ๆ ได้ เพราะแต่ละส่วนอาจมีขนาดไม่เท่ากัน สูตรที่ถูกต้องคือ total_sum / total_count รูปแบบนี้ใช้ได้กับปริมาณใด ๆ ที่สามารถแยกองค์ประกอบได้ เช่น ความแปรปรวน สหสัมพันธ์ และฮิสโตแกรมต่างก็มีสูตรแบบทยอยเพิ่ม
import pandas as pd
total_sum = 0.0
total_count = 0
for chunk in pd.read_csv('transactions.csv', chunksize=100000):
total_sum += chunk['amount'].sum()
total_count += chunk['amount'].notna().sum()
grand_mean = total_sum / total_count
print(f'Rows processed: {total_count:,}')
print(f'Grand mean: {grand_mean:.4f}')ค่าต่ำสุดและสูงสุดแบบทยอยเพิ่ม
การติดตามค่าต่ำสุดและสูงสุดทั่วทั้งข้อมูลข้ามส่วนทำได้ตรงไปตรงมา โดยเริ่มต้นด้วย float('inf') และ float('-inf') ของ Python จากนั้นอัปเดตด้วยค่าต่ำสุด/สูงสุดของแต่ละส่วน วิธีนี้ไม่ต้องจัดเก็บข้อมูลระหว่างทาง รูปแบบเดียวกันนี้ขยายไปใช้กับค่าต่ำสุด/สูงสุดแยกตามกลุ่มได้ โดยรักษาพจนานุกรมที่ใช้ตัวระบุกลุ่มเป็นคีย์
import pandas as pd
global_min = float('inf')
global_max = float('-inf')
for chunk in pd.read_csv('prices.csv', chunksize=50000):
chunk_min = chunk['price'].min()
chunk_max = chunk['price'].max()
if chunk_min < global_min:
global_min = chunk_min
if chunk_max > global_max:
global_max = chunk_max
print(f'Price range: {global_min} to {global_max}')การนับความถี่แบบทยอยเพิ่ม
สำหรับคอลัมน์ประเภทหมวดหมู่ ให้รักษา พจนานุกรมความถี่สะสม โดยนำผลลัพธ์ value_counts() ของแต่ละส่วนไปเพิ่มในตัวสะสม Pandas Series เนื่องจากการบวก Pandas Series จะจัดแนวตามป้ายกำกับดัชนี หมวดหมู่ที่ไม่เคยพบในส่วนก่อนหน้าจึงถูกเพิ่มเข้ามาโดยอัตโนมัติ หลังประมวลผลครบทุกส่วน ให้เรียงตามจำนวนเพื่อดูหมวดหมู่ยอดนิยมทั่วทั้งชุดข้อมูล
import pandas as pd
freq = pd.Series(dtype='int64')
for chunk in pd.read_csv('orders.csv',
chunksize=100000,
usecols=['category']):
chunk_counts = chunk['category'].value_counts()
freq = freq.add(chunk_counts, fill_value=0)
# Final sorted frequency table
print(freq.sort_values(ascending=False).head(10))การหาค่ารวมด้วย GroupBy แบบทยอยเพิ่ม
หากต้องการคำนวณ ผลรวมหรือจำนวนด้วย groupby ข้ามส่วน ให้ใช้ groupby().agg() ภายในแต่ละส่วนและจัดเก็บ Series หรือ DataFrame ที่ได้ หลังจบลูป ให้นำผลลัพธ์บางส่วนทั้งหมดมาต่อกัน แล้วใช้ groupby ครั้งที่สองเพื่อรวมผลลัพธ์ วิธีสองขั้นตอนนี้จัดการกลุ่มที่ปรากฏในหลายส่วนได้อย่างถูกต้อง ซึ่งพบได้บ่อยเมื่อข้อมูลเรียงตามวันที่แทนที่จะเรียงตามกลุ่ม
import pandas as pd
partials = []
for chunk in pd.read_csv('sales.csv',
chunksize=100000,
usecols=['region', 'product', 'revenue']):
p = chunk.groupby(['region', 'product'])['revenue'].sum()
partials.append(p)
final = (
pd.concat(partials)
.groupby(level=['region', 'product'])
.sum()
.sort_values(ascending=False)
)
print(final.head(10))การคำนวณความแปรปรวนแบบทยอยเพิ่ม (วิธีของ Welford)
การคำนวณความแปรปรวนข้ามส่วนซับซ้อนกว่าการคำนวณค่าเฉลี่ย สูตรพื้นฐาน E[X²] - E[X]² มีปัญหาการหักล้างกันอย่างรุนแรงเมื่อค่าเฉลี่ยมีขนาดใหญ่ อัลกอริทึมออนไลน์ของ Welford จะรักษาค่าเฉลี่ยสะสมและผลรวมของค่าความเบี่ยงเบนกำลังสองสะสม โดยอัปเดตค่าทั้งสองเมื่อพบค่าใหม่แต่ละค่าอย่างมีเสถียรภาพทางตัวเลข แม้ SciPy จะมีการใช้งานนี้อยู่แล้ว แต่การเข้าใจรูปแบบดังกล่าวจะช่วยให้คุณต่อยอดไปยังความแปรปรวนแบบถ่วงน้ำหนักและความแปรปรวนร่วมได้
import pandas as pd
import numpy as np
# Simple two-pass approach using stored chunk stats
chunk_stats = []
for chunk in pd.read_csv('data.csv',
chunksize=100000,
usecols=['value']):
n = chunk['value'].count()
mean = chunk['value'].mean()
var = chunk['value'].var(ddof=1)
chunk_stats.append((n, mean, var))
# Combine: use pooled variance formula
total_n = sum(s[0] for s in chunk_stats)
total_mean = sum(s[0]*s[1] for s in chunk_stats) / total_n
pooled_var = sum((s[0]-1)*s[2] + s[0]*(s[1]-total_mean)**2
for s in chunk_stats) / (total_n - 1)
print(f'Grand variance: {pooled_var:.4f}')การสร้างฮิสโตแกรมแบบทยอยเพิ่ม
การคำนวณการกระจายของคอลัมน์ในไฟล์ที่ใหญ่เกินกว่า RAM ต้องใช้ ฮิสโตแกรมแบบทยอยเพิ่ม กำหนดขอบเขตของช่วงชั้นไว้ล่วงหน้า โดยอ้างอิงจากตัวอย่างขนาดเล็กหรือความรู้เฉพาะด้าน จากนั้นใช้ np.histogram(chunk_values, bins=edges) ภายในแต่ละส่วนและสะสมจำนวน เมื่อสิ้นสุด ให้วาดจำนวนรวมเป็นแผนภูมิแท่ง นี่คือวิธีที่ระบบสตรีมข้อมูลอย่าง Kafka Streams และ Flink ใช้คำนวณฮิสโตแกรมโดยประมาณ
import pandas as pd
import numpy as np
# Decide bin edges from a sample
sample = pd.read_csv('amounts.csv', nrows=5000)
bins = np.linspace(sample['amount'].min(),
sample['amount'].max(), 21)
counts = np.zeros(len(bins) - 1, dtype='int64')
for chunk in pd.read_csv('amounts.csv',
chunksize=100000,
usecols=['amount']):
chunk_counts, _ = np.histogram(
chunk['amount'].dropna(), bins=bins
)
counts += chunk_counts
print('Histogram counts:', counts[:5], '...')การติดตามค่าที่ไม่ซ้ำกันโดยประมาณ
การนับค่าที่แตกต่างกันอย่างแม่นยำข้ามส่วนจำเป็นต้องจัดเก็บค่าที่ไม่ซ้ำกันทั้งหมด ซึ่งอาจมีจำนวนหลายล้านค่า สำหรับการนับโดยประมาณในระดับใหญ่ ให้ใช้โครงสร้าง HyperLogLog ซึ่งพร้อมใช้งานใน Python ผ่านไลบรารี hyperloglog อีกทางเลือกหนึ่งคือ ติดตามค่าที่ไม่ซ้ำกันในแต่ละส่วนด้วยเซตแล้วหายูเนียน แต่โครงสร้างนี้จะเติบโตโดยไม่มีขอบเขต หากต้องการการประมาณแบบประหยัด ให้ใช้ pd.Series.nunique() ในแต่ละส่วนแล้วรายงานค่าเฉลี่ย วิธีนี้ไม่แม่นยำแน่นอน แต่เพียงพอสำหรับการสำรวจข้อมูลในหลายกรณี
import pandas as pd
unique_ids = set()
for chunk in pd.read_csv('events.csv',
chunksize=100000,
usecols=['user_id']):
unique_ids.update(chunk['user_id'].dropna().unique())
print(f'Distinct user IDs: {len(unique_ids):,}')
# Warning: the set may grow large for high-cardinality columnsการรายงานความคืบหน้าระหว่างการทำงานที่ใช้เวลานาน
การประมวลผลไฟล์ขนาดหลายกิกะไบต์อาจใช้เวลาหลายนาที ให้เพิ่ม การรายงานความคืบหน้า เพื่อให้ทราบว่าไปป์ไลน์ยังทำงานอยู่และสามารถประมาณเวลาที่เหลือได้ นับจำนวนไบต์หรือแถวที่ประมวลผลแล้วเปรียบเทียบกับขนาดไฟล์ ไลบรารี tqdm ทำให้เรื่องนี้ง่ายด้วยตัวห่อ tqdm(reader) แม้ไม่มี tqdm การพิมพ์บรรทัดสถานะทุก ๆ 10 ส่วนก็ให้ข้อมูลที่มีประโยชน์ระหว่างงานชุดที่ใช้เวลานาน
import pandas as pd
import time
chunksize = 100000
start = time.time()
rows_processed = 0
for i, chunk in enumerate(pd.read_csv('big.csv',
chunksize=chunksize)):
rows_processed += len(chunk)
# Report every 10 chunks
if (i + 1) % 10 == 0:
elapsed = time.time() - start
rate = rows_processed / elapsed
print(f'Chunk {i+1}: {rows_processed:,} rows '
f'@ {rate/1000:.0f}k rows/sec')
print(f'Total: {rows_processed:,} rows in {time.time()-start:.1f}s')การกรองก่อนการหาค่ารวม
ใช้ตัวกรอง ภายในแต่ละส่วน ก่อนหาค่ารวม เพื่อหลีกเลี่ยงการสะสมข้อมูลที่ไม่ต้องการ ตัวอย่างเช่น หากคุณสนใจเฉพาะคำสั่งซื้อในปี 2024 ให้กรองคอลัมน์วันที่ของส่วนข้อมูลก่อนทำ groupby วิธีนี้ลดหน่วยความจำที่ต้องใช้สำหรับผลลัพธ์บางส่วนและเร่งขั้นตอนการนำผลลัพธ์มาต่อกันในตอนท้าย ควรผลักตัวกรองให้ทำงานเร็วที่สุดเท่าที่ทำได้ในไปป์ไลน์เสมอ ซึ่งเป็นหลักการพื้นฐานของการประมวลผลข้อมูลอย่างมีประสิทธิภาพ
import pandas as pd
partials = []
for chunk in pd.read_csv('orders.csv',
chunksize=100000,
parse_dates=['order_date']):
# Filter early: only 2024 orders
mask = chunk['order_date'].dt.year == 2024
filtered = chunk.loc[mask, ['category', 'revenue']]
if len(filtered) > 0:
p = filtered.groupby('category')['revenue'].sum()
partials.append(p)
if partials:
result = pd.concat(partials).groupby(level=0).sum()
print(result)การบันทึกผลลัพธ์ระหว่างทาง
สำหรับงานที่ใช้เวลาทำงานนานมาก ควรบันทึกผลลัพธ์ระหว่างทางเป็นระยะ เพื่อให้สามารถทำงานต่อจากจุดตรวจสอบได้หากกระบวนการถูกขัดจังหวะ ให้เขียนผลรวมของแต่ละส่วนลงในไฟล์ Parquet หรือ CSV หลังจากประมวลผลครบทุก ๆ N ส่วน หากงานล้มเหลวที่ส่วนที่ 800 จากทั้งหมด 1,000 ส่วน คุณสามารถโหลดผลรวมที่บันทึกไว้แล้วทำงานต่อจากจุดที่ค้างอยู่ได้ แทนที่จะต้องประมวลผลทั้งไฟล์ใหม่ รูปแบบการรองรับความเสียหายนี้มีความสำคัญอย่างยิ่งในกระบวนการประมวลผลข้อมูลสำหรับใช้งานจริง
import pandas as pd
import os
CHECKPOINT = 'checkpoint.csv'
running_total = 0.0
running_count = 0
# Resume from checkpoint if it exists
if os.path.exists(CHECKPOINT):
ckpt = pd.read_csv(CHECKPOINT)
running_total = ckpt['total'].iloc[0]
running_count = int(ckpt['count'].iloc[0])
print(f'Resuming from checkpoint: {running_count:,} rows')
for chunk in pd.read_csv('huge.csv', chunksize=100000):
running_total += chunk['value'].sum()
running_count += len(chunk)
# Save checkpoint
pd.DataFrame({'total': [running_total],
'count': [running_count]}).to_csv(CHECKPOINT, index=False)
print(f'Final mean: {running_total / running_count:.4f}')ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจแนวคิดการวิเคราะห์ข้อมูลจากบทเรียนนี้
ทบทวนบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า ตัวสะสมที่ทำงานต่อเนื่อง (sum, count, min/max, ชุดข้อมูลความถี่) ช่วยให้รวมข้อมูลจากไฟล์ขนาดใหญ่โดยใช้หน่วยความจำคงที่ได้, การ groupby สองขั้นตอน (ทำ groupby บางส่วนในแต่ละส่วน แล้วต่อข้อมูลและจัดกลุ่มใหม่) ช่วยจัดการกลุ่มที่กระจายอยู่ข้ามส่วนได้อย่างถูกต้อง และการกรองข้อมูลตั้งแต่เนิ่น ๆภายในแต่ละส่วนช่วยลดต้นทุนของขั้นตอนการสะสมข้อมูล ต่อไปเราจะสำรวจ Dask DataFrames ซึ่งเป็นทางเลือกแบบขนานที่ใช้แทน Pandas ได้โดยแทบไม่ต้องปรับเปลี่ยนโค้ด สำหรับชุดข้อมูลขนาดใหญ่
คำถามที่พบบ่อย
บทเรียน “การรวมค่าแบบเพิ่มทีละส่วนระหว่างชิ้นข้อมูล” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การรวมค่าแบบเพิ่มทีละส่วนระหว่างชิ้นข้อมูล” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Pandas & NumPy Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การรวมค่าแบบเพิ่มทีละส่วนระหว่างชิ้นข้อมูล”
สะสมจำนวน ผลรวม และค่าต่ำสุด/สูงสุดที่คำนวณต่อเนื่องระหว่างชิ้นข้อมูล โดยไม่เก็บไฟล์ทั้งหมดไว้ในหน่วยความจำ คุณปฏิบัติ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การสตรีม CSV ด้วย chunksize
- การรวมค่าแบบเพิ่มทีละส่วนระหว่างชิ้นข้อมูล
- บทนำสู่ Dask DataFrames
- Parquet: การจัดเก็บข้อมูลแบบคอลัมน์ความเร็วสูง