پایتون علمی: استفاده از SciPy برای بهینه سازی
هنگامی که می خواهید کار علمی را در پایتون انجام دهید، اولین کتابخانه ای که می توانید به آن مراجعه کنید SciPy است. همانطور که در این آموزش خواهید دید، SciPy فقط یک کتابخانه نیست، بلکه یک اکوسیستم کامل از کتابخانه ها است که با هم کار می کنند تا به شما کمک کنند کارهای علمی پیچیده را سریع و قابل اعتماد انجام دهید.
در این آموزش یاد خواهید گرفت که چگونه:
- اطلاعات مربوط به تمام کارهایی که می توانید با SciPy انجام دهید بیابید
- SciPy را روی رایانه خود نصب کنید
- استفاده از SciPy برای خوشه بندی یک مجموعه داده توسط چندین متغیر
- از SciPy برای یافتن بهینه یک تابع استفاده کنید
می توانید نمونه های این آموزش را با دانلود کد منبع موجود در لینک زیر دنبال کنید:
تمایز SciPy اکوسیستم و SciPy کتابخانه
هنگامی که می خواهید از پایتون برای کارهای محاسباتی علمی استفاده کنید، چندین کتابخانه وجود دارد که احتمالا به شما توصیه می شود از آنها استفاده کنید، از جمله:
- NumPy
- SciPy
- ماتplotlib
- آی پیتون
- SymPy
- پانداها
در مجموع، این کتابخانه ها اکوسیستم SciPy را تشکیل می دهند و برای همکاری با یکدیگر طراحی شده اند. بسیاری از آنها برای انجام محاسبات مستقیما به آرایه های NumPy متکی هستند. این آموزش انتظار دارد که شما با ایجاد آرایه های NumPy و کار بر روی آنها آشنایی داشته باشید.
توجه: اگر به یک آغازگر سریع یا تجدید نظر در NumPy نیاز دارید، می توانید این آموزش ها را بررسی کنید:
- Look Ma، No
for
Loops: برنامه نویسی آرایه با NumPy NumPy arange()
: نحوه استفادهاز()np.arange
- MATLAB در مقابل پایتون: بررسی عملیات آرایه اولیه
در این آموزش، با کتابخانه SciPy، یکی از اجزای اصلی اکوسیستم SciPy آشنا خواهید شد. کتابخانه SciPy کتابخانه اساسی برای محاسبات علمی در پایتون است. بسیاری از رابط های کارآمد و کاربرپسند را برای کارهایی مانند یکپارچه سازی عددی، بهینه سازی، پردازش سیگنال، جبر خطی و غیره فراهم می کند.
آشنایی با ماژول های SciPy
کتابخانه SciPy از تعدادی ماژول تشکیل شده است که کتابخانه را به واحدهای عملکردی متمایز تقسیم می کند. اگر می خواهید در مورد ماژول های مختلفی که SciPy گنجانده شده است بیاموزید، می توانید help()
را در scipy
اجرا کنید، همانطور که در زیر نشان داده شده است:
>>> import scipy
>>> help(scipy)
این برخی از خروجی های راهنما را برای کل کتابخانه SciPy تولید می کند که بخشی از آن در زیر نشان داده شده است:
Subpackages
-----------
Using any of these subpackages requires an explicit import. For example,
``import scipy.cluster``.
::
cluster --- Vector Quantization / Kmeans
fft --- Discrete Fourier transforms
fftpack --- Legacy discrete Fourier transforms
integrate --- Integration routines
...
این بلوک کد بخش Subpackages
خروجی راهنما را نشان می دهد که لیستی از تمام ماژول های موجود در SciPy است که می توانید برای محاسبات از آنها استفاده کنید.
به متن بالای بخش توجه کنید که می گوید: "استفاده از هر یک از این زیربسته ها نیاز به وارد کردن صریح دارد."
هنگامی که می خواهید از عملکرد یک ماژول در SciPy استفاده کنید، باید ماژولی را که می خواهید به طور خاص استفاده کنید وارد کنید. کمی بعد در آموزش چند نمونه از این موارد را خواهید دید و دستورالعمل های وارد کردن کتابخانه ها از SciPy در مستندات SciPy نشان داده شده است.
هنگامی که تصمیم گرفتید از کدام ماژول می خواهید استفاده کنید، می توانید مرجع SciPy API را بررسی کنید که شامل تمام جزئیات هر ماژول در SciPy است. اگر به دنبال چیزی با کمی نمایش بیشتر هستید، یادداشت های سخنرانی SciPy منبعی عالی برای بررسی عمیق بسیاری از ماژول های SciPy هستند.
بعدا در این آموزش، با خوشه
و بهینه سازی
آشنا خواهید شد که دو ماژول موجود در کتابخانه SciPy هستند. اما ابتدا باید SciPy را روی رایانه خود نصب کنید.
نصب SciPy بر روی کامپیوتر شما
مانند اکثر بسته های پایتون، دو راه اصلی برای نصب SciPy بر روی رایانه شما وجود دارد:
- آناکوندا
- PyPI و
پیپ
در اینجا، یاد خواهید گرفت که چگونه از هر دوی این روش ها برای نصب کتابخانه استفاده کنید. تنها وابستگی مستقیم SciPy بسته NumPy است. در صورت لزوم، هر دو روش نصب، به طور خودکار NumPy را علاوه بر SciPy نصب می کند.
آناکوندا
Anaconda یک توزیع محبوب پایتون است، عمدتا به این دلیل که شامل نسخه های از پیش ساخته شده محبوب ترین بسته های علمی پایتون برای ویندوز، macOS و لینوکس است. اگر هنوز اصلا پایتون را روی رایانه خود نصب نکرده اید، آناکوندا یک گزینه عالی برای شروع کار است. Anaconda با SciPy و وابستگی های مورد نیاز آن از قبل نصب شده است، بنابراین هنگامی که Anaconda را نصب کردید، نیازی به انجام کار دیگری ندارید!
می توانید Anaconda را از صفحه دانلودهای آنها دانلود و نصب کنید. مطمئن شوید که جدیدترین نسخه پایتون 3 را دانلود کرده اید. هنگامی که نصب کننده را روی رایانه خود دارید، بسته به پلتفرم خود، می توانید روش راه اندازی پیش فرض یک برنامه را دنبال کنید.
توجه داشته باشید: مطمئن شوید که Anaconda را در دایرکتوری نصب کنید که برای تغییر آن نیازی به مجوز مدیر ندارد. این تنظیمات پیش فرض در نصب کننده است.
اگر قبلا Anaconda را نصب کرده اید، اما می خواهید SciPy را نصب یا به روز کنید، می توانید این کار را نیز انجام دهید. یک برنامه ترمینال را در macOS یا Linux یا Anaconda Prompt در ویندوز باز کنید و یکی از خطوط کد زیر را تایپ کنید:
conda install scipy
conda update scipy
اگر نیاز به نصب SciPy دارید، باید از خط اول استفاده کنید یا اگر فقط می خواهید SciPy را به روز کنید، از خط دوم استفاده کنید. برای اطمینان از نصب SciPy ، پایتون را در ترمینال خود اجرا کنید و سعی کنید SciPy را وارد کنید:
>>> import scipy
>>> print(scipy.__file__)
/.../lib/python3.7/site-packages/scipy/__init__.py
در این کد، scipy
را وارد کرده اید و مکان فایلی را که scipy
از آن بارگذاری شده است چاپ کرده اید. مثال بالا برای macOS است. رایانه شما احتمالا مکان متفاوتی را نشان می دهد. اکنون SciPy را روی رایانه خود نصب کرده اید و آماده استفاده است. برای شروع استفاده از SciPy می توانید به بخش بعدی بروید!
مدیر بسته پیپ
اگر قبلا نسخه ای از پایتون را نصب کرده اید که آناکوندا نیست، یا نمی خواهید از Anaconda استفاده کنید، از pip
برای نصب SciPy استفاده خواهید کرد. برای کسب اطلاعات بیشتر در مورد اینکه pip
چیست، استفاده از pip
پایتون برای مدیریت وابستگی های پروژه های خود و راهنمای مبتدیان برای pip
را بررسی کنید.
توجه: پیپ
بسته ها را با استفاده از قالبی به نام چرخ ها نصب می کند. در قالب چرخ، کد قبل از ارسال به رایانه شما کامپایل می شود. این تقریبا همان رویکردی است که آناکوندا در پیش می گیرد، اگرچه فایل های فرمت چرخ کمی با فرمت Anaconda متفاوت هستند و این دو قابل تعویض نیستند.
برای نصب SciPy با استفاده از pip
، برنامه ترمینال خود را باز کنید و خط کد زیر را تایپ کنید:
python -m pip install -U scipy
کد SciPy را در صورتی که قبلا نصب نشده باشد نصب می کند یا در صورت نصب SciPy را ارتقا می دهد. برای اطمینان از نصب SciPy ، پایتون را در ترمینال خود اجرا کنید و سعی کنید SciPy را وارد کنید:
>>> import scipy
>>> print(scipy.__file__)
/.../lib/python3.7/site-packages/scipy/__init__.py
در این کد، scipy
را وارد کرده اید و مکان فایلی را که scipy
از آن بارگذاری شده است چاپ کرده اید. مثال بالا برای macOS است که از pyenv استفاده می کند. رایانه شما احتمالا مکان متفاوتی را نشان می دهد. اکنون SciPy را روی رایانه خود نصب کرده اید. بیایید ببینیم چگونه می توانید از SciPy برای حل چند مشکلی که ممکن است با آن مواجه شوید استفاده کنید!
استفاده از ماژول خوشه در SciPy
خوشه بندی یک تکنیک محبوب برای دسته بندی داده ها با مرتبط کردن آنها به گروه ها است. کتابخانه SciPy شامل پیاده سازی الگوریتم خوشه بندی k-means و همچنین چندین الگوریتم خوشه بندی سلسله مراتبی است. در این مثال، از الگوریتم k-means در scipy.cluster.vq
استفاده خواهید کرد، جایی که vq
مخفف کوانتیزاسیون برداری است.
ابتدا باید نگاهی به مجموعه داده ای که برای این مثال استفاده می کنید بیندازید. این مجموعه داده شامل 4827 پیام متنی واقعی و 747 پیام متنی هرزنامه (یا پیامک) است. مجموعه داده خام را می توان در مخزن یادگیری ماشین UCI یا صفحه وب نویسندگان یافت.
توجه: داده ها توسط Tiago A. Almeida و José María Gómez Hidalgo جمع آوری شده و در مقاله ای با عنوان "مشارکت در مطالعه فیلترینگ اسپم پیامک: مجموعه جدید و نتایج" در مجموعه مقالات سمپوزیوم ACM 2011 در مورد مهندسی اسناد (DOCENG'11) که در Mountain View، کالیفرنیا، ایالات متحده آمریکا در سال 2011 برگزار شد، منتشر شد.
در مجموعه داده، هر پیام دارای یکی از دو برچسب است:
ژامبون
برای پیام های قانونیهرزنامه
برای پیام های هرزنامه
پیام متنی کامل با هر برچسب مرتبط است. هنگامی که داده ها را اسکن می کنید، ممکن است متوجه شوید که پیام های هرزنامه دارای ارقام عددی زیادی هستند. آنها اغلب شامل یک شماره تلفن یا برنده جایزه هستند. بیایید بر اساس تعداد ارقام موجود در پیام پیش بینی کنیم که آیا یک پیام اسپم است یا خیر. برای انجام این کار، داده ها را بر اساس تعداد ارقامی که در پیام ظاهر می شود به سه گروه دسته بندی می کنید:
هرزنامه نیست: پیش بینی می شود پیام هایی که کمترین تعداد رقم را دارند هرزنامه نباشند.
ناشناس: پیام هایی با تعداد متوسط رقم ناشناخته هستند و باید توسط الگوریتم های پیشرفته تر پردازش شوند.
هرزنامه: پیام هایی که بیشترین تعداد رقم را دارند پیش بینی می شود که هرزنامه باشند.
بیایید با خوشه بندی پیام های متنی شروع کنیم. ابتدا باید کتابخانه هایی را که در این مثال استفاده می کنید وارد کنید:
from pathlib import Path
import numpy as np
from scipy.cluster.vq import whiten, kmeans, vq
می بینید که سه تابع را از scipy.cluster.vq
وارد می کنید. هر یک از این توابع یک آرایه NumPy را به عنوان ورودی می پذیرد. این آرایه ها باید دارای ویژگی های مجموعه داده در ستون ها و مشاهدات در ردیف ها باشند.
یک ویژگی یک متغیر مورد علاقه است، در حالی که هر بار که هر ویژگی را ضبط می کنید، یک مشاهده ایجاد می شود. در این مثال، 5,574 مشاهده یا پیام فردی در مجموعه داده وجود دارد. علاوه بر این، خواهید دید که دو ویژگی وجود دارد:
- تعداد ارقام یک پیام متنی
- تعداد دفعاتی که تعداد ارقام در کل مجموعه داده ظاهر می شود
در مرحله بعد، باید فایل داده را از پایگاه داده UCI بارگیری کنید. داده ها به صورت یک فایل متنی ارائه می شوند، جایی که کلاس پیام با یک کاراکتر برگه از پیام جدا می شود و هر پیام در خط خاص خود قرار دارد. شما باید داده ها را با استفاده از pathlib در یک لیست بخوانید. مسیر
:
data = Path("SMSSpamCollection").read_text()
data = data.strip()
data = data.split("\n")
در این کد از pathlib استفاده می کنید. Path.read_text()
برای خواندن فایل در یک رشته. سپس، از .strip()
برای حذف هر فاصله انتهایی استفاده می کنید و رشته را به یک لیست با .split()
تقسیم می کنید.
در مرحله بعد، می توانید تجزیه و تحلیل داده ها را شروع کنید. شما باید تعداد ارقامی را که در هر پیام متنی ظاهر می شود بشمارید. پایتون شامل مجموعه ها است. شمارنده
در کتابخانه استاندارد برای جمع آوری تعداد اشیاء در یک ساختار دیکشنری مانند. با این حال، از آنجایی که همه توابع در scipy.cluster.vq
انتظار آرایه های NumPy را به عنوان ورودی دارند، نمی توانید از مجموعه ها استفاده کنید. شمارنده
برای این مثال. در عوض، شما از یک آرایه NumPy استفاده می کنید و شمارش ها را به صورت دستی پیاده سازی می کنید.
باز هم، شما به تعداد ارقام یک پیام کوتاه معین و تعداد پیام های SMS دارای این تعداد رقم علاقه مند هستید. ابتدا باید یک آرایه NumPy ایجاد کنید که تعداد ارقام یک پیام معین را با نتیجه پیام مرتبط کند، خواه ژامبون باشد یا هرزنامه:
digit_counts = np.empty((len(data), 2), dtype=int)
در این کد، شما یک آرایه خالی NumPy به نام digit_counts
ایجاد می کنید که دارای دو ستون و 5,574 ردیف است. تعداد ردیف ها برابر با تعداد پیام های موجود در مجموعه داده است. از digit_counts
برای مرتبط کردن تعداد ارقام پیام با هرزنامه بودن یا نبودن پیام استفاده خواهید کرد.
قبل از ورود به حلقه، باید آرایه را ایجاد کنید، بنابراین مجبور نیستید با گسترش آرایه خود، حافظه جدیدی را اختصاص دهید. این کار کارایی کد شما را بهبود می بخشد. در مرحله بعد، باید داده ها را برای ثبت تعداد ارقام و وضعیت پیام پردازش کنید:
for i, line in enumerate(data):
case, message = line.split("\t")
num_digits = sum(c.isdigit() for c in message)
digit_counts[i, 0] = 0 if case == "ham" else 1
digit_counts[i, 1] = num_digits
در اینجا یک تفکیک خط به خط از نحوه عملکرد این کد آورده شده است:
خط 8: روی
داده
ها حلقه بزنید. شما ازenumerate()
استفاده می کنید تا مقدار لیست را درخط
قرار دهید و یک indexi
برای این لیست ایجاد کنید. برای کسب اطلاعات بیشتر در موردenumerate()
، Pythonenumerate()
: ساده کردن حلقه هایی که به شمارنده نیاز دارند، را بررسی کنید.خط 9: خط را روی کاراکتر تب تقسیم کنید تا
مورد
وپیام
ایجاد شود.CASE
رشته ای است که می گوید پیامHam
است یاهرزنامه
، در حالی کهmessage
رشته ای با متن پیام است.خط 10: تعداد ارقام پیام را با استفاده از
sum()
یک درک محاسبه کنید. در درک، هر کاراکتر را در پیام با استفادهاز isdigit()
بررسی می کنید، که اگر عنصر یک عددباشد True
و در غیر این صورتFalse
را برمی گرداند.sum()
سپس هر نتیجهTrue
را به عنوان 1 و هرFalse
را به عنوان 0 در نظر می گیرد. بنابراین، نتیجهsum()
در این درک، تعداد کاراکترهایی است کهisdigit()
برایآنها True
را برمی گرداند.خط 11: مقادیر را به
digit_counts
اختصاص دهید. شما اولین ستون ردیفi
را به 0 اختصاص می دهید اگر پیام قانونی بود (ham
) یا اگر پیام هرزنامه بود 1.خط 12: مقادیر را به
digit_counts
اختصاص دهید. شما ستون دوم ردیفi
را به تعداد ارقام پیام اختصاص می دهید.
اکنون شما یک آرایه NumPy دارید که شامل تعداد ارقام هر پیام است. با این حال، شما می خواهید الگوریتم خوشه بندی را روی آرایه ای اعمال کنید که تعداد پیام ها با تعداد مشخصی از ارقام را دارد. به عبارت دیگر، شما باید آرایه ای ایجاد کنید که در آن ستون اول دارای تعداد ارقام یک پیام باشد و ستون دوم تعداد پیام هایی است که آن تعداد رقم را دارند. کد زیر را بررسی کنید:
unique_counts = np.unique(digit_counts[:, 1], return_counts=True)
np.unique()
یک آرایه را به عنوان اولین آرگومان می گیرد و آرایه دیگری را با عناصر منحصر به فرد آرگومان برمی گرداند. همچنین چندین استدلال اختیاری لازم است. در اینجا، شما از return_counts=True
برای دستور دادن به np.unique()
استفاده می کنید تا آرایه ای را با تعداد دفعاتی که هر عنصر منحصر به فرد در آرایه ورودی وجود دارد، برگرداند. این دو خروجی به صورت تاپل بازگردانده می شوند که در unique_counts
ذخیره می کنید.
در مرحله بعد، باید unique_counts
را به شکلی تبدیل کنید که برای خوشه بندی مناسب باشد:
unique_counts = np.transpose(np.vstack(unique_counts))
شما دو خروجی 1xN از np.unique()
را با استفاده از np.vstack()
در یک آرایه 2xN ترکیب می کنید و سپس آنها را به یک آرایه Nx2 منتقل می کنید. این فرمت همان چیزی است که در توابع خوشه بندی استفاده خواهید کرد. هر ردیف در unique_counts
اکنون دارای دو عنصر است:
- تعداد ارقام در یک پیام
- تعداد پیام هایی که این تعداد رقم را داشتند
زیرمجموعه ای از خروجی این دو عملیات در زیر نشان داده شده است:
[[ 0 4110]
[ 1 486]
[ 2 160]
...
[ 40 4]
[ 41 2]
[ 47 1]]
در مجموعه داده، 4110 پیام وجود دارد که رقمی ندارند، 486 پیام دارای 1 رقم و غیره هستند. اکنون، شما باید الگوریتم خوشه بندی k-means را برای این آرایه اعمال کنید:
whitened_counts = whiten(unique_counts)
codebook, _ = kmeans(whitened_counts, 3)
شما از whiten()
برای نرمال کردن هر ویژگی برای داشتن واریانس واحد استفاده می کنید، که نتایج حاصل از kmeans()
را بهبود می بخشد. سپس، kmeans()
داده های سفید شده و تعداد خوشه ها را برای ایجاد به عنوان آرگومان می گیرد. در این مثال، شما می خواهید 3 خوشه ایجاد کنید، برای قطعا ژامبون، قطعا اسپم و ناشناخته. kmeans()
دو مقدار را برمی گرداند:
آرایه ای با سه ردیف و دو ستون که مرکزهای هر گروه را نشان می دهد: الگوریتم
kmeans()
مکان بهینه مرکز هر خوشه را با به حداقل رساندن فاصله از مشاهدات تا هر مرکز محاسبه می کند. این آرایه بهکتاب کد
اختصاص داده شده است.میانگین فاصله اقلیدسی از مشاهدات تا مرکز: برای بقیه این مثال به این مقدار نیاز نخواهید داشت، بنابراین می توانید آن را به
_
اختصاص دهید.
در مرحله بعد، باید با استفاده از vq()
تعیین کنید که هر مشاهده به کدام خوشه تعلق دارد:
codes, _ = vq(whitened_counts, codebook)
vq()
کدهایی را از کتاب کد
به هر مشاهده اختصاص می دهد. دو مقدار را برمی گرداند:
مقدار اول آرایه ای به طول
unique_counts
است که در آن مقدار هر عنصر یک عدد صحیح است که نشان می دهد آن مشاهده به کدام خوشه اختصاص داده شده است. از آنجایی که در این مثال از سه خوشه استفاده کرده اید، هر مشاهده به خوشه0
،1
یا2
اختصاص داده می شود.مقدار دوم آرایه ای از فاصله اقلیدسی بین هر مشاهده و مرکز آن است.
اکنون که داده ها را خوشه بندی کرده اید، باید از آن برای پیش بینی پیام های SMS استفاده کنید. می توانید شمارش ها را بررسی کنید تا مشخص کنید که الگوریتم خوشه بندی در چند رقم مرز بین ژامبون قطعی و ناشناخته و بین ناشناخته و قطعا هرزنامه را ترسیم کرده است.
الگوریتم خوشه بندی به طور تصادفی کد 0
، 1
یا 2
را به هر خوشه اختصاص می دهد، بنابراین باید مشخص کنید که کدام یک است. می توانید از این کد برای یافتن کد مرتبط با هر خوشه استفاده کنید:
ham_code = codes[0]
spam_code = codes[-1]
unknown_code = list(set(range(3)) ^ set((ham_code, spam_code)))[0]
در این کد، خط اول کد مرتبط با پیام های ژامبون را پیدا می کند. طبق فرضیه ما در بالا ، پیام های ژامبون کمترین رقم را دارند و آرایه ارقام از کمترین به بیشترین رقم مرتب شده است. بنابراین، خوشه پیام ژامبون از ابتدای کدها
شروع می شود.
به طور مشابه، پیام های اسپم بیشترین رقم را دارند و آخرین خوشه را در کدها
تشکیل می دهند. بنابراین، کد پیام های اسپم برابر با آخرین عنصر کدها
خواهد بود. در نهایت، باید کد پیام های ناشناخته را پیدا کنید. از آنجایی که تنها 3 گزینه برای کد وجود دارد و قبلا دو مورد از آنها را شناسایی کرده اید، می توانید از عملگر symmetric_difference
در مجموعه
پایتون برای تعیین آخرین مقدار کد استفاده کنید. سپس، می توانید خوشه مرتبط با هر نوع پیام را چاپ کنید:
print("definitely ham:", unique_counts[codes == ham_code][-1])
print("definitely spam:", unique_counts[codes == spam_code][-1])
print("unknown:", unique_counts[codes == unknown_code][-1])
در این کد، هر خط ردیف هایی را در unique_counts
دریافت می کند که vq()
مقادیر متفاوتی از کدها را اختصاص داده است. از آنجایی که این عملیات یک آرایه را برمی گرداند، باید آخرین ردیف آرایه را دریافت کنید تا بیشترین تعداد ارقام اختصاص داده شده به هر خوشه را تعیین کنید. خروجی در زیر نشان داده شده است:
definitely ham: [0 4110]
definitely spam: [47 1]
unknown: [20 18]
در این خروجی می بینید که پیام های قطعا ژامبون پیام هایی با صفر رقم در پیام هستند، پیام های ناشناخته همه چیز بین 1 تا 20 رقم هستند و قطعا پیام های اسپم همه چیز از 21 تا 47 رقم هستند که حداکثر تعداد ارقام در مجموعه داده شما است.
اکنون، باید بررسی کنید که پیش بینی های شما در این مجموعه داده چقدر دقیق است. ابتدا چند ماسک برای digit_counts
ایجاد کنید تا بتوانید به راحتی وضعیت ژامبون
یا هرزنامه
پیام ها را بگیرید:
digits = digit_counts[:, 1]
predicted_hams = digits == 0
predicted_spams = digits > 20
predicted_unknowns = np.logical_and(digits > 0, digits <= 20)
در این کد، شما ماسک predicted_hams
را ایجاد می کنید، جایی که هیچ رقمی در پیام وجود ندارد. سپس، ماسک predicted_spams
را برای همه پیام های با بیش از 20 رقم ایجاد می کنید. در نهایت، پیام های وسط predicted_unknowns
هستند.
در مرحله بعد، این ماسک ها را روی تعداد ارقام واقعی اعمال کنید تا پیش بینی ها را بازیابی کنید:
spam_cluster = digit_counts[predicted_spams]
ham_cluster = digit_counts[predicted_hams]
unk_cluster = digit_counts[predicted_unknowns]
در اینجا، شما ماسک هایی را که در آخرین بلوک کد ایجاد کرده اید روی آرایه digit_counts
اعمال می کنید. با این کار سه آرایه جدید ایجاد می شود که فقط پیام هایی که در هر گروه خوشه بندی شده اند. در نهایت، می توانید ببینید که چه تعداد از هر نوع پیام در هر خوشه قرار گرفته است:
print("hams:", np.unique(ham_cluster[:, 0], return_counts=True))
print("spams:", np.unique(spam_cluster[:, 0], return_counts=True))
print("unknowns:", np.unique(unk_cluster[:, 0], return_counts=True))
این کد شمارش هر مقدار منحصر به فرد را از خوشه ها چاپ می کند. به یاد داشته باشید که 0
به این معنی است که پیام ژامبون
بوده و 1
به این معنی است که پیام هرزنامه
بوده است. نتایج در زیر نشان داده شده است:
hams: (array([0, 1]), array([4071, 39]))
spams: (array([0, 1]), array([ 1, 232]))
unknowns: (array([0, 1]), array([755, 476]))
از این خروجی می توانید ببینید که 4110 پیام در گروه قطعا ژامبون قرار گرفت که 4071 پیام در واقع ژامبون و تنها 39 پیام اسپم بودند. برعکس، از 233 پیامی که در گروه قطعا هرزنامه قرار گرفتند، تنها 1 پیام در واقع ژامبون و بقیه اسپم بودند.
البته، بیش از 1200 پیام در دسته ناشناخته قرار می گیرند، بنابراین برای طبقه بندی این پیام ها به تجزیه و تحلیل پیشرفته تری نیاز است. ممکن است بخواهید چیزی مانند پردازش زبان طبیعی را برای کمک به بهبود دقت پیش بینی خود بررسی کنید و می توانید از پایتون و Keras برای کمک به آن استفاده کنید.
استفاده از ماژول بهینه سازی در SciPy
هنگامی که نیاز به بهینه سازی پارامترهای ورودی برای یک تابع دارید، scipy.optimize
شامل تعدادی روش مفید برای بهینه سازی انواع مختلف توابع است:
minimize_scalar()
وminimize()
به ترتیب تابع یک متغیر و بسیاری از متغیرها را به حداقل رسانده اندcurve_fit()
برای قرار دادن یک تابع با مجموعه ای از داده هاroot_scalar()
وroot()
به ترتیب برای یافتن صفر تابعی از یک متغیر و بسیاری از متغیرهاlinprog()
برای به حداقل رساندن یک تابع هدف خطی با محدودیت های نابرابری و برابری خطی
در عمل، همه این توابع بهینه سازی را از یک نوع یا نوع دیگر انجام می دهند. در این بخش با دو تابع minimization minimize_scalar()
و minimize()
آشنا خواهید شد.
به حداقل رساندن یک تابع با یک متغیر
یک تابع ریاضی که یک عدد را می پذیرد و منجر به یک خروجی می شود، تابع اسکالر نامیده می شود. معمولا با توابع چند متغیره که چندین عدد را می پذیرند و همچنین منجر به تعداد خروجی های متعدد می شوند، در تضاد است. نمونه ای از بهینه سازی توابع چند متغیره را در بخش بعدی مشاهده خواهید کرد.
برای این بخش، تابع اسکالر شما یک چند جمله ای کوارتیک خواهد بود و هدف شما یافتن حداقل مقدار تابع است. تابع y=3x⁴ - 2x + 1 است. عملکرد در تصویر زیر برای محدوده x از 0 تا 1 ترسیم شده است:
در شکل می بینید که حداقل مقدار این تابع تقریبا x=0.55 است. می توانید از minimize_scalar()
برای تعیین مختصات دقیق x و y حداقل استفاده کنید. ابتدا minimize_scalar()
را از scipy.optimize
وارد کنید. سپس، باید تابع هدف را تعریف کنید که باید به حداقل برسد:
from scipy.optimize import minimize_scalar
def objective_function(x):
return 3 * x ** 4 - 2 * x + 1
objective_function()
ورودی x
را می گیرد و عملیات ریاضی لازم را روی آن اعمال می کند، سپس نتیجه را برمی گرداند. در تعریف تابع می توانید از هر تابع ریاضی که می خواهید استفاده کنید. تنها محدودیت این است که تابع باید یک عدد واحد را در انتها برگرداند.
در مرحله بعد، از minimize_scalar()
برای یافتن حداقل مقدار این تابع استفاده کنید. minimize_scalar()
فقط یک ورودی مورد نیاز دارد که نام تعریف تابع هدف است:
res = minimize_scalar(objective_function)
خروجی minimize_scalar()
نمونه ای از OptimizeResult
است. این کلاس بسیاری از جزئیات مربوطه را از اجرای بهینه ساز جمع آوری می کند، از جمله اینکه آیا بهینه سازی موفقیت آمیز بوده است یا خیر و در صورت موفقیت، نتیجه نهایی چه بوده است. خروجی minimize_scalar()
برای این تابع در زیر نشان داده شده است:
fun: 0.17451818777634331
nfev: 16
nit: 12
success: True
x: 0.5503212087491959
این نتایج همه ویژگی های OptimizeResult
هستند. موفقیت
یک مقدار بولی است که نشان می دهد آیا بهینه سازی با موفقیت انجام شده است یا خیر. اگر بهینه سازی موفقیت آمیز بود، پس سرگرم کننده
مقدار تابع هدف در مقدار بهینه x
است. از خروجی می توانید ببینید که همانطور که انتظار می رفت، مقدار بهینه برای این تابع نزدیک به x=0.55 بود.
توجه: همانطور که می دانید، هر عملکردی حداقل ندارد. به عنوان مثال، سعی کنید ببینید اگر تابع هدف شما y=x³ باشد چه اتفاقی می افتد. برای minimize_scalar()
، توابع هدف بدون حداقل اغلب منجر به OverflowError
می شوند، زیرا بهینه ساز در نهایت عددی را امتحان می کند که برای محاسبه توسط کامپیوتر بسیار بزرگ است.
در طرف مقابل توابع بدون حداقل توابع وجود دارد که دارای چندین مینیمم هستند. در این موارد، minimize_scalar()
تضمینی برای یافتن حداقل جهانی تابع ندارد. با این حال، minimize_scalar()
دارای یک آرگومان کلمه کلیدی متد
است که می توانید آن را برای کنترل حل کننده ای که برای بهینه سازی استفاده می شود مشخص کنید. کتابخانه SciPy دارای سه روش داخلی برای به حداقل رساندن اسکالر است:
برنت
پیاده سازی الگوریتم برنت است. این روش پیش فرض است.طلایی
یک پیاده سازی از جستجوی بخش طلایی است. مستندات اشاره می کند که روش برنت معمولا بهتر است.bounded
یک پیاده سازی محدود از الگوریتم برنت است. محدود کردن منطقه جستجو زمانی که حداقل در یک محدوده شناخته شده است مفید است.
وقتی متد
برنت
یا طلایی
باشد، minimize_scalar()
آرگومان دیگری به نام براکت
می گیرد. این دنباله ای از دو یا سه عنصر است که حدس اولیه مرزهای منطقه را با حداقل ارائه می دهد. با این حال، این حل کننده ها تضمین نمی کنند که حداقل یافت شده در این محدوده باشد.
از طرف دیگر ، هنگامی که متد
محدود
است ، minimize_scalar()
آرگومان دیگری به نام bounds
را می گیرد. این دنباله ای از دو عنصر است که به شدت منطقه جستجو را برای حداقل محدود می کند. روش محدود
شده را با تابع y=x⁴ - x² امتحان کنید. این تابع در شکل زیر ترسیم شده است:
با استفاده از کد نمونه قبلی، می توانید objective_function()
را به این صورت دوباره تعریف کنید:
def objective_function(x):
return x ** 4 - x ** 2
ابتدا روش پیش فرض برنت
را امتحان کنید:
res = minimize_scalar(objective_function)
در این کد، شما مقداری را برای متد
ارسال نکردید، بنابراین minimize_scalar()
به طور پیش فرض از متد برنت
استفاده کرد. خروجی این است:
fun: -0.24999999999999994
nfev: 15
nit: 11
success: True
x: 0.7071067853059209
می بینید که بهینه سازی موفقیت آمیز بوده است. بهینه نزدیک x=0.707 و y=-1/4 را پیدا کرد. اگر حداقل معادله را به صورت تحلیلی حل کنید، حداقل را در x=1/√2 پیدا خواهید کرد، که بسیار نزدیک به پاسخ یافت شده توسط تابع کمینه سازی است. با این حال، اگر بخواهید حداقل متقارن را در x=-1/√2 پیدا کنید، چه؟ شما می توانید همان نتیجه را با ارائه آرگومان براکت
به متد برنت
برگردانید:
res = minimize_scalar(objective_function, bracket=(-1, 0))
در این کد، دنباله (-1، 0)
را به براکت
ارائه می دهید تا جستجو در منطقه بین -1 و 0 شروع شود. شما انتظار دارید که حداقل در این منطقه وجود داشته باشد زیرا تابع هدف در مورد محور y متقارن است. با این حال، حتی با براکت
، روش برنت
همچنان حداقل را در x=+1/√2 برمی گرداند. برای یافتن حداقل در x=-1/√2 ، می توانید از روش محدود
با کران
استفاده کنید:
res = minimize_scalar(objective_function, method='bounded', bounds=(-1, 0))
در این کد، متد
و کرانها
را به عنوان آرگومان به minimize_scalar()
اضافه می کنید و مرزها
را از -1 تا 0 تنظیم می کنید. خروجی این روش به شرح زیر است:
fun: -0.24999999999998732
message: 'Solution found.'
nfev: 10
status: 0
success: True
x: -0.707106701474177
همانطور که انتظار می رفت، حداقل در x=-1/√2 یافت شد. به خروجی اضافی این روش توجه کنید که شامل یک ویژگی پیام
در res.
این فیلد اغلب برای خروجی دقیق تر از برخی از حل کننده های حداقل سازی استفاده می شود.
به حداقل رساندن یک تابع با متغیرهای زیاد
scipy.optimize
همچنین شامل minimize()
عمومی تر است. این تابع می تواند ورودی ها و خروجی های چند متغیره را مدیریت کند و الگوریتم های بهینه سازی پیچیده تری دارد تا بتواند این کار را انجام دهد. علاوه بر این، minimize()
می تواند محدودیت های راه حل مشکل شما را مدیریت کند. شما می توانید سه نوع محدودیت را مشخص کنید:
LinearConstraint
: راه حل با در نظر گرفتن حاصل ضرب داخلی مقادیر راه حل x با یک آرایه ورودی کاربر و مقایسه نتیجه با کران پایین و بالا محدود می شود.NonlinearConstraint
: راه حل با اعمال یک تابع ارائه شده توسط کاربر به مقادیر راه حل x و مقایسه مقدار بازگشت با کران پایین و بالا محدود می شود.مرزها
: مقادیر راه حل x محدود به قرار گرفتن بین کران پایین و بالا هستند.
هنگامی که از این محدودیت ها استفاده می کنید، می تواند انتخاب خاص روش بهینه سازی را که می توانید استفاده کنید محدود کند، زیرا همه روش های موجود از محدودیت ها به این روش پشتیبانی نمی کنند.
بیایید نمایشی در مورد نحوه استفاده از minimize()
امتحان کنیم. تصور کنید شما یک کارگزار سهام هستید که علاقه مند به به حداکثر رساندن کل درآمد حاصل از فروش تعداد ثابتی از سهام خود هستید. شما مجموعه خاصی از خریداران را شناسایی کرده اید و برای هر خریدار، می دانید که آنها چه قیمتی می پردازند و چه مقدار پول نقد در دست دارند.
می توانید این مشکل را به عنوان یک مسئله بهینه سازی محدود بیان کنید. تابع هدف این است که شما می خواهید درآمد خود را به حداکثر برسانید. با این حال، minimize()
حداقل مقدار یک تابع را پیدا می کند، بنابراین باید تابع هدف خود را در -1 ضرب کنید تا مقادیر x را پیدا کنید که بزرگترین عدد منفی را تولید می کنند.
یک محدودیت در این مشکل وجود دارد و آن این است که مجموع کل سهام خریداری شده توسط خریداران از تعداد سهامی که در دست دارید تجاوز نمی کند. همچنین مرزهایی برای هر یک از متغیرهای راه حل وجود دارد زیرا هر خریدار دارای حد بالایی پول نقد در دسترس و حد پایین صفر است. راه حل منفی مقادیر x به این معنی است که شما به خریداران پول می دهید!
برای حل این مشکل کد زیر را امتحان کنید. ابتدا ماژول های مورد نیاز خود را وارد کنید و سپس متغیرهایی را برای تعیین تعداد خریداران در بازار و تعداد سهامی که می خواهید بفروشید تنظیم کنید:
import numpy as np
from scipy.optimize import minimize, LinearConstraint
n_buyers = 10
n_shares = 15
در این کد، numpy
، minimize()
و LinearConstraint
را از scipy.optimize
وارد می کنید. سپس، بازاری متشکل از 10 خریدار ایجاد می کنید که در مجموع 15 سهم را از شما خریداری می کنند.
در مرحله بعد، آرایه هایی را برای ذخیره قیمتی که هر خریدار می پردازد، حداکثر مبلغی که می تواند خرج کند، و حداکثر تعداد سهامی که هر خریدار می تواند بپردازد، با توجه به دو آرایه اول، ایجاد کنید. برای این مثال، می توانید از تولید اعداد تصادفی در np.random
برای تولید آرایه ها استفاده کنید:
np.random.seed(10)
prices = np.random.random(n_buyers)
money_available = np.random.randint(1, 4, n_buyers)
در این کد، seed را برای مولدهای اعداد تصادفی NumPy تنظیم می کنید. این تابع اطمینان حاصل می کند که هر بار که این کد را اجرا می کنید، همان مجموعه اعداد تصادفی را دریافت خواهید کرد. اینجاست تا مطمئن شوید که خروجی شما با آموزش مقایسه یکسان است.
در خط 7، مجموعه ای از قیمت هایی را که خریداران می پردازند ایجاد می کنید. np.random.random()
آرایه ای از اعداد تصادفی را در بازه نیمه باز ایجاد می کند [0، 1]. تعداد عناصر موجود در آرایه با مقدار آرگومان تعیین می شود که در این حالت تعداد خریداران است.
در خط 8، شما آرایه ای از اعداد صحیح را در بازه نیمه باز از [1، 4] ایجاد می کنید، دوباره با اندازه تعداد خریداران. این آرایه نشان دهنده کل پول نقد هر خریدار است. اکنون، باید حداکثر تعداد سهامی را که هر خریدار می تواند خریداری کند، محاسبه کنید:
n_shares_per_buyer = money_available / prices
print(prices, money_available, n_shares_per_buyer, sep="\n")
در خط 9، نسبت money_available
با قیمت
ها را در نظر می گیرید تا حداکثر تعداد سهامی را که هر خریدار می تواند خریداری کند، تعیین کنید. در نهایت، هر یک از این آرایه ها را که با یک خط جدید از هم جدا شده اند، چاپ می کنید. خروجی در زیر نشان داده شده است:
[0.77132064 0.02075195 0.63364823 0.74880388 0.49850701 0.22479665
0.19806286 0.76053071 0.16911084 0.08833981]
[1 1 1 3 1 3 3 2 1 1]
[ 1.29647768 48.18824404 1.57816269 4.00638948 2.00598984 13.34539487
15.14670609 2.62974258 5.91328161 11.3199242 ]
ردیف اول آرایه ای از قیمت ها است که اعداد ممیز شناور بین 0 و 1 هستند. این ردیف با حداکثر پول نقد موجود در اعداد صحیح از 1 تا 4 دنبال می شود. در نهایت، تعداد سهامی را که هر خریدار می تواند خریداری کند، مشاهده می کنید.
اکنون، شما باید محدودیت ها و مرزها را برای حل کننده ایجاد کنید. محدودیت این است که مجموع کل سهام خریداری شده نمی تواند از تعداد کل سهام موجود تجاوز کند. این یک محدودیت است تا یک محدود زیرا بیش از یکی از متغیرهای راه حل را شامل می شود.
برای نشان دادن این به صورت ریاضی، می توان گفت که x[0] + x[1] + ... + x[n]=n_shares
، که در آن n
تعداد کل خریداران است. به طور خلاصه تر، می توانید نقطه یا حاصل ضرب داخلی بردار آنهایی با مقادیر محلول را در نظر بگیرید و آن را برابر با n_shares
محدود کنید. به یاد داشته باشید که LinearConstraint
حاصل ضرب نقطه آرایه ورودی را با مقادیر راه حل می گیرد و آن را با کران پایین و بالا مقایسه می کند. می توانید از این برای تنظیم محدودیت روی n_shares
استفاده کنید:
constraint = LinearConstraint(np.ones(n_buyers), lb=n_shares, ub=n_shares)
در این کد، آرایه ای از موارد با طول n_buyers
ایجاد می کنید و آن را به عنوان اولین آرگومان به LinearConstraint
ارسال می کنید. از آنجایی که LinearConstraint
حاصلضرب نقطه ای بردار راه حل را با این آرگومان می گیرد، مجموع سهام خریداری شده را به دست می آورد.
سپس این نتیجه محدود می شود که بین دو استدلال دیگر قرار بگیرد:
پوند
کران پایینub کران
بالایی
از آنجایی که lb=ub=n_shares
، این یک محدودیت برابری است زیرا مجموع مقادیر باید برابر با lb
و ub
باشد. اگر lb
با ub
متفاوت بود، پس یک محدودیت نابرابری بود.
در مرحله بعد، مرزهای متغیر راه حل را ایجاد کنید. مرزها تعداد سهام خریداری شده را به 0 در سمت پایین و n_shares_per_buyer
در سمت بالا محدود می کند. قالبی که minmize()
برای مرزها انتظار دارد، دنباله ای از تاپل های مرزهای پایین و بالا است:
bounds = [(0, n) for n in n_shares_per_buyer]
در این کد از یک درک مطلب برای ایجاد لیستی از تاپل ها برای هر خریدار استفاده می کنید. آخرین مرحله قبل از اجرای بهینه سازی، تعریف تابع هدف است. به یاد بیاورید که سعی می کنید درآمد خود را به حداکثر برسانید. به طور معادل، شما می خواهید منفی درآمد خود را تا حد امکان به یک عدد منفی تبدیل کنید.
درآمدی که از هر فروش به دست می آورید، قیمتی است که خریدار می پردازد ضرب در تعداد سهامی که خریداری می کند. از نظر ریاضی، می توانید این را به صورت قیمت ها[0]*x[0] + قیمت ها[1]*x[1] + ... + قیمت ها[n]*x[n]
بنویسید، که در آن n
دوباره تعداد کل خریداران است.
یک بار دیگر، می توانید این را به طور خلاصه تر با محصول داخلی یا x.dot(price)
نشان دهید. این بدان معنی است که تابع هدف شما باید مقادیر راه حل فعلی x
و آرایه قیمت ها را به عنوان آرگومان در نظر بگیرد:
def objective_function(x, prices):
return -x.dot(prices)
در این کد، شما objective_function()
را برای گرفتن دو آرگومان تعریف می کنید. سپس حاصل ضرب نقطه ای x
را با قیمت
ها می گیرید و منفی آن مقدار را برمی گردانید. به یاد داشته باشید که شما باید منفی را برگردانید زیرا سعی می کنید آن عدد را تا حد امکان کوچک کنید، یا تا حد امکان به بی نهایت منفی نزدیک کنید. در نهایت، می توانید minimize()
را فراخوانی کنید:
res = minimize(
objective_function,
x0=10 * np.random.random(n_buyers),
args=(prices,),
constraints=constraint,
bounds=bounds,
)
در این کد، res
نمونه ای از OptimizeResult
است، درست مانند minimize_scalar()
. همانطور که خواهید دید، بسیاری از فیلدهای مشابه وجود دارد، حتی اگر مشکل کاملا متفاوت باشد. در فراخوانی برای minimize()
، پنج آرگومان را ارسال می کنید:
objective_function
: اولین آرگومان موقعیتی باید تابعی باشد که در حال بهینه سازی آن هستید.x0
: آرگومان بعدی یک حدس اولیه برای مقادیر راه حل است. در این مورد، شما فقط یک آرایه تصادفی از مقادیر بین 0 تا 10 را با طولn_buyers
ارائه می دهید. برای برخی الگوریتم ها یا برخی مشکلات، انتخاب یک حدس اولیه مناسب ممکن است مهم باشد. با این حال، برای این مثال، خیلی مهم به نظر نمی رسد.args
: آرگومان بعدی مجموعه ای از آرگومان های دیگر است که لازم است به تابع هدف منتقل شوند.minimize()
همیشه مقدار فعلی راه حلx
را به تابع هدف منتقل می کند، بنابراین این آرگومان به عنوان مکانی برای جمع آوری هر ورودی لازم دیگر عمل می کند. در این مثال، شما بایدقیمت
ها را بهobjective_function()
منتقل کنید، بنابراین به اینجا می رسد.محدودیت
ها: استدلال بعدی دنباله ای از محدودیت ها در مورد مسئله است. شما در حال عبور از محدودیتی هستید که قبلا در تعداد سهام های موجود ایجاد کرده اید.bounds
: آخرین آرگومان دنباله مرزها در متغیرهای راه حلی است که قبلا ایجاد کرده اید.
هنگامی که حل کننده اجرا شد، باید با چاپ آن رزولوشن
را بررسی کنید:
fun: -8.783020157087478
jac: array([-0.7713207 , -0.02075195, -0.63364828, -0.74880385,
-0.49850702, -0.22479665, -0.1980629 , -0.76053071, -0.16911089,
-0.08833981])
message: 'Optimization terminated successfully.'
nfev: 204
nit: 17
njev: 17
status: 0
success: True
x: array([1.29647768e+00, 2.78286565e-13, 1.57816269e+00,
4.00638948e+00, 2.00598984e+00, 3.48323773e+00, 3.19744231e-14,
2.62974258e+00, 2.38121197e-14, 8.84962214e-14])
در این خروجی می توانید پیام
و وضعیتی
را مشاهده کنید که وضعیت نهایی بهینه سازی را نشان می دهد. برای این بهینه ساز، وضعیت 0
به معنای پایان بهینه سازی با موفقیت است که می توانید آن را در پیام
نیز مشاهده کنید. از آنجایی که بهینه سازی موفقیت آمیز بود، fun
مقدار تابع هدف را در مقادیر راه حل بهینه نشان می دهد. از این فروش 8.78 دلار درآمد خواهید داشت.
می توانید مقادیر x
را مشاهده کنید که عملکرد را در res.x
بهینه می کند. در این حالت نتیجه این است که شما باید حدود 1.3 سهم را به خریدار اول، صفر به خریدار دوم، 1.6 سهم به خریدار سوم، 4.0 به خریدار چهارم و غیره بفروشید.
همچنین باید بررسی کنید و مطمئن شوید که محدودیت ها و مرزهایی که تعیین می کنید برآورده شده اند. می توانید این کار را با کد زیر انجام دهید:
print("The total number of shares is:", sum(res.x))
print("Leftover money for each buyer:", money_available - res.x * prices)
در این کد مجموع سهام خریداری شده توسط هر خریدار را چاپ می کنید که باید برابر با n_shares
باشد. سپس، تفاوت بین پول نقد هر خریدار و مبلغی که خرج کرده است را چاپ می کنید. هر یک از این مقادیر باید مثبت باشند. خروجی حاصل از این بررسی ها در زیر نشان داده شده است:
The total number of shares is: 15.000000000000002
Leftover money for each buyer: [3.08642001e-14 1.00000000e+00
3.09752224e-14 6.48370246e-14 3.28626015e-14 2.21697984e+00
3.00000000e+00 6.46149800e-14 1.00000000e+00 1.00000000e+00]
همانطور که می بینید، تمام محدودیت ها و مرزهای راه حل برآورده شد. حالا باید سعی کنید مشکل را تغییر دهید تا حل کننده نتواند راه حلی پیدا کند. n_shares
را به مقدار 1000 تغییر دهید، به طوری که می خواهید 1000 سهم را به همین خریداران بفروشید. وقتی minimize()
را اجرا می کنید، متوجه خواهید شد که نتیجه به شرح زیر است:
fun: nan
jac: array([nan, nan, nan, nan, nan, nan, nan, nan, nan, nan])
message: 'Iteration limit exceeded'
nfev: 2182
nit: 101
njev: 100
status: 9
success: False
x: array([nan, nan, nan, nan, nan, nan, nan, nan, nan, nan])
توجه داشته باشید که ویژگی وضعیت
اکنون دارای مقدار 9
است و پیام
بیان می کند که از حد مجاز تکرار فراتر رفته است. با توجه به مقدار پولی که هر خریدار دارد و تعداد خریداران در بازار، هیچ راهی برای فروش 1000 سهم وجود ندارد. با این حال، به جای ایجاد خطا، minimize()
همچنان یک نمونه OptimizeResult
را برمی گرداند. قبل از انجام محاسبات بیشتر باید حتما کد وضعیت را بررسی کنید.
نتیجه
در این آموزش، با اکوسیستم SciPy و تفاوت آن با کتابخانه SciPy آشنا شدید. شما در مورد برخی از ماژول های موجود در SciPy مطالعه کرده اید و یاد گرفتید که چگونه SciPy را با استفاده از Anaconda یا pip
نصب کنید. سپس، روی چند مثال تمرکز کردید که از قابلیت خوشه بندی و بهینه سازی در SciPy استفاده می کنند.
در مثال خوشه بندی، الگوریتمی برای مرتب سازی پیام های متنی هرزنامه از پیام های قانونی ایجاد کردید. با استفاده از kmeans()
، متوجه شدید که پیام هایی با بیش از 20 رقم به احتمال زیاد اسپم هستند!
در مثال بهینه سازی، ابتدا حداقل مقدار را در یک تابع ریاضی واضح تنها با یک متغیر پیدا کردید. سپس، مشکل پیچیده تر به حداکثر رساندن سود خود از فروش سهام را حل کردید. با استفاده از minimize()
، تعداد بهینه سهام را برای فروش به گروهی از خریداران پیدا کردید و 8.79 دلار سود کسب کردید!
SciPy یک کتابخانه بزرگ است که ماژول های بسیار بیشتری برای غواصی در آن وجود دارد. با دانشی که اکنون دارید، به خوبی برای شروع کاوش مجهز هستید!
می توانید نمونه های این آموزش را با دانلود کد منبع موجود در لینک زیر دنبال کنید: