NumPy کتابخانه‌ای برای محاسبهٔ عددی با آرایه‌های چندبعدی در پایتون است. اگر دادهٔ عددی را با فهرست‌های تو‌در‌تو نگه می‌دارید و برای هر عملیات حلقه می‌نویسید، آرایه می‌تواند کد را روشن‌تر و بسیاری از محاسبات را سریع‌تر کند. اما سرعت تنها مزیت نیست؛ شکل، نوع داده و محور، قراردادهایی فراهم می‌کنند که با شناخت آن‌ها می‌توان خطاهای تحلیلی را زودتر پیدا کرد.

این آموزش بر یک جدول کوچک فروش تمرکز دارد: سطرها روز و ستون‌ها محصول هستند. می‌خواهیم مجموع فروش، میانگین هر محصول و دادهٔ استانداردشده را محاسبه کنیم. هم‌زمان بررسی می‌کنیم که چرا یک عبارت درست از نظر نحوی ممکن است نتیجهٔ اشتباه بسازد. مهم‌ترین مهارت NumPy حفظ نام توابع نیست؛ پیش‌بینی شکل خروجی و توضیح معنای آن است.

آرایه با فهرست پایتون چه تفاوتی دارد؟

فهرست عمومی پایتون می‌تواند عضوهایی با نوع‌های گوناگون داشته باشد. آرایهٔ عددی NumPy معمولاً داده‌ها را با یک dtype مشخص نگه می‌دارد؛ مثلاً عدد صحیح یا اعشاری. این نمایش امکان استفاده از عملیات بهینه را فراهم می‌کند. البته نوع object نیز وجود دارد، اما بسیاری از مزیت‌های محاسبهٔ عددی همگن را ندارد و نباید صرفاً برای کنار هم گذاشتن هر چیزی انتخاب شود.

در فهرست، عمل جمع ممکن است دو دنباله را به هم بچسباند، اما در آرایهٔ عددی جمع معمولاً عضو‌به‌عضو است. این تفاوت ساده یکی از نخستین چیزهایی است که باید آزمایش کنید. همچنین تبدیل رشته و عدد به آرایه ممکن است dtype ناخواسته ایجاد کند. پیش از تحلیل، فقط چند مقدار را چاپ نکنید؛ شکل و نوع آرایه را نیز ببینید تا دادهٔ عددی واقعاً عدد باشد.

shape، ndim و size را از هم جدا کنید

shape اندازهٔ هر بعد را نشان می‌دهد. ndim تعداد بعدها و size تعداد کل عضوهاست. یک آرایه با شکل سه در چهار، دو بعد و دوازده عضو دارد. آرایهٔ یک‌بعدی با چهار عضو با ماتریس یک در چهار یکسان نیست، حتی اگر روی صفحه شبیه دیده شود. این تفاوت روی ضرب ماتریسی، اتصال آرایه‌ها و Broadcasting اثر می‌گذارد.

به هر بعد یک معنا بدهید. در جدول فروش، محور صفر روزها و محور یک محصولات است. اگر همین آرایه در جایی برعکس شود، نام محور هم باید با معنای جدید تفسیر شود. نوشتن شکل موردانتظار کنار طرح مسئله، پیش از کد، جلوی بسیاری از خطاها را می‌گیرد. پیام shape mismatch مزاحمت کتابخانه نیست؛ نشانه‌ای است که قرارداد ابعاد نیاز به بازبینی دارد.

import numpy as np
sales = np.array([[10, 20, 30], [15, 25, 35]], dtype=float)
assert sales.shape == (2, 3)
assert sales.ndim == 2
assert sales.size == 6

dtype و خطرهای محاسبهٔ عددی

نوع داده روی حافظه، دامنهٔ مقدار و رفتار محاسبه اثر دارد. عدد صحیح با اندازهٔ محدود می‌تواند سرریز کند و محاسبهٔ اعشاری نیز همیشه نمایش دقیق عدد ده‌دهی نیست. انتخاب نوع کوچک‌تر فقط وقتی خوب است که دامنه و دقت لازم را بدانید. کاهش حافظه بدون بررسی صحت، ممکن است نتیجهٔ مدل یا گزارش مالی را تغییر دهد.

برای دادهٔ گمشده، NaN در آرایهٔ اعشاری رایج است. NaN با صفر فرق دارد و مقایسهٔ عادی با خودش نیز رفتار معمول عددها را ندارد؛ برای تشخیص از np.isnan استفاده کنید. تابع mean روی آرایهٔ دارای NaN معمولاً NaN می‌دهد، در حالی که nanmean آن‌ها را نادیده می‌گیرد. انتخاب دومی باید تصمیمی مستند باشد، نه راهی برای ناپدیدکردن مسئلهٔ دادهٔ ناقص.

اندیس‌گذاری و برش با مثال قابل‌فهم

اندیس صفر به نخستین عضو اشاره می‌کند. در آرایهٔ دوبعدی، sales[0, 1] یعنی روز اول و محصول دوم. برش انتهای باز دارد؛ بازهٔ 0:2 عضوهای صفر و یک را می‌گیرد. بهتر است در آغاز چند مثال کوچک را دستی حساب کنید. وقتی چند محور و بازه در یک عبارت جمع شوند، حدس از روی ظاهر عددها به‌راحتی اشتباه می‌شود.

ماسک بولی برای انتخاب بر اساس شرط مفید است. مثلاً sales > 20 آرایه‌ای از درست و نادرست می‌سازد. اگر آن را مستقیم برای انتخاب استفاده کنید، خروجی ممکن است یک‌بعدی شود؛ این همان جدول اولیه با چند خانهٔ خالی نیست. قبل از ادامه، shape خروجی را ببینید و مشخص کنید می‌خواهید خانه‌ها را انتخاب کنید یا سطرهای دارای یک ویژگی خاص را.

محور تجمیع را درست تفسیر کنید

وقتی sum(axis=0) می‌نویسید، محاسبه در امتداد محور روزها انجام می‌شود و برای هر محصول یک مجموع باقی می‌ماند. sum(axis=1) برای هر روز مجموع محصول‌ها را می‌دهد. عبارت «جمع روی ستون» گاهی بین افراد مبهم است؛ بهتر است بگویید کدام بعد حذف می‌شود و خروجی چه معنایی دارد. این توصیف در آرایه‌های سه‌بعدی هم قابل‌استفاده است.

product_totals = sales.sum(axis=0)
daily_totals = sales.sum(axis=1)
assert np.array_equal(product_totals, [25, 45, 65])
assert np.array_equal(daily_totals, [60, 75])

اگر به حفظ بعد برای عملیات بعدی نیاز دارید، keepdims مفید است. میانگین با شکل یک در تعداد محصولات راحت‌تر با جدول روزها ترکیب می‌شود. البته حفظ بعد جای فهم مسئله را نمی‌گیرد. آرایه‌ای که به‌طور اتفاقی قابل‌پخش است ممکن است بدون هیچ خطایی اجرا شود ولی میانگین را از محور اشتباه کم کند. آزمون با مقدارهای نامتقارن، خطا را بهتر از دادهٔ همه‌یکسان آشکار می‌کند.

Broadcasting چگونه کار می‌کند؟

Broadcasting امکان انجام عملیات میان بعضی آرایه‌های با شکل متفاوت را فراهم می‌کند، بدون اینکه لازم باشد نسخه‌های تکراری را دستی بسازید. قاعدهٔ اصلی از سمت راست شکل‌ها بررسی می‌شود: هر جفت بعد باید برابر باشد یا یکی از آن‌ها اندازهٔ یک داشته باشد. بعدهای غایب مانند اندازهٔ یک در نظر گرفته می‌شوند. اگر این شرط برقرار نباشد، عملیات سازگار نیست.

برای جدول دو در سه، یک بردار سه‌عضوی می‌تواند به هر سطر اضافه شود. اما بردار دو‌عضوی مستقیماً با آن سازگار نیست. اگر هدفتان افزودن یک مقدار به هر روز است، آن بردار باید شکل دو در یک بگیرد. مهم است این تغییر شکل از معنای داده بیاید، نه صرفاً از تلاش برای خاموش‌کردن خطا. هر reshape باید پاسخی به پرسش «این بعد چه معنایی دارد؟» داشته باشد.

استانداردسازی بدون نشت داده

برای استانداردسازی ویژگی‌ها، میانگین هر ستون را کم و بر انحراف معیار همان ستون تقسیم می‌کنیم. در پروژهٔ یادگیری ماشین، این آمار فقط از دادهٔ آموزش به دست می‌آید. آزمون و ورودی‌های آینده باید با همان مقدارهای ذخیره‌شده تبدیل شوند. محاسبهٔ میانگین روی کل داده، اطلاعات آزمون را وارد مرحلهٔ آماده‌سازی می‌کند و ارزیابی را خوش‌بینانه می‌سازد.

mean = sales.mean(axis=0, keepdims=True)
std = sales.std(axis=0, keepdims=True)
safe_std = np.where(std == 0, 1, std)
scaled = (sales - mean) / safe_std
assert scaled.shape == sales.shape
assert np.allclose(scaled.mean(axis=0), 0)

این مثال فقط رفتار عددی را روی جدول آموزشی نشان می‌دهد. در یک فرایند واقعی، استفاده از Pipeline معمولاً مدیریت این قرارداد را امن‌تر می‌کند. برای ستون ثابت باید سیاست روشن داشته باشید؛ تقسیم بر یک، حذف ویژگی یا نگه‌داشتن آن می‌توانند انتخاب‌های متفاوتی باشند. تصمیم را با توجه به مدل و معنای ستون بگیرید و در آزمون، حالت ثابت را جدا بررسی کنید.

کپی و نما؛ چرا تغییر یک برش خطرناک است؟

بعضی برش‌های ساده، نمایی از همان حافظهٔ آرایهٔ اصلی هستند. در نتیجه تغییر برش می‌تواند دادهٔ اولیه را هم تغییر دهد. این رفتار برای کارایی مفید است، اما اگر انتظار کپی مستقل داشته باشید غافلگیرکننده خواهد بود. در مقابل، بعضی شیوه‌های اندیس‌گذاری پیشرفته کپی می‌سازند. بهتر است به جای تعمیم یک قانون ساده به همهٔ حالت‌ها، رفتار عملیات را بشناسید.

وقتی لازم است دادهٔ خام حفظ شود، صریحاً copy بگیرید و هزینهٔ حافظه را هم در نظر داشته باشید. در آزمون‌ها پس از تبدیل، چند مقدار آرایهٔ اصلی را کنترل کنید. اشتباه ناشی از تغییر ناخواسته معمولاً دیر آشکار می‌شود؛ چون یک بخش برنامه داده را عوض می‌کند و بخش دیگری نتیجهٔ نامعمول می‌بیند. مستندسازی مالکیت و تغییرپذیری داده در طراحی، از اشکال‌زدایی پراکنده بهتر است.

ضرب عضو‌به‌عضو با ضرب ماتریسی فرق دارد

عملگر ستاره معمولاً ضرب عضو‌به‌عضو انجام می‌دهد، در حالی که @ برای ضرب ماتریسی استفاده می‌شود. در ضرب ماتریسی، بعدهای داخلی باید سازگار باشند. اگر جدول نمونه‌ها شکل n در p و وزن‌ها شکل p داشته باشند، حاصل می‌تواند پیش‌بینی n نمونه باشد. این رابطه همان محاسبهٔ مدل خطی است که با زبان آرایه بیان شده است.

خروجی درست از نظر شکل نیز الزاماً از نظر معنا درست نیست. ترتیب ستون‌ها باید با ترتیب وزن‌ها هماهنگ باشد. در دادهٔ واقعی، نام ویژگی‌ها را در کنار آرایه نگه دارید یا پیش از تبدیل از جدول، ترتیب ستون را صریح تعیین کنید. از دست رفتن نام ستون هنگام تبدیل به آرایه یکی از دلایلی است که کد بدون خطا اجرا می‌شود ولی پیش‌بینی‌هایش با انتظار سازگار نیست.

کارایی را اندازه بگیرید، حدس نزنید

برداری‌سازی اغلب هزینهٔ حلقهٔ پایتون را کم می‌کند، اما هر عبارت برداری حافظهٔ کمی مصرف نمی‌کند. Broadcasting ممکن است در محاسبهٔ فاصلهٔ همهٔ جفت‌ها خروجی بسیار بزرگی بسازد. پیش از عملیات، تعداد عضوهای خروجی و اندازهٔ dtype را تخمین بزنید. برای دادهٔ بزرگ شاید پردازش بلوکی یا الگوریتم متفاوت از ساختن یک ماتریس عظیم مناسب‌تر باشد.

زمان‌سنجی را روی نمونه‌ای نماینده انجام دهید و هزینهٔ تبدیل داده را هم حساب کنید. اگر یک عملیات فقط یک بار روی ده عدد اجرا می‌شود، پیچیده‌کردن برنامه برای چند میکروثانیه ارزش چندانی ندارد. خوانایی، صحت و مصرف حافظه را کنار زمان اجرا ببینید. بهینه‌سازی پس از شناسایی گلوگاه واقعی معنا دارد، نه با جایگزین‌کردن خودکار هر حلقه‌ای با عبارتی دشوار.

تمرین تشخیص شکل قبل از اجرا

سه آرایه با شکل‌های چهار در سه، سه و چهار در یک را تصور کنید. جمع آرایهٔ نخست با آرایهٔ دوم باید به هر سطر یک بردار سه‌عضوی اضافه کند. جمع آن با آرایهٔ سوم، برای هر سطر یک مقدار متفاوت اضافه می‌کند. هر دو خروجی شکل چهار در سه دارند، اما معنای عملیات متفاوت است. همین مثال نشان می‌دهد بررسی شکل لازم است ولی برای اثبات معنای درست کافی نیست.

پیش از اجرا، خروجی یک خانه را دستی حساب کنید. سپس با عددهایی نامتقارن آزمون بنویسید تا جابه‌جایی محور پنهان نماند. اگر همهٔ مقدارها یک یا صفر باشند، بسیاری از اشتباه‌ها دیده نمی‌شوند. دادهٔ آزمایشی باید عمداً تفاوت میان دو برداشت را آشکار کند. انتخاب خوب نمونهٔ آزمون، بخش مهمی از مهارت عددی است و گاهی از افزودن چندین بررسی عمومی مؤثرتر عمل می‌کند.

حالت آرایهٔ خالی و یک‌نمونه‌ای را نیز جدا بررسی کنید. میانگین روی مجموعهٔ خالی یا انحراف معیار در تعداد کم، نیاز به سیاست روشن دارد. قرار نیست برای هر برنامه ده‌ها حالت ناممکن بسازید، اما اگر ورودی از فایل یا کاربر می‌آید، اندازهٔ واقعی تضمین‌شده نیست. در مرز ورودی قرارداد را بررسی و در محاسبهٔ داخلی به قرارداد معتبر تکیه کنید؛ این تقسیم مسئولیت، کد را هم امن‌تر و هم خواناتر نگه می‌دارد.

در پایان، نتیجه را به واحد اصلی مسئله برگردانید. آرایهٔ استانداردشده دیگر واحد فروش ندارد و جمع آن معنای جمع درآمد را نمی‌دهد. تغییر نمایش عددی می‌تواند برای مدل مفید باشد، اما تفسیر تجاری باید از داده و تبدیل درست بیاید. جدا نگه‌داشتن دادهٔ خام، دادهٔ تبدیل‌شده و خروجی گزارش کمک می‌کند این سه معنا در مراحل بعد با هم مخلوط نشوند.

تمرین کاربردی و پرسش‌های متداول

جدولی با چهار روز و سه محصول بسازید، یک خانه را NaN و یک ستون را ثابت قرار دهید. مجموع روزانه، میانگین محصول و ماسک روزهای پرفروش را محاسبه کنید. سپس بررسی کنید حذف دادهٔ خالی چه اثری بر تعداد نمونه دارد. خروجی را با محاسبهٔ دستی دو سطر کنترل کنید. این تمرین کوچک بیشتر از اجرای بی‌فکر یک مثال بزرگ، فهم محور و نوع را نشان می‌دهد.

آیا NumPy همیشه از فهرست سریع‌تر است؟

نه. مزیت به اندازهٔ داده، نوع عملیات و هزینهٔ تبدیل وابسته است. آرایهٔ object یا ساخت مکرر آرایه در حلقه می‌تواند نتیجهٔ متفاوتی داشته باشد. برای محاسبهٔ عددی گروهی انتخاب مناسبی است، اما برای دادهٔ ناهمگون یا عملیات عمومی پایتون ممکن است فهرست ساده‌تر باشد. ابزار را با مسئله انتخاب کنید و ادعای سرعت را اندازه بگیرید.

چرا reshape خطا می‌دهد؟

تعداد عضوها باید با شکل تازه سازگار باشد. تغییر شکل، دادهٔ تازه تولید نمی‌کند و کمبود عضو را پر نمی‌کند. حتی وقتی reshape موفق است، ترتیب و معنای بعدها را کنترل کنید. اگر فقط برای اجرای کد، چند شکل را تصادفی امتحان کنید، احتمال تولید خروجی ظاهراً معتبر ولی تحلیلی نادرست بالا می‌رود.

بعد از NumPy چه چیزی یاد بگیریم؟

برای دادهٔ جدولی، Pandas قدم طبیعی بعدی است؛ نام ستون، نوع داده و عملیات اتصال را بهتر مدیریت می‌کند. برای مدل‌سازی، مقالهٔ ارزیابی مدل کمک می‌کند تبدیل‌های عددی را در مرز آموزش و آزمون درست به کار ببرید. این دو مسیر مکمل‌اند: یکی کیفیت آماده‌سازی را بالا می‌برد و دیگری از ادعای نادرست دربارهٔ خروجی جلوگیری می‌کند.

منابع و مطالعهٔ بیشتر

برای بررسی جزئیات و ادامهٔ مطالعه؛ متن این راهنما مستقلاً برای نوونتیکس نوشته شده است.