در این فصل چه یاد میگیری#
فصلِ قبل دیدی که np_array * 2 بدونِ هیچ حلقهای کلِ آرایه را دو برابر کرد. این یک ترفندِ سرعتی نیست؛ یک روشِ فکرکردن است. در این فصل یاد میگیری بهجای «برای هر عنصر، این کار را بکن» بنویسی «این کار را روی همه بکن» — و مهمتر از آن، با ماسکِ شرطی فقط عنصرهایی را جدا کنی که شرطی را دارند. این تنها مهارتی است که در کلِ ترمِ ۲ و ۳ بیشترین بار را میکشد؛ اگر یک فصل را باید دو بار بخوانی، این است.

آخر این فصل میتوانی:
- روی کلِ یک آرایه عملیات ریاضی و مقایسهای انجام بدهی
- قاعدهٔ
broadcastingرا بگویی و پیشبینی کنی کِی کار میکند - با ماسکِ شرطی زیرمجموعهای از داده را جدا و بشماری
- با
np.whereبر اساسِ شرط مقدارِ تازه بسازی - با
axisروی ردیف یا ستونِ یک جدول تجمیع کنی
قبل از شروع#
از فصل ۱: np.array، shape، dtype، و برشِ دوبعدی با arr[:, 0].
از ترمِ ۱ فصل ۵: عملگرهای مقایسهای و and/or — که اینجا شکلِ تازهای پیدا میکنند.
📓 نوتبوک: نوتبوک این فصل را در Colab باز کن — همهٔ کدهای این فصل آماده و بهترتیب داخلش هست.
۱. عملیات روی کلِ آرایه#
import numpy as np
prices = np.array([850000, 1200000, 430000, 2100000, 650000])
print(prices * 2)
print(prices + 50000)
print(prices / 1000)
print(prices - prices.mean())
[1700000 2400000 860000 4200000 1300000]
[ 900000 1250000 480000 2150000 700000]
[ 850. 1200. 430. 2100. 650.]
[-196000. 154000. -616000. 1054000. -396000.]
هر عملیات عنصربهعنصر روی همهٔ آرایه اجرا شد. این را vectorization میگویند: بهجای گفتنِ «چطور»، فقط میگویی «چه».
خطِ آخر جالبترین است: prices - prices.mean() فاصلهٔ هر قیمت از میانگین را داد. عددِ منفی یعنی ارزانتر از میانگین، مثبت یعنی گرانتر. همین یک خط، هستهٔ کاری است که در فصلِ ۷ ترمِ ۳ با نامِ نرمالسازی میبینی.
🌱 ریشهاش کجاست: «فاصله از میانگین» شهودِ پشتِ انحرافِ معیار است — عددی که میگوید دادهها بهطورِ متوسط چقدر از مرکز دورند. اگر میخواهی بدانی چرا این عدد اینطور تعریف شده و چرا مربع میشود، ریشه، ترم ۶ فصل ۶ — میانگین، میانه، پراکندگی دقیقاً همین را میسازد.
۲. broadcasting: وقتی شکلها یکی نیستند#
در بخشِ قبل prices + 50000 کار کرد، هرچند prices پنج عنصر داشت و 50000 یک عدد بود. numpy عددِ تکی را روی همهٔ عنصرها پخش کرد. این قاعده اسم دارد: broadcasting.
table = np.array([
[10, 20, 30],
[40, 50, 60],
])
column_factor = np.array([1, 2, 3])
print(table * 2)
print(table * column_factor)
print(table.shape, column_factor.shape)
[[ 20 40 60]
[ 80 100 120]]
[[ 10 40 90]
[ 40 100 180]]
(2, 3) (3,)
آرایهٔ (2, 3) با آرایهٔ (3,) جمع شد، چون آخرین بُعدشان میخواند: هر دو سه ستون دارند، پس column_factor روی هر ردیف تکرار شد.
قاعده در یک جمله: دو آرایه با هم سازگارند اگر برای هر بُعد، اندازهشان یا برابر باشد یا یکیشان ۱ باشد — و ابعاد از راست به هم تطبیق داده میشوند.
برای همین در فصلِ قبل (3,) و (4,) خطا داد: نه برابرند و نه هیچکدام ۱ است.
قبل از ادامه، جواب بده: آرایهای (100, 3) داری و میخواهی هر ردیف را در عددِ متفاوتی ضرب کنی. آرایهٔ ضریبها با shape برابرِ (100,) کار میکند؟ جواب: نه. تطبیق از راست است، پس (100,) با آخرین بُعد یعنی 3 مقایسه میشود و نمیخواند. باید شکلش را به (100, 1) تبدیل کنی — با reshape(-1, 1). متدِ reshape شکلِ تازه را میگیرد و همان عنصرها را در آن قالب میریزد، و آن -1 یعنی «این بُعد را خودت حساب کن»: میگویی یک ستون میخواهم، numpy خودش میفهمد که پس ۱۰۰ ردیف لازم است. این دقیقاً همان جایی است که در بلوکِ 🔧 فصلِ قبل هشدار دادیم.
۳. ماسکِ شرطی: مهمترین بخشِ این فصل#
عملگرهای مقایسه هم برداریاند و نتیجهشان آرایهای از True و False است:
print(prices > 800000)
print((prices > 800000).sum())
print((prices > 800000).mean())
[ True True False True False]
3
0.6
به آن آرایهٔ True/False میگویند ماسک (mask). دو ترفندِ بسیار پرکاربرد رویش:
.sum()روی ماسک تعدادِTrueها را میدهد، چونTrueمثلِ ۱ وFalseمثلِ ۰ جمع میشود..mean()روی ماسک نسبتشان را میدهد — اینجا ۰٫۶ یعنی شصت درصدِ قیمتها بالای ۸۰۰ هزارند.
این دو خط، پرکاربردترین ابزارِ «داده را ببین» در کلِ دورهاند.
و حالا کارِ اصلی: ماسک را داخلِ کروشه بگذار تا فقط همان عنصرها را بگیری.
expensive = prices[prices > 800000]
print(expensive)
print(f"تعداد: {len(expensive)}")
print(f"میانگینِ گرانها: {expensive.mean()}")
[ 850000 1200000 2100000]
تعداد: 3
میانگینِ گرانها: 1383333.3333333333
prices[prices > 800000] را بلند بخوان: «از prices، آنهایی که بزرگتر از هشتصدهزارند». همین. هیچ حلقهای، هیچ appendی.
✅ چک کن: سه عدد باید برگردند و هر سه واقعاً بالای ۸۰۰٬۰۰۰ باشند. اگر پنج عدد گرفتی، احتمالاً پرانتز را جا انداختهای و کلِ آرایه برگشته.
ترکیبِ چند شرط هم میشود، ولی با نمادِ دیگری:
mid_range = prices[(prices > 500000) & (prices < 1500000)]
print(mid_range)
not_cheap = prices[~(prices < 500000)]
print(not_cheap)
[ 850000 1200000 650000]
[ 850000 1200000 2100000 650000]
⚠️ مواظب باش: اینجا
&و|و~بهکار میروند، نهandوorوnot. دلیلش این است کهandمیخواهد کلِ آرایه را یکTrueیاFalseواحد ببیند و نمیتواند، پس خطا میدهد:ValueError: The truth value of an array with more than one element is ambiguous. و پرانتزها اجباریاند — چون&تقدمِ بالاتری از>دارد و بدونِ پرانتز، پایتون اول اشتباهی عددها را با هم&میکند.
۴. np.where: بر اساسِ شرط، مقدار بساز#
ماسک عنصرها را جدا میکند. گاهی نمیخواهی جدا کنی — میخواهی برچسب بزنی:
labels = np.where(prices > 800000, "گران", "ارزان")
capped = np.where(prices > 1000000, 1000000, prices)
print(labels)
print(capped)
['گران' 'گران' 'ارزان' 'گران' 'ارزان']
[ 850000 1000000 430000 1000000 650000]
np.where(شرط، اگر درست، اگر نادرست) را میشود «ifِ برداری» خواند. مثالِ دوم یک کارِ خیلی رایج است: سقف گذاشتن روی مقدارهای خیلی بزرگ.
۵. axis: تجمیع روی ردیف یا ستون#
روی جدول، تجمیع یک سؤالِ اضافه دارد: در چه جهتی؟
sales = np.array([
[12, 15, 9],
[7, 22, 14],
[30, 4, 11],
[18, 19, 25],
])
print("مجموع کل:", sales.sum())
print("مجموع هر ستون:", sales.sum(axis=0))
print("مجموع هر ردیف:", sales.sum(axis=1))
print("میانگین هر ستون:", sales.mean(axis=0))
print("بیشینهٔ هر ردیف:", sales.max(axis=1))
مجموع کل: 186
مجموع هر ستون: [67 60 59]
مجموع هر ردیف: [36 43 45 62]
میانگین هر ستون: [16.75 15. 14.75]
بیشینهٔ هر ردیف: [15 22 30 25]
قاعدهٔ axis را همه یک بار اشتباه میفهمند، پس اینطور بهخاطر بسپار: axis بُعدی است که از بین میرود.
sales شکلش (4, 3) است. sum(axis=0) بُعدِ صفر (ردیفها) را جمع میکند و از بین میبرد، پس نتیجه (3,) میشود — یک عدد برای هر ستون. و axis=1 ستونها را از بین میبرد و یک عدد برای هر ردیف میدهد.
اگر شک کردی، shape نتیجه را چاپ کن؛ همیشه جوابِ قطعی میدهد.
📏 اندازه بگیر: «میانگینِ هر ستون» را نگاه کن:
[16.75, 15.0, 14.75]. سه عدد خیلی نزدیک به هم. حالا بهsum(axis=1)نگاه کن:[36, 43, 45, 62]— ردیفِ آخر تقریباً دو برابرِ ردیفِ اول است. یک تجمیع میتواند تفاوتِ واقعی را کاملاً پنهان کند. قبل از اینکه از روی میانگین نتیجه بگیری، همیشه بپرس: میانگینِ چه چیزی، در کدام جهت، و آیا پراکندگیاش را هم دیدهام؟ فصلِ ۸ همین ترم دقیقاً به این میپردازد.
۶. یک خطای واقعی: and روی آرایه#
print(prices[(prices > 500000) and (prices < 1500000)])
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
پیام دقیقاً همان چیزی را میگوید که در بلوکِ ⚠️ بخشِ ۳ خواندی: پایتون میخواهد and را روی یک True/False واحد اجرا کند، ولی طرفینش آرایهاند و «درست بودنِ» یک آرایهٔ پنجعنصری معنا ندارد.
🔧 اگر کار نکرد: هر وقت این پیام را دیدی، دنبالِ
and،orیاnotبگرد که روی آرایه یا ستون بهکار رفته باشد و به&،|،~تبدیلش کن — و پرانتزها را فراموش نکن. این پیام را در فصلِ بعد رویpandasهم میبینی، با همان علت و همان راهِ حل.
🤖 از دستیارت بپرس: «قاعدهٔ broadcasting در numpy را با سه مثال توضیح بده که یکیشان کار نکند، و بگو چرا.» جوابش را با قاعدهٔ بخشِ ۲ بسنج، و هر سه مثال را خودت اجرا کن. مثالِ خراب مهمترینشان است: اگر دستیار مثالی داد که برخلافِ ادعایش کار کرد، همانجا یاد میگیری که خروجی را باید امتحان کرد.
واژههای تازهٔ این فصل#
| کلمه | تلفظ به حروف فارسی | یعنی چه |
|---|---|---|
| vectorization | وکتورایزیشِن | اجرای یک عملیات روی کلِ آرایه، بدونِ حلقه |
| broadcasting | برادکستینگ | قاعدهٔ تطبیقِ شکلها هنگامِ عملیات بینِ دو آرایه |
| mask | ماسک | آرایهای از True/False که برای فیلترکردن بهکار میرود |
| axis | اَکسیس | جهتِ تجمیع؛ همان بُعدی که از بین میرود |
تمرینها
اول خودت فکر کن یا امتحان کن — بعد اینجا را باز کن.
در فصل بعد#
آرایه برای عددِ خالص عالی است، ولی دادهٔ واقعی فقط عدد نیست: ستونِ نام دارد، ستونِ شهر دارد، خانهٔ خالی دارد، و مهمتر از همه ستونهایش اسم دارند، نه شماره. فصلِ بعد pandas را میآورد و DataFrame را — جدولی که هر ستونش نام و نوعِ خودش را دارد. و از همان فصل، دیگر با دادهٔ ساختگیِ چهارخطی کار نمیکنی: یک فایلِ واقعی با ۲۴۴ ردیف و همهٔ کثیفیهای دنیای واقعی.
به آخر این فصل رسیدی!
اگر ساختی و جواب داد، این دکمه مال توست.