גאוס נאיבי בייס, הסבר

גאוס נאיבי בייס, הסבר

צומת המקור: 2021431

גאוס נאיבי בייס, הסבר
אזור ההכרעה של מסווג בייס נאיבי גאוסי. תמונה מאת המחבר.

 

אני חושב שזו קלאסיקה בתחילת כל קריירת מדעי הנתונים: ה סיווג בייבס Naive. או שעדיף לומר את משפחה של מסווגים נאיביים של Bayes, שכן הם מגיעים בטעמים רבים. לדוגמה, יש Bayes נאיבי רב-נומי, Bayes נאיבי ברנולי, וגם מסווג Bayes נאיבי גאוסי, כל אחד שונה בפרט אחד קטן, כפי שנגלה. האלגוריתמים הנאיביים של Bayes הם די פשוטים בעיצובם אך הוכחו שימושיים במצבים מורכבים רבים בעולם האמיתי.

במאמר זה תוכלו ללמוד

  • איך עובדי הסיווג הנאיבי של בייס,
  • למה הגיוני להגדיר אותם כמו שהם ו
  • כיצד ליישם אותם ב-Python באמצעות NumPy.

אתה יכול למצוא את הקוד ב גיתוב שלי.

אולי זה יעזור קצת לבדוק את הפריימר שלי על סטטיסטיקה בייסיאנית מבוא עדין להסקת בייסיאנית להתרגל לנוסחת בייס. מכיוון שנטמיע את המסווגן בצורה של למידה תואמת sikit, כדאי גם לבדוק את המאמר שלי בנה רגרסיה מותאמת אישית משלך של sikit-learn. עם זאת, ה-skit-learn-overhead קטן למדי ואתה אמור להיות מסוגל לעקוב אחריו בכל מקרה.

נתחיל לחקור את התיאוריה הפשוטה להדהים של סיווג בייס הנאיבי ולאחר מכן נפנה ליישום.

מה באמת מעניין אותנו כשמסוגים? מה בעצם אנחנו עושים, מה הקלט והפלט? התשובה פשוטה:

בהינתן נקודת נתונים x, מהי ההסתברות ש-x שייך למחלקה c כלשהי?

זה כל מה שאנחנו רוצים לענות איתו כל מִיוּן. אתה יכול לדגמן ישירות הצהרה זו כהסתברות מותנית: p(c|x).

למשל, אם יש

  • כיתות 3 c₁c₂c₃, ו
  • מורכב מ-2 תכונות x₁x₂,

התוצאה של מסווג יכולה להיות משהו כמו p(c₁|x₁x₂)=0.3, p(c₂|x₁x₂)=0.5 ו p(c₃|x₁x₂)=0.2. אם אנו דואגים לתווית בודדת בתור הפלט, היינו בוחרים את התווית בעלת ההסתברות הגבוהה ביותר, כלומר c₂ עם הסתברות של 50% כאן.

הסיווג התמים של בייס מנסה לחשב את ההסתברויות הללו ישירות.

נאיביות

אוקיי, אז בהינתן נקודת נתונים x, אנחנו רוצים לחשב p(c|x) לכל הכיתות ולאחר מכן פלט את c עם ההסתברות הגבוהה ביותר. בנוסחאות אתה רואה את זה לעתים קרובות

 

גאוס נאיבי בייס, הסבר
תמונה מאת המחבר.

 

הערה: מקסימום p(c|x) מחזיר את ההסתברות המקסימלית בעוד argmax p(c|x) מחזיר את ה c עם ההסתברות הגבוהה ביותר הזו.

אבל לפני שנוכל לבצע אופטימיזציה p(c|x), עלינו להיות מסוגלים לחשב אותו. לשם כך, אנו משתמשים משפט בייס:

 

גאוס נאיבי בייס, הסבר
משפט בייס. תמונה מאת המחבר.

 

זה החלק של בייס של בייס הנאיבי. אבל עכשיו, יש לנו את הבעיה הבאה: מה הם p(x|c) ו p(c)?

זה מה שההכשרה של מסווג בייס נאיבי עוסקת.

האימון

כדי להמחיש הכל, הבה נשתמש במערך נתונים של צעצועים שתי תכונות אמיתיות x₁x₂, ו שלוש כיתות c₁c₂c₃ בהמשך.

 

גאוס נאיבי בייס, הסבר
הנתונים, חזותיים. תמונה מאת המחבר.

 

אתה יכול ליצור את מערך הנתונים המדויק הזה באמצעות

from sklearn.datasets import make_blobs X, y = make_blobs(n_samples=20, centers=[(0,0), (5,5), (-5, 5)], random_state=0)

בואו נתחיל עם ה- הסתברות כיתה p(c), ההסתברות שמחלקה כלשהי c נצפה במערך הנתונים המסומן. הדרך הפשוטה ביותר להעריך זאת היא פשוט לחשב את התדרים היחסיים של המחלקות ולהשתמש בהם כהסתברויות. אנחנו יכולים להשתמש במערך הנתונים שלנו כדי לראות מה זה אומר בדיוק.

ישנן 7 מתוך 20 נקודות המסומנות בכיתה c₁ (כחול) במערך הנתונים, לכן אנו אומרים p(c₁)=7/20. יש לנו 7 נקודות לכיתה c₂ (אדום) גם כן, לכן קבענו p(c₂)=7/20. השיעור האחרון c₃ (צהוב) יש רק 6 נקודות, ומכאן p(c₃)=6/20.

חישוב פשוט זה של הסתברויות המחלקה דומה לגישה של סבירות מקסימלית. עם זאת, אתה יכול גם להשתמש באחר קוֹדֵם הפצה, אם תרצה. לדוגמה, אם אתה יודע שמערך נתונים זה אינו מייצג את האוכלוסייה האמיתית בגלל המעמד c₃ אמור להופיע ב-50% מהמקרים, אז אתה מגדיר p(c₁)=0.25, p(c₂)=0.25 ו p(c₃)=0.5. כל מה שיעזור לך לשפר את הביצועים בסט המבחן.

כעת נפנה אל ה סְבִירוּת p(x|c)=p(x₁x₂|c). גישה אחת לחישוב סבירות זו היא לסנן את מערך הנתונים עבור דוגמאות עם תווית ולאחר מכן נסה למצוא התפלגות (למשל גאוס דו מימדי) שתופס את התכונות x₁x₂.

למרבה הצער, בדרך כלל, אין לנו מספיק דגימות לכיתה כדי לבצע הערכה נכונה של הסבירות.

כדי להיות מסוגלים לבנות מודל חזק יותר, אנו מייצרים את הנחה תמימה שהתכונות x₁x₂ יש לו עצמאי מבחינה סטוגסטית, נתון c. זו רק דרך מהודרת להקל על המתמטיקה באמצעות

 

גאוס נאיבי בייס, הסבר
תמונה מאת המחבר

 

לכל שיעור c. זה המקום בו נאיבי חלק מבייס הנאיבי מגיע מכיוון שהמשוואה הזו לא מתקיימת באופן כללי. ובכל זאת, גם אז בייס הנאיבי מניב תוצאות טובות, לפעמים יוצאות דופן בפועל. במיוחד עבור בעיות NLP עם תכונות שקיות של מילים, Bayes הנאיבי הרב-נומי זורח.

הטיעונים שניתנו לעיל זהים עבור כל מסווג Bayes נאיבי שתוכל למצוא. עכשיו זה רק תלוי איך אתה מדגמן p(x₁|c₁), p(x₂|c₁), p(x₁|c₂), p(x₂|c₂), p(x₁|c₃) ו p(x₂|c₃).

אם התכונות שלך הן 0 ו-1 בלבד, תוכל להשתמש ב-a הפצת ברנולי. אם הם מספרים שלמים, א התפלגות רב-נומית. עם זאת, יש לנו ערכי תכונה אמיתיים ומחליטים על א גאוס תפוצה, ומכאן השם Bayes נאיבי גאוס. אנו מניחים את הצורה הבאה

 

גאוס נאיבי בייס, הסבר
תמונה מאת המחבר.

 

איפה μᵢ,ⱼ הוא הממוצע ו σᵢ,ⱼ היא סטיית התקן שעלינו להעריך מהנתונים. זה אומר שאנחנו מקבלים ממוצע אחד עבור כל תכונה i יחד עם שיעור גⱼ, במקרה שלנו 2*3=6 אומר. כך גם לגבי סטיות התקן. זה מצריך דוגמה.

בואו ננסה להעריך μ₂,₁ ו σ₂,₁. כי j=1, אנחנו מתעניינים רק בשיעור c₁, הבה נשמור רק דוגמאות עם תווית זו. נותרו הדוגמאות הבאות:

# samples with label = c_1 array([[ 0.14404357, 1.45427351], [ 0.97873798, 2.2408932 ], [ 1.86755799, -0.97727788], [ 1.76405235, 0.40015721], [ 0.76103773, 0.12167502], [-0.10321885, 0.4105985 ], [ 0.95008842, -0.15135721]])

עכשיו, בגלל i=2 עלינו לשקול רק את העמודה השנייה. μ₂,₁ הוא הממוצע ו σ₂,₁ סטיית התקן עבור עמודה זו, כלומר μ₂,₁ = 0.49985176 ו σ₂,₁ = 0.9789976.

המספרים האלה הגיוניים אם מסתכלים שוב על עלילת הפיזור מלמעלה. התכונות x₂ מהדגימות מהכיתה c₁ הם בסביבות 0.5, כפי שניתן לראות מהתמונה.

אנו מחשבים זאת כעת עבור חמשת השילובים האחרים וסיימנו!

ב-Python, אתה יכול לעשות זאת כך:

from sklearn.datasets import make_blobs
import numpy as np # Create the data. The classes are c_1=0, c_2=1 and c_3=2.
X, y = make_blobs( n_samples=20, centers=[(0, 0), (5, 5), (-5, 5)], random_state=0
) # The class probabilities.
# np.bincounts counts the occurence of each label.
prior = np.bincount(y) / len(y) # np.where(y==i) returns all indices where the y==i.
# This is the filtering step.
means = np.array([X[np.where(y == i)].mean(axis=0) for i in range(3)])
stds = np.array([X[np.where(y == i)].std(axis=0) for i in range(3)])

קיבלנו

# priors
array([0.35, 0.35, 0.3 ])
# means array([[ 0.90889988, 0.49985176], [ 5.4111385 , 4.6491892 ], [-4.7841679 , 5.15385848]])
# stds
array([[0.6853714 , 0.9789976 ], [1.40218915, 0.67078568], [0.88192625, 1.12879666]])

זו התוצאה של הכשרתו של מסווג בייס נאיבי גאוסי.

להכין תחזיות

נוסחת החיזוי המלאה היא

 

גאוס נאיבי בייס, הסבר
תמונה מאת המחבר.

 

בואו נניח נקודת נתונים חדשה x*=(-2, 5) נכנס.

 

גאוס נאיבי בייס, הסבר
תמונה מאת המחבר.

 

כדי לראות לאיזו מחלקה הוא שייך, תן לנו לחשב p(c|x*) לכל הכיתות. מהתמונה, זה צריך להיות שייך לכיתה c₃ = 2, אבל בוא נראה. נתעלם מהמכנה p(x) לשנייה. שימוש בלולאה הבאה חישב את המועמדים עבור j = 1, 2, 3.

x_new = np.array([-2, 5]) for j in range(3): print( f"Probability for class {j}: {(1/np.sqrt(2*np.pi*stds[j]**2)*np.exp(-0.5*((x_new-means[j])/stds[j])**2)).prod()*p[j]:.12f}" )

קיבלנו

Probability for class 0: 0.000000000263
Probability for class 1: 0.000000044359
Probability for class 2: 0.000325643718

כמובן, אלה הסתברויות (לא צריך לקרוא להם כך) אל תצטרפו לאחד מכיוון שהתעלמנו מהמכנה. עם זאת, זו לא בעיה מכיוון שאנו יכולים פשוט לקחת את ההסתברויות הלא מנורמלות הללו ולחלק אותן בסכום שלהן, ואז הן יצטברו לאחד. אז, אם מחלקים את שלושת הערכים האלה בסכום שלהם של בערך 0.00032569, נקבל

 

גאוס נאיבי בייס, הסבר
תמונה מאת המחבר.

 

מנצח ברור, כפי שציפינו. עכשיו, בואו ליישם את זה!

יישום זה הוא עדין לא יעיל, לא יציב מבחינה מספרית, הוא משרת רק מטרה חינוכית. דנו ברוב הדברים, אז זה אמור להיות קל לעקוב עכשיו. אתה יכול להתעלם מכל check פונקציות, או קרא את המאמר שלי בנה sikit-lear מותאם אישית משלך אם אתה מעוניין במה שהם בדיוק עושים.

רק שים לב שיישמתי א predict_proba שיטה ראשונה לחישוב הסתברויות. השיטה predict פשוט קורא לשיטה הזו ומחזיר את האינדקס (=מחלקה) עם ההסתברות הגבוהה ביותר באמצעות פונקציית argmax (הנה זה שוב!). הכיתה ממתינה לשיעורים מ-0 עד k-1, איפה k הוא מספר הכיתות.

import numpy as np
from sklearn.base import BaseEstimator, ClassifierMixin
from sklearn.utils.validation import check_X_y, check_array, check_is_fitted class GaussianNaiveBayesClassifier(BaseEstimator, ClassifierMixin): def fit(self, X, y): X, y = check_X_y(X, y) self.priors_ = np.bincount(y) / len(y) self.n_classes_ = np.max(y) + 1 self.means_ = np.array( [X[np.where(y == i)].mean(axis=0) for i in range(self.n_classes_)] ) self.stds_ = np.array( [X[np.where(y == i)].std(axis=0) for i in range(self.n_classes_)] ) return self def predict_proba(self, X): check_is_fitted(self) X = check_array(X) res = [] for i in range(len(X)): probas = [] for j in range(self.n_classes_): probas.append( ( 1 / np.sqrt(2 * np.pi * self.stds_[j] ** 2) * np.exp(-0.5 * ((X[i] - self.means_[j]) / self.stds_[j]) ** 2) ).prod() * self.priors_[j] ) probas = np.array(probas) res.append(probas / probas.sum()) return np.array(res) def predict(self, X): check_is_fitted(self) X = check_array(X) res = self.predict_proba(X) return res.argmax(axis=1)

בדיקת היישום

למרות שהקוד די קצר, הוא עדיין ארוך מדי מכדי להיות בטוחים לחלוטין שלא עשינו טעויות. אז הבה נבדוק איך זה מסתדר מול ה sikit-learn GaussianNB מסווג.

my_gauss = GaussianNaiveBayesClassifier()
my_gauss.fit(X, y)
my_gauss.predict_proba([[-2, 5], [0,0], [6, -0.3]])

פלטים

array([[8.06313823e-07, 1.36201957e-04, 9.99862992e-01], [1.00000000e+00, 4.23258691e-14, 1.92051255e-11], [4.30879705e-01, 5.69120295e-01, 9.66618838e-27]])

התחזיות באמצעות ה predict השיטה הם

# my_gauss.predict([[-2, 5], [0,0], [6, -0.3]])
array([2, 0, 1])

כעת, הבה נשתמש ב-skit-learn. זורק קצת קוד

from sklearn.naive_bayes import GaussianNB gnb = GaussianNB()
gnb.fit(X, y)
gnb.predict_proba([[-2, 5], [0,0], [6, -0.3]])

תשואות

array([[8.06314158e-07, 1.36201959e-04, 9.99862992e-01], [1.00000000e+00, 4.23259111e-14, 1.92051343e-11], [4.30879698e-01, 5.69120302e-01, 9.66619630e-27]])

המספרים נראים די דומים לאלו של המסווג שלנו, אבל הם קצת פחות בספרות המוצגות האחרונות. האם עשינו משהו לא בסדר? 'מס גרסת scikit-learn פשוט משתמשת בהיפרפרמטר אחר var_smoothing=1e-09 . אם אנחנו מגדירים את זה ל אפס, אנחנו מקבלים בדיוק את המספרים שלנו. מושלם!

תסתכל על אזורי ההחלטה של ​​המסווג שלנו. סימנתי גם את שלוש הנקודות בהן השתמשנו לבדיקה. לאותה נקודה אחת קרובה לגבול יש רק 56.9% סיכוי להשתייך למעמד האדום, כפי שניתן לראות מה predict_proba תפוקות. שתי הנקודות האחרות מסווגות עם הרבה יותר ביטחון.

 

גאוס נאיבי בייס, הסבר

אזורי ההחלטה עם 3 הנקודות החדשות. תמונה מאת המחבר.

 

במאמר זה, למדנו כיצד עובד הסיווג הנאיבי גאוסי בייס ונתנו אינטואיציה מדוע הוא תוכנן כך - זוהי גישה ישירה למודל של הסתברות לעניין. השווה את זה עם רגרסיה לוגיסטית: שם, ההסתברות נבנית באמצעות פונקציה לינארית עם פונקציה סיגמואידית המוחלת עליה. זה עדיין דגם קל, אבל זה לא מרגיש טבעי כמו מסווג בייס נאיבי.

המשכנו בחישוב כמה דוגמאות ואיסוף כמה פיסות קוד שימושיות בדרך. לבסוף, יישמנו סיווג Bayes נאיבי גאוסי שלם בצורה שעובדת היטב עם scikit-learn. זה אומר שאתה יכול להשתמש בו בצינורות או בחיפוש רשת, למשל.

בסופו של דבר, עשינו בדיקת שפיות קטנה על ידי ייבוא ​​sikit-learns מסווג Bayes נאיבי גאוסי משלו ובדקנו אם שניהם, המסווג שלנו ושל sikit-learn מניבים את אותה תוצאה. בדיקה זו הצליחה.

 
 
ד"ר רוברט קובלר הוא מדען נתונים ב- Publicis Media ומחבר ב-Towards Data Science.

 
מְקוֹרִי. פורסם מחדש באישור.
 

בול זמן:

עוד מ KDnuggets