کتابخانه NumPy پایتون – راهنمای جامع – بخش اول


NumPy یک کتابخانه برای زبان برنامه نویسی پایتون (Python) است. با استفاده از این کتابخانه امکان استفاده از آرایهها و ماتریسهای بزرگ چند بعدی فراهم میشود. همچنین میتوان از تابعهای ریاضیاتی سطح بالا بر روی این آرایهها استفاده کرد. پیش از اینکه این آموزش را مطالعه کنید، میبایست دستکم اندکی با زبان برنامهنویسی پایتون آشنایی داشته باشید. همچنین اگر نیاز دارید معلوماتتان را در مورد پایتون یکبار یادآوری کنید، میتوانید از آموزش پایتون استفاده کنید.
همچنین اگر میخواهید بر روی نمونههای ارائه شده در این آموزش کار کنید، باید برخی نرمافزارها را روی رایانه خود نصب کنید. دستکم موارد زیر الزامی هستند.
این نرمافزارها هم مفید هستند.
- ipython یک پوسته (Shell) تعاملی بهبود یافته برای پایتون است که برای بررسی خصوصیات NumPy بسیار مناسب است.
- matplotlib به شما امکان رسم نمودار را میدهد.
- SciPy بسیاری از رویههای علمی را در خود دارد که بر روی NumPy عمل میکنند.
مفاهیم پایه
هدف اصلی NumPy فراهم ساختن امکان کار با آرایههای چندبعدی همگن است. این آرایهها جدولی از عناصر (معمولاً اعداد) هستند که همگی از یک نوع میباشند و با یک چندتایی، از اعداد صحیح مثبت اندیسگذاری میشوند. در NumPy ابعاد به نام محور (axe) شناخته میشوند. تعداد محورها رتبه (rank) نامیده میشود.
برای مثال، مختصات یک نقطه در فضای 3 بعدی [1, 2, 1] یک آرایه با رتبه 1 است زیرا یک محور دارد. این محور طولی بهاندازه 3 دارد. در مثال زیر آرایه رتبه 2 دارد (2 بعدی است). بعد (محور) نخست طولی به اندازه 2 دارد، بعد دوم طول 3 دارد.
[[ 1., 0., 0.], [ 0., 1., 2.]]
کلاس آرایه Numpy بهصورت ndarray نامگذاری شده است. همچنین بهصورت مستعار array نامیده میشود. توجه داشته باشید که numpy.array همان کلاس کتابخانه استاندارد پایتون به نام array.array نیست. کتابخانه استاندارد پایتون تنها آرایههای تکبعدی را مدیریت میکند و کاربردهای اندکی دارد. خصوصیات مهمتر یک ndarray بدین ترتیب هستند.
ndarray.ndim
تعداد محور (ابعاد) آرایه است. در دنیای پایتون تعداد ابعاد بهصورت رتبه نامیده میشود.
ndarray.shape
ابعاد یک آرایه است. این خصوصیت از یک چندتایی اعداد صحیح تشکیل یافته است که نشاندهنده اندازه هر بعد آرایه هستند. برای یک ماتریس با n ردیف و m ستون، شکل (shape) بهصورت (n,m) خواهد بود. بدین ترتیب طول چندتایی shape برابر با رتبه آرایه یا تعداد ابعاد ndim است.
ndarray.size
تعداد کل عناصر آرایه است. این مقدار برابر با حاصلضرب اجزای shape است.
ndarray.dtype
نوع عناصر یک آرایه را توصیف میکند. فرد میتواند dtype آرایه را با استفاده از انواع استاندارد پایتون ایجاد یا توصیف کند. بهعلاوه NumPy انواع مخصوص به خود را نیز دارد. برای مثال numpy.int32، numpy.int16 و numpy.float64 نمونههایی از انواع آرایه تعریف شده در NumPy هستند.
ndarray.itemsize
اندازه بایتهای هر یک از عناصر آرایه است. برای نمونه itemsize یک آرایه از عناصری با نوع float64 برابر با 8 (64/8) است در حالی که itemsize یک آرایه از نوع complex32 برابر با 4 (32/8) است. این مقدار معادل ndarray.dtype.itemsize است.
ndarray.data
این بافر (buffer) حاوی عناصر واقعی آرایه است. بهطورمعمول ما نیاز نداریم از این خصوصیت استفاده کنیم، زیرا با استفاده از امکان اندیسگذاری میتوانیم به عناصر آرایه دسترسی داشته باشیم.
مثال
>>> from numpy import * >>> a = arange(15).reshape(3, 5) >>> a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) >>> a.shape (3, 5) >>> a.ndim 2 >>> a.dtype.name 'int32' >>> a.itemsize 4 >>> a.size 15 >>> type(a) numpy.ndarray >>> b = array([6, 7, 8]) >>> b array([6, 7, 8]) >>> type(b) numpy.ndarray
ایجاد آرایه
چند روش برای ایجاد آرایه وجود دارند. برای مثال، میتوان با استفاده از تابع array یک آرایه را از فهرست معمولی پایتون یا چندتاییها ایجاد کرد. نوع آرایه حاصل، برابر با نوع عناصر موجود در دنبالههای تشکیل دهنده آن خواهد بود.
>>> from numpy import * >>> a = array( [2,3,4] ) >>> a array([2, 3, 4]) >>> a.dtype dtype('int32') >>> b = array([1.2, 3.5, 5.1]) >>> b.dtype dtype('float64')
یکی از خطاهای رایج در کار کردن با آرایههای چندبعدی زمانی رخ میدهد که قصد داریم array را با چند آرگومان عددی فراخوانی کنیم، در حالی که باید از فهرست منفردی از اعداد به عنوان آرگومان استفاده کنیم.
>>> a = array(1,2,3,4) # اشتباه >>> a = array([1,2,3,4]) # صحیح
array دنبالهای از دنبالهها را به آرایههای چندبعدی تبدیل میکند، دنبالهای از دنبالههای دنبالهها به آرایههای سهبعدی تبدیل میشود و همینطور تا آخر.
>>> b = array( [ (1.5,2,3), (4,5,6) ] ) >>> b array([[ 1.5, 2. , 3. ], [ 4. , 5. , 6. ]])
نوع آرایه را میتوان در زمان ایجاد آن به طور صریح تعیین کرد.
>>> c = array( [ [1,2], [3,4] ], dtype=complex ) >>> c array([[ 1.+0.j, 2.+0.j], [ 3.+0.j, 4.+0.j]])
معمولاً عناصر یک آرایه از ابتدا مشخص نیستند، اما اندازه آن مشخص است. از اینرو NumPy چند تابع برای ایجاد آرایه با جایگاههای ابتدایی مشخص پیشنهاد میکند. بدین ترتیب در ادامه نیازی به بسط آرایه که عملیات پرهزینهای است، وجود نخواهد داشت. تابع zeros یک آرایه با مقادیر تماماً صفر ایجاد میکند. تابع ones یک آرایه با مقادیر 1 تولید میکند و تابع empty یک آرایه ایجاد میکند که محتوای اولیه آن تصادفی است و به وضعیت حافظه بستگی دارد. به طور پیشفرض dtype آرایه ایجاد شده، برابر با float64 است.
>>> zeros( (3,4) ) array([[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]]) >>> ones( (2,3,4), dtype=int16 ) # را هم میتوان تعیین کرد dtype array([[[ 1, 1, 1, 1], [ 1, 1, 1, 1], [ 1, 1, 1, 1]], [[ 1, 1, 1, 1], [ 1, 1, 1, 1], [ 1, 1, 1, 1]]], dtype=int16) >>> empty( (2,3) ) array([[ 3.73603959e-262, 6.02658058e-154, 6.55490914e-260], [ 5.30498948e-313, 3.14673309e-307, 1.00000000e+000]])
NumPy برای ایجاد دنبالههایی از اعداد یک تابع مشابه range ارائه کرده است که بهجای لیست، یک آرایه برمیگرداند.
>>> arange( 10, 30, 5 ) array([10, 15, 20, 25]) >>> arange( 0, 2, 0.3 ) # آرگومانهای اعشاری میپذیرد array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8]
زمانی که arange با آرگومانهای اعشاری استفاده میشود، به دلیل دقت متناهی اعداد اعشاری، عموماً امکان پیشبینی تعداد عناصر به دست آمده وجود ندارد. به همین دلیل معمولاً استفاده از تابع linspace که تعداد عناصر مطلوب را نیز به عنوان یک آرگومان میگیرد، بهتر است:
پرینت کردن آرایهها
زمانی که یک آرایه را پرینت میکنید NumPy آن را به صوت یک فهرست تودرتو نمایش میدهد که طرح کلی آن بهصورت زیر است:
- آخرین محور از چپ به راست پرینت میشود.
- محور ماقبل آخر از بالا به پایین پرینت میشود.
- باقی محورها نیز از بالا به پایین پرینت و هرکدام با یک خط خالی از قبلی جدا میشوند.
بدین ترتیب آرایههای تکبعدی بهصورت ردیفی، آرایههای دوبعدی بهصورت ماتریس و آرایههای سهبعدی بهصورت فهرستی از ماتریسها پرینت میشوند.
اگر یک آرایه برای پرینت گرفتن بسیار بزرگ باشد، NumPy به طور خودکار بخش مرکزی آرایه را قطع میکند و تنها ابتدا و انتهای آن را نمایش میدهد.
برای اینکه این حالت را غیرفعال کنیم و NumPy کل آرایه را پرینت بگیرد، میتوانیم با استفاده از گزینه set_printoptions رفتار آن را تغییر دهیم.
عملیاتهای پایه
عملیاتهای حسابی بر روی آرایهها در سطح عناصر انجام مییابند. درنتیجه اجرای عملیات حسابی یک آرایه جدید ایجاد و مقادیر آن پر میشود.
برخلاف بسیاری از زبانهای ماتریسی عملگر * در آرایههای NumPy بهصورت عنصر به عنصر، عمل ضرب را انجام میدهد. ضرب ماتریسی را میتوان با استفاده از تابع dot یا ایجاد اشیای matrix انجام داد.
برخی عملیاتها مانند += و *= بهجای ایجاد یک آرایه جدید بر روی همان ماتریس موجود عمل میکنند.
زمانی که بر روی آرایههایی با انواع مختلف، عملیاتی انجام میگیرد، نوع آرایه حاصل متناظر با نوع آرایه عمومیتر یا دقیقتر خواهد بود (این حالت به نام upcasting نامیده میشود).
بسیاری از عملیاتهای تک آرایهای مانند جمع زدن همه عناصر یک آرایه بهصورت متدهایی در کلاس ndarray اجرا میشوند.
این عملیاتها به طور پیشفرض طوری بر روی آرایهها اجرا میشوند که صرفنظر از شکلشان، گویی آرایهها فهرستی از اعداد هستند. بااینحال با تعیین پارامتر axis میتوان یک عملیات را در راستای یک محور تعیین شده در یک آرایه اجرا کرد:
تابعهای سراسری
NumPy تابعهای ریاضیاتی متداولی مانند sin، cos و exp را در خود دارد. در NumPy این توابع به نام «تابعهای سراسری» (ufanc) نامیده میشوند. درون NumPy این تابعها در سطح عناصر یک آرایه اجرا میشوند و درنتیجه یک آرایه جدید ایجاد میکنند.
اندیسگذاری، قطعهبندی و تکرار
آرایههای تکبعدی را میتوان همانند فهرستها و دیگر دنبالههای پایتون، اندیسگذاری کرد، قطعهبندی نمود و عملیاتی را بر روی آنها تکرار کرد.
آرایههای چندبعدی میتوانند برای هر محور خود یک اندیس داشته باشند. این اندیسها در یک چندتایی که با کاما از هم جدا میشود ارائه میشوند:
زمانی که تعداد اندیسها کمتر از تعداد محورها باشد، اندیسهای ناموجود بهصورت قطعههای کامل در نظر گرفته میشوند:
در مورد آرایه [b[i عبارت داخل براکت را میتوان بدینصورت نوشت که ابتدا یک «i» قرار داد و سپس به تعداد محورهای باقیمانده «:» قرار داد. NumPy امکان استفاده از نقطه را نیز دارد یعنی [...,b[i.
نقطهها (...) بدین معنی است که به NumPy میگوییم هر مقدار دونقطه (:) دیگر که نیاز است بگذار تا یک چندتایی کامل برای اندیسها ایجاد شود.
تکرار عملیات بر روی آرایههای چندبعدی با توجه به محور نخست انجام مییابد.
بااینحال، اگر کسی بخواهد یک عملیات را بر روی همه عناصر یک آرایه اجرا کند، میتواند از خصوصیت flat استفاده کند که باعث میشود عملیات بر روی همه عناصر آرایه تکرار شود:

دستکاری شکل
چگونه میتوانیم شکل یک آرایه را تغییر دهیم؟ هر آرایهای شکلی دارد که بر اساس تعداد عناصر هر محور تعیین میشود:
شکل یک آرایه را میتوان بهوسیله فرمانهای مختلف تغییر داد:
ترتیب عناصر در آرایه حاصل از ()ravel بهطورمعمول به «سبک C» هستند یعنی اندیس منتهیالیه سمت راست «سریعتر از بقیه تغییر مییابد» بنابراین عنصر بعد از [a[0,0، عنصر [a[0,1 است. اگر شکل آرایه تغییر یابد، در حالت جدید هم بهصورت «سبک C» با آن برخورد میشود. NumPy بهطورمعمول آرایههایی ایجاد میکند که به این ترتیب ذخیره میشوند. بنابراین برای کپی کردن آرگومانهای آن نیازی به ()ravel نیست، اما اگر آرایه با استفاده از تکههایی از آرایههای دیگر یا با استفاده از گزینههای نامعمول ایجاد شده باشد، ممکن است نیاز باشد که ()ravel نیز کپی شود. تابعهای ()ravel و ()reshape را نیز میتوان با استفاده از آرگومانهای اختیاری تغییر داد و مثلاً از آرایههایی به سبک فرترن (FORTRAN) استفاده کرد که در آنها اندیس منتهیالیه سمت چپ قبل از همه تغییر مییابد.
تابع reshape آرگومانش را با شکل تغییر یافتهای برمیگرداند، در حالی که تابع resize خود آرایه را تغییر میدهد:
اگر یک بعد در طی عملیات reshape بهصورت 1- تعیین شده باشد در این صورت ابعاد دیگر به طور خودکار محاسبه میشوند:
پشتهسازی (Stacking) با آرایههای مختلف
میتوان از چند آرایه برای پشتهسازی در راستای محورهای مختلف استفاده کرد:
تابع column_stack آرایههای یکبعدی را بهصورت ستونهایی در یک آرایه دوبعدی پشته میکند. این تابع معادل تابع vstack است که تنها در مورد آرایههای یکبعدی عمل میکند:
از سوی دیگر، تابع row_stack آرایههای یکبعدی را بهصورت ردیفهایی در آرایههای دوبعدی، پشته میکند. برای آرایههایی با ابعادی بیش از 2، تابع hstack در راستای محور دوم و vstack در راستای محور اول پشتهسازی میکند و تابع concatenate امکان تعیین تعداد محورهایی که پشتهسازی در راستای آنها انجام میگیرد را مهیا کرده است. در موارد پیچیدهتر تابعهای []_r و []_c برای ایجاد آرایههایی با پشتهسازی در راستای یک محور، مناسب هستند. این توابع امکان استفاده از عبارتهای محدودهای (":") را فراهم کردهاند:
[]_r و []_ c وقتی بر روی آرایهها به عنوان آرگومان استفاده میشوند، مشابه توابع vstack و hstack با رفتار پیشفرض عمل میکنند، اما این مزیت اضافی را دارند که امکان تعریف کردن تعداد محورهایی که پشتهسازی در راستای آنها انجام میشود را دارند.
افراز کردن یک آرایه به چند آرایه کوچکتر
با استفاده از تابع hsplit میتوان یک آرایه را در راستای محورهای افقیاش افراز کرد. این کار یا با تعیین تعداد آرایههای همشکلی که باید بازگردانده شوند، انجام میگیرد یا با تعیین ستونهایی که پس از آنها باید عمل تقسیم کردن انجام گیرد.
تابع Vsplit آرایه را در راستای محورهای عمودی افراز میکند و تابع array split امکان تعیین دقیق محورهایی که باید افراز شوند را فراهم کرده است.
کپیها و نمایشها
زمانی که بر روی آرایهها عملیاتی انجام میدهیم یا آنها را دستکاری میکنیم، در برخی موارد دادههای آنها به یک آرایه جدید کپی میشود و در برخی موارد نیز چنین نمیشود. این مسئله موجب سردرگمی افراد مبتدی میشود. بهطورکلی سه حالت وجود دارد:
هیچ کپی انجام نمیشود
در انتسابهای ساده هیچ کپی از اشیای آرایه یا دیگر دادهها ایجاد نمیشود.
پایتون اشیای تغییرپذیر را بهصورت مرجع ارسال میکند بنابراین فراخوانهای تابع هیچ کپی جدیدی ایجاد نمیکنند.

نمایش (view) یا کپی سطحی
اشیای آرایهای مختلف میتوانند دادههای مشترکی داشته باشند. متد view یک شی آرایهای جدید ایجاد میکند که از دادههای مشابهی استفاده میکند.
قطعهبندی کردن یک آرایه یک نمایش (view) از آن بازمیگرداند:
کپی عمیق
متد copy یک کپی کامل از آرایه و دادههای آن ایجاد میکند.
در بخش دوم این مقاله، به بررسی مفاهیم و توابع پیشرفتهتری خواهیم پرداخت.
اگر تمایل به مطالعه بیشتر در مورد این موضوعات را داشته باشید؛ شاید آموزش های زیر نیز برای شما مفید باشند:
- آموزش برنامه نویسی پایتون
- آموزش ساخت ربات تلگرام با پایتون (Python)
- آموزش پایتون گرافیکی (رابط های گرافیکی پایتون)
- آموزش یادگیری ماشین (Machine Learning) با پایتون (Python)
#
با سلام و خسته نباشید
امکان این قسمت از مقاله رو یه توضیح مختصر بدین که چجوری این اتفاق میوفته؟
** در مثال زیر آرایه رتبه 2 دارد (2 بعدی است). بعد (محور) نخست طولی به اندازه 2 دارد، بعد دوم طول 3 دارد.
[[ 1., 0., 0.],
[ 0., 1., 2.]]