CSV كبير بيكسر RAM؟ chunksize في pandas يحلها بهدوء
لو سكربت Python بيقع كل ما تقرأ ملف CSV كبير، هتعرف هنا طريقة تخفض Peak RAM من حوالي 7.8GB إلى أقل من 1.3GB بدون تغيير كامل في البايبلاين.
مستوى القارئ: متوسط
المشكلة باختصار
الطريقة الشائعة هي إنك تعمل pd.read_csv("events.csv") وخلاص. الطريقة دي بتفشل لما حجم الملف يقرب من RAM المتاحة، لأن pandas لا يقرأ النص الخام فقط. هو يحوّل الأعمدة لأنواع بيانات، يبني index، ويتعامل مع missing values. فملف 8GB ممكن يستهلك 12GB أو أكثر أثناء التحويل.
الافتراض إن عندك Job يومي بيقرأ events أو orders من نظام خارجي، وحجم الملف بين 2GB و10GB. لو عندك موقع بـ 50K زائر في اليوم، ملف الأحداث الشهري ممكن يكبر بسرعة، وساعتها المشكلة مش في سرعة CPU فقط. المشكلة إن الذاكرة بتنفد قبل ما الحساب يبدأ أصلاً.
مثال بسيط قبل التعريف العلمي
ركز في المثال ده: بدل ما تنقل 1000 صندوق مرة واحدة وتكسر العربية، انقل 50 صندوق في كل مشوار. هتعمل مشاوير أكثر، لكن العربية مش هتقف. ده بالظبط اللي بيعمله chunksize.
علميًا، pandas.read_csv(..., chunksize=N) لا يرجع DataFrame واحد. بيرجع iterator يطلع DataFrame صغير في كل مرة. كل دفعة تتعالج، تتجمع نتيجتها، وبعدها تسيب الذاكرة للدفعة التالية. المكسب: Peak RAM أقل بكثير. التكلفة: الكود أطول، وبعض العمليات اللي تحتاج الملف كله مرة واحدة لازم تتعاد صياغتها.
الحل العملي: عالج الملف على دفعات
المثال التالي يحسب إجمالي المبيعات لكل دولة من ملف كبير، بدون تحميل الملف كله في الذاكرة. استخدمه كبداية، وبعدها بدّل أسماء الأعمدة حسب ملفك.
import pandas as pd
input_path = "orders.csv"
output_path = "sales_by_country.csv"
partial_results = []
for chunk in pd.read_csv(
input_path,
chunksize=100_000,
usecols=["country", "total", "status"],
dtype={"country": "category", "total": "float64", "status": "category"},
):
paid = chunk[chunk["status"] == "paid"]
summary = paid.groupby("country", observed=True)["total"].sum()
partial_results.append(summary)
final = pd.concat(partial_results, axis=1).fillna(0).sum(axis=1)
final.sort_values(ascending=False).to_csv(output_path, header=["total_sales"])
print(f"saved: {output_path}")لو جرّبت ده على ملف 8GB، التوقع الواقعي إن الذاكرة القصوى تبقى بين 900MB و1.3GB مع chunksize=100_000. في المقابل، زمن التشغيل ممكن يزيد من 14 دقيقة إلى 16 أو 18 دقيقة. الـ trade-off هنا واضح: بتكسب استقرار وRAM أقل، وبتخسر شوية زمن وكود أبسط.