رضا مظاهری
رضا مظاهری
خواندن ۸ دقیقه·۲ سال پیش

پیاده سازی رگرسیون لجستیک از صفر

مقدمه

در مطلب قبلی که در ویرگول پست کردم با رگرسیون خطی ساده و نحوه‌ی پیاده سازی آن از صفر آشنا شدیم (لینک) ، در این مطلب یک مدل یادگیری ماشین دیگر به نام رگرسیون لجستیک را بررسی می‌کنیم. رگرسیون لجستیک از دسته الگوریتم‌های نظارت شده (Supervised) می‌باشد و برای دسته‌بندی (Classification) مورد استفاده قرار می‌گیرد. رگرسیون لجستیک یکی از پرکاربرد‌ترین الگوریتم‌های یادگیری ماشین است که در ادامه به تفصیل آن را بررسی می‌کنیم.

محدودیت الگوریتم رگرسیون خطی در دسته‌بندی

در این مطلب هدف به دست آوردن الگوریتمی برای دسته‌بندی گروهی از داده‌ها می‌باشد. اما اول باید به این سوال پاسخ دهیم که چرا به الگوریتم جدیدی برای دسته‌بندی نیاز داریم، آيا نمی‌توان از الگوریتم رگرسیون خطی برای این امر استفاده کرد؟ برای پاسخ به این سوال تلاش می‌کنیم تا به کمک الگوریتم رگرسیون خطی، داده‌های زیر را دسته بندی کنیم. نمودار زیر نشان‌دهنده‌ی رابطه‌ی احتمال بیمار بودن و وزن شش (۶) موش مختلف می‌باشد، به این شکل که بر روی محور عرض‌ها (y) احتمال بیمار بودن یا نبودن موش مورد نظر مشخص شده و بر روی محور طول‌ها (x) وزن موش مورد نظر به واحد گِرم (g) نمایش داده شده است. نتایج به دست آمده در آزمایشگاه نشان می‌دهند که سه موش سنگین وزن شرکت کرده در این آزمایش بیمار هستند.

شکل یک (۱): نمودار نسبت وزن به احتمال بیمار بودن در موش‌ها
شکل یک (۱): نمودار نسبت وزن به احتمال بیمار بودن در موش‌ها

حال الگوریتم رگرسیون خطی ساده را با داده‌های ارائه شده در بالا آموزش می‌دهیم و آستانه‌ی انتخاب (Threshold) را ۰/۵ در نظر می‌گیریم. آستانه‌ی انتخاب به این معنی است که اگر مدل رگرسیون خطی برای وزن یک موش، عددی بزرگتر از ۰/۵ پیش‌بینی کرد موش را بیمار در نظر می‌گیریم و اگر عددی کوچکتر از ۰/۵ را پیش‌بینی کرد موش را سالم در نظر می‌گیریم، در نمودار پایین خط نقطه‌چین مشکی نشان‌دهنده‌ی آستانه‌ی انتخاب یا مقدار ۰/۵ می‌باشد به عبارت دیگر اگر بر روی محور طول‌ها (x) از خط نقطه‌چین به سمت راست حرکت کنیم، مقدار پیش‌بینی شده بزرگتر از ۰/۵ و موش، بیمار می‌باشد، ولی اگر به سمت چپ حرکت کنیم مقدار پیش‌بینی شده توسط مدل رگرسیون خطی ساده کوچکتر از ۰/۵ و موش مورد نظر، سالم می‌باشد.

شکل دو (۲): نمودار نسبت وزن به احتمال بیماری با نمایش آستانه‌ی انتخاب (Threshold)
شکل دو (۲): نمودار نسبت وزن به احتمال بیماری با نمایش آستانه‌ی انتخاب (Threshold)

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

شکل سه (۳): نمودار نسبت وزن به احتمال بیماری که اضافه شدن موش سنگین وزن باعث خراب شدن عملکرد رگرسیون خطی می‌گردد.
شکل سه (۳): نمودار نسبت وزن به احتمال بیماری که اضافه شدن موش سنگین وزن باعث خراب شدن عملکرد رگرسیون خطی می‌گردد.


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

دو مشکل الگوریتم رگرسیون خطی ساده در دسته‌بندی، عبارتند از: ۱ـ عملکرد ضعیف و ۲ـ تولید مقادیری که تفسیر آنها مشکل است.

تابع سیگموئید

توابع سیگموئیدی به توابعی کراندار، مشتق‌پذیر و حقیقی گفته می‌شود که نمودار آنها شکل حرف s انگلیسی دارد. یکی از معروف‌ترین این توابع، تابع لجستیک می‌باشد که مدل رگرسیون لجستیک نام خود را از این تابع وام گرفته است. نمودار این تابع را در شکل زیر می‌بینیم. این تابع اعداد حقیقی در بازه‌ی (∞+،∞-) را به بازه‌ی (۰،۱) نگاشت می‌کند. این کار باعث ساده‌سازی تفسیر خروجی مدل به عنوان احتمال می‌گردد و مشکل اعداد بزرگتر از یک (۱) و کوچکتر از صفر (۰) در رگرسیون خطی را برطرف می‌سازد.

شکل چهار (۴): نمودار تابع لجستیک
شکل چهار (۴): نمودار تابع لجستیک

این تابع به کمک معادله‌ی زیر محاسبه می‌گردد.

معادله‌ی یک (۱): تابع لجستیک
معادله‌ی یک (۱): تابع لجستیک

مدل رگرسیون لجستیک

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

فرض کنید مجموعه‌ی دادگانی دارای n ویژگی (Feature) باشد، همچنین در مجموعه‌ی دادگان m داده داشته باشیم. این مجموعه داده را به شکل زیر می‌توان نشان داد.

شکل پنج (۵): نمایش مجموعه دادگان
شکل پنج (۵): نمایش مجموعه دادگان

حاصل‌جمع وزن‌دار برای هر عضو از مجموعه‌ی دادگان نشان داده شده در بالا به شکل زیر محاسبه می‌گردد.

معادله‌ی دو (۲): حاصل‌جمع وزن‌دار
معادله‌ی دو (۲): حاصل‌جمع وزن‌دار

به منظور ساده‌سازی معادلات همچنین استفاده‌ی حداکثری از توان کامپیوتر (موازی سازی) فرمول بالا را به کمک جبر خطی و به شکل برداری بازنویسی می‌کنیم. در صورتی که وزن‌ها و متغیر‌ها را به شکل دو بردار زیر نشان دهیم، حاصل‌جمع وزن دار را می‌توانیم به شکل ضرب بردار نمایش دهیم که در آن T، ترانهاده‌ی بردار می‌باشد.

معادله‌ی سه (۳): نمایش برداری وزن‌ها و متغیر‌ها
معادله‌ی سه (۳): نمایش برداری وزن‌ها و متغیر‌ها
معادله‌ی چهار (۴): نمایش برداری حاصل‌جمع وزن‌دار
معادله‌ی چهار (۴): نمایش برداری حاصل‌جمع وزن‌دار

مفهوم بایاس (Bias) و الزام استفاده از آن خارج از بحث این مطلب می‌باشد اما به طور خلاصه به منظور عملکرد بهتر مدل و یادگیری روابط پیچیده‌تر، بایاس را نیز به عبارت بالا اضافه می‌نماییم و حاصل به دست آمده را z نام‌گذاری می‌کنیم.

معادله‌ی پنج (۵): نمایش برداری حاصل‌جمع وزن دار با اضافه شدن بایاس
معادله‌ی پنج (۵): نمایش برداری حاصل‌جمع وزن دار با اضافه شدن بایاس

حاصل عبارت بالا یک بردار از اعداد حقیقی خواهد بود که آن را به عنوان ورودی به تابع لجستیک می‌دهیم، در این گفتار تابع لجستیک را با نماد σ (سیگمای کوچک) نمایش می‌دهیم.

معادله‌ی شش (۶): مدل رگرسیون لجستیک
معادله‌ی شش (۶): مدل رگرسیون لجستیک

عبارت به دست آمده در بالا مدل (فرضیه، Hypothesis، h_θ(x)) رگرسیون لجستیک می‌باشد. گفتنی‌است که حاصل به دست‌آمده از طریق تابع لجستیک یک بردار به اندازه‌ی m از اعداد در بازه‌ی (۰،۱) می‌باشد. هر عدد به دست آمده از طریق این معادله‌ (مدل) را می‌توان به صورت عبارت زیر که یک احتمال شرطی یا برشی می‌باشد تفسیر کرد. به طور مثال در مورد موشها عدد حاصل شده از مدل احتمال بیمار بودن موش، به شرط وزن آن می‌باشد.

معادله‌ی هفت (۷): تفسیر جواب رگرسیون لجستیک به کمک احتمال شرطی
معادله‌ی هفت (۷): تفسیر جواب رگرسیون لجستیک به کمک احتمال شرطی

تابع هزینه

جهت ارزیابی عملکرد مدل همچنین بهبود آن به کمک الگوریتم گرادیان‌کاهشی که در ادامه به آن می‌پردازیم باید ابتدا یک تابع هزینه تعریف کنیم. تابع هزینه‌ای که از آن استفاده میکنیم Cross Entropy Cost Function یا به اختصار CEC می‌باشد، تابع هزینه را برای رگرسیون لجستیک به شکل زیر تعریف می‌کنیم.

معادله‌ی هشت (۸): تابع هزینه‌ی رگرسیون لجستیک
معادله‌ی هشت (۸): تابع هزینه‌ی رگرسیون لجستیک


گرادیان کاهشی

مفهوم گرادیان کاهشی را در مطلب قبلی که در ویرگول پست کردم (لینک)، توضیح دادم اما به طور خلاصه باید گفت که گرادیان کاهشی یک الگوریتم بهینه سازیست که در اینجا برای کمینه (Minimize) کردن تابع هزینه از آن استفاده می‌کنیم. شبه کد گرادیان کاهشی به شکل زیر می‌باشد.

شبه کد یک (۱): شبه کد الگوریتم گرادیان کاهشی
شبه کد یک (۱): شبه کد الگوریتم گرادیان کاهشی

برای استفاده از گرادیان کاهشی، نیاز به محاسبه‌ی مشتق جزئی تابع هزینه نسبت به پارامتر θ داریم. این عملیات مشتق‌گیری نیاز به استفاده از قانون مشتق زنجیره‌ای (Chain Rule) دارد.

معادله‌ی نه (۹): عملیات مشتق گرفتن از تابع هزینه و حاصل به دست آمده از آن
معادله‌ی نه (۹): عملیات مشتق گرفتن از تابع هزینه و حاصل به دست آمده از آن

حال که همه‌ی المان‌های مورد نیاز را داریم آنها را به کد تبدیل می‌کنیم.

کد

کد قابل اجرا و کامل این مطلب را می‌توانید از این مخزن گیتهاب دریافت کنید (لینک).

مرحله‌ی اول import کردن کتابخانه‌ی numpy می‌باشد که برای انجام محاسبات ریاضی از آن کمک می‌گیریم.

کد یک (۱): وارد کردن کتابخانه‌های مورد نیاز
کد یک (۱): وارد کردن کتابخانه‌های مورد نیاز

حال داده‌ها را وارد برنامه می‌کنیم، داده‌های استفاده شده در این گفتار داده‌های مربوط به سرطان سینه هستند که در کتابخانه‌ی scikit موجود هستند. (لینک دادگان)

کد دو (۲): وارد کردن داده‌ها‌ی سرطان سینه به کمک scikit
کد دو (۲): وارد کردن داده‌ها‌ی سرطان سینه به کمک scikit

حال مجموعه دادگان وارد شده را به دو گروه test و train تقسیم می‌کنیم. ۲۵ درصد از دادگان را در مجموعه‌ی test قرار داده و بقیه را در مجموعه‌ی train همچنین اگر می‌خواهید نتایج به دست آمده در این گفتار را تکرار کنید می‌توانید random_state را برابر با مقدار 42 قرار دهید، دقت کنید که در این امر اجباری نیست.

کد سه (۳): تقسیم مجموعه دادگان به آموزش و تست
کد سه (۳): تقسیم مجموعه دادگان به آموزش و تست

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

در متد fit ابتدا ابعاد مجموعه‌ی دادگان را میگیریم و آن را در دو متغیر n_samples (تعداد اعضای مجموعه) و n_features تعداد ویژگی‌ها میریزیم. سپس به کمک کتابخانه‌ی numpy بردار theta را با مقدار صفر مقداردهی می‌کنیم.

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

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

معادله‌ی ده (۱۰): معادله‌ی گرادیان بایاس
معادله‌ی ده (۱۰): معادله‌ی گرادیان بایاس
کد چهار(۴): کلاس رگرسیون لجستیک
کد چهار(۴): کلاس رگرسیون لجستیک

حال که کلاس را داریم از آن استفاده کرده و دقت را محاسبه می‌کنیم.

کد پنج (۵): استفاده از کلاس
کد پنج (۵): استفاده از کلاس
کد شش (۶): محسابه‌ی دقت
کد شش (۶): محسابه‌ی دقت






گرادیان کاهشیرگرسیون لجستیکپیاده سازیکد
شاید از این پست‌ها خوشتان بیاید