The Misgeneralization Mind – Telegram
The Misgeneralization Mind
154 subscribers
208 photos
14 videos
40 files
109 links
اینجا چیزایی که برام جالب باشه رو میذارم.

ناشناس:
https://news.1rj.ru/str/BiChatBot?start=sc-6e66d9fc9f
Download Telegram
Sampling in Inferential Statistics 📊
——————————————————————————————

نمونه‌گیری در آمار استنباطی (Sampling in Inferential Statistics) 📉

1. نمونه‌گیری تصادفی (Random Sampling) 🎲
نمونه‌گیری تصادفی یکی از روش‌های اصلی نمونه‌گیری در آمار است که در آن هر عضوی از جامعه آماری شانس برابری برای انتخاب شدن دارد. این روش کمک می‌کند تا نمونه‌ای که انتخاب می‌شود به خوبی نماینده جامعه آماری باشد و نتایج به دست آمده از تحلیل‌های آماری قابل تعمیم به کل جامعه باشد.

2. عدم تعصب (Non-Bias) 🚫
یکی از اصول مهم در نمونه‌گیری این است که نمونه باید بدون تعصب (Bias) انتخاب شود. تعصب می‌تواند نتایج تحقیق را تحریف کند و باعث شود که نتایج به دست آمده دقیق نباشند. برای جلوگیری از تعصب:
- نمونه‌گیری تصادفی انجام شود.
- فرآیند نمونه‌گیری به دقت طراحی شود تا هیچ گروه یا دسته‌ای از جامعه آماری نادیده گرفته نشود.

3. حداقل حجم نمونه (Minimum Sample Size) 📏
حداقل حجم نمونه (Minimum Sample Size) به تعداد حداقل نمونه‌هایی که برای انجام تحلیل‌های آماری معتبر نیاز است، اشاره دارد. تعیین حجم نمونه به عوامل مختلفی بستگی دارد:
- اندازه جامعه آماری (Population Size)
- سطح اطمینان (Confidence Level) که معمولاً 95% یا 99% انتخاب می‌شود.
- حاشیه خطا (Margin of Error) که معمولاً بین 1% تا 5% تنظیم می‌شود.
- انحراف معیار (Standard Deviation) یا واریانس (Variance) داده‌ها که اگر پیش از این مشخص باشد، کمک می‌کند.

نکات کلیدی 🗝

- نمونه‌گیری تصادفی ساده (Simple Random Sampling) 🎲: یکی از ساده‌ترین و رایج‌ترین روش‌های نمونه‌گیری که در آن هر عضو جامعه آماری به صورت تصادفی و با شانس برابر انتخاب می‌شود.

- نمونه‌گیری سیستماتیک (Systematic Sampling) 📐: یکی دیگر از روش‌های نمونه‌گیری که در آن هر nامین عضو جامعه آماری انتخاب می‌شود.

- نمونه‌گیری طبقه‌بندی شده (Stratified Sampling) 🧩: زمانی استفاده می‌شود که جامعه آماری به زیرگروه‌های همگن تقسیم شده و سپس نمونه‌گیری از هر زیرگروه به صورت تصادفی انجام می‌شود.

- نمونه‌گیری خوشه‌ای (Cluster Sampling) 🏢: زمانی استفاده می‌شود که جامعه آماری به خوشه‌های ناهمگن تقسیم شده و سپس برخی از این خوشه‌ها به صورت تصادفی انتخاب و از همه اعضای خوشه‌های انتخاب شده نمونه‌گیری می‌شود.
رابطه علت و معلول بین داده ها، با استفاده از Inferetial Statistics انجام میشه.

A/B Test 📉
——————————————————————————————

📈 در AB Test وقتی جامعه آماری را به دو گروه مساوی تقسیم کردیم، بعد از انجام آزمایش مدنظر، از هر دو گروه میانگین میگیریم. تفاضل میانگین دو گروه عددی میشود که اون رو d در نظر میگیریم (مثلا تاثیر دارو بر گروه B). حال اینکه چقدر اون تاثیر (همان d) بر اساس شانس هست، میشه مقدار P value. (در واقع، داده ها رو شافل میکنیم و مثلا برای هزار بار آزمایش رو تکرار میکنیم، بعد چک میکنیم که چند بار این اعداد رندوم بزرگتر مساوی عدد d بوده. نتیجه بدست آمده میشه مقدار P value)

🖍 معمولا یک حد آستانه (Treshold) برای P value در نظر میگیریم. معمولا 5 درصد گرفته میشه. اگر P value ما زیر 5 درصد شد، قبول میکنیم. در غیر این صورت میگیم که به شواهد کافی برای تایید ادعای مطرح شده نرسیدیم. هر چقدر مقدار P value پایین تر باشه بهتر هست.

T Test 📑
——————————————————————————————

🔸 آزمون T، دو شرط دارد. داده هایی که داریم باید توزیع نرمالی داشته باشند و داده ها نمونه ای از داده کل باشند. برای فهمیدن اینکه داده ها نرمال هستن یا نه، میتونیم از نمودار histogram استفاده کنیم.

🟣 ما سه نوع T Test داریم:
- One Sample
❗️ مقایسه یک نمونه با جامعه کل.
import scipy.stats as stats
stats.ttest_1samp(a=df['oranges'], popmean=population_mean)


- Independent TTest (Two Sample)
برای وقتی هست که ما دو مجموعه مجزا از هم داریم، و این دو مجموعه شرایط TTest رو دارن (پیروی از توزیع نرمال، نمونه ای از کل هستند).
stats.ttest_ind(a=df_ielts_98['ielts'], b=df_ielts_99['ielts'])


- Relative TTest
❗️ برای وقتی هست که دو گروه ما به همدیگر وابسته هستند.
stats.ttest_rel(a=df['weight_before'], b=df['weight_after'])



❇️ میتونیم از داده های غیر نرمال، لگاریتم بگیریم و سپس T Test رو انجام بدیم. یا کلا روی همون داده های غیر نرمال از MannWithnyUTest استفاده کنیم.


⁉️ تست شاپیرو (Shapiro): شاپیرو، داده های ما رو با توزیع نرمال ایده آل خودش مقایسه میکنه، و اختلاف اونهارو بررسی میکنه. حال هر چقدر P value پایینتر بشه، نشون میده داده ها از توزیع نرمالی که مد نظر شاپیرو بوده، اختلاف معنا دار تری داشته. اگر این اختلاف معنا دار نباشه، میگیم که احتمالا نرمال هست. (اگر Shapiro Test انجام بدیم و مقدار P value زیر 5 درصد بشه، داده ها نرمال نیست).

💡 نمودار Probplot: داده ها رو با توزیع نرمال مقایسه میکنه. روی نمودار، هر چقدر داده های ما (نقاط آبی رنگ) به خط قرمز نزدیک تر باشند یعنی داده ما بیشتر به داده های نرمال شبیه هست.
stats.probplot(data, dist='norm', plot=pylab)


🔑 دو مورد آخر (تست شاپیرو، Probplot) برای اینه که بفهمیم داده ها از توزیع نرمال پیروی میکنند یا خیر.
🔻 توزیع binomial (دو جمله ای)، یک مقدار n (تعداد تکرار آزمایش) و مقدار k (تعداد نمونه) و p (نرخ برد) از ما دریافت میکند و به طول n بازی انجام میدهد. در هر بازی، kتا خونه میسازه که داخلش یا 0 یا 1 قرار داره. (0 یعنی شکست، 1 یعنی پیروزی).

⁉️ از کجا متوجه میشه در یک خانه 0 بزاره یا 1؟ به p نگاه میکند. هر بار یک عدد رندوم وابسته به p میسازه و به احتمال p، داخل خونه مقدار 1 میاد، و به احتمال یک منهای p صفر میاد.


📌 تست خی (Chi Squared Test)
ct = pd.crosstab(data['Attrition'], data['JobSatisfaction'], margins=True)

obs = np.append(ct.iloc[0][: -1].values, ct.iloc[1][: -1].values)

exp = []
for j in range(2):
for val in ct.iloc[2, : -1].values:
print(val, ' * ', row_sum[j], ' / ', ct.loc['All', 'All'], ' = ', val * row_sum[j] / ct.loc['All', 'All'])
exp.append(val * row_sum[j] / ct.loc['All', 'All'])

((obs - exp) ** 2 / exp).sum()


📐 بعد از بدست آوردن عدد Chi که در کد بالا، آخرین خط این کار را میکند، باید این عدد را در Chi-Squared Table بگذاریم. (بسته به مقدار k، نمودار chi متفاوت میشه).

🧮 عدد k همان dof یا درجه آزادی میباشد. نحوه محاسبه dof:
dof = (len(row_sum) - 1) * (len(ct.iloc[2, :-1].values) - 1)


محاسبه p value در آزمون Chi:
1 - stats.chi2.cdf(((obs - exp) ** 2 / exp).sum(), dof)


🔎 اگر مقدار p value زیر treshold بشه میگن که اون دو متغیر با هم در ارتباط هستند.

✳️ کد آماده تابع chi square در Scipy موجود هست، فقط کافیه مقدار obs رو بهش بدیم.
📊 پیش پردازش (preprocessing) مجموعه فعالیت هایی هست که روی مجموعه داده های در اختیارمون انجام میدیم، تا بتونیم اونهارو برای الگوریتم های یادگیری آماده کنیم.

🖌 برای پیش پردازش باید داده ها رو به فضای R^n تبدیل کنیم. یعنی متغیرهای مستقل داخل فضای R^n قرار بگیرند. پیش پردازش ها روش های زیادی دارند، اما باید سه تا کار رو حتما روی داده ها انجام بدیم. اون سه کار عبارت اند از:

🔻 حذف missing valueها.
🔺 اگر categorical بود، اونهارو عددی کنیم.
🔻 باید scale ستون ها رو یکی کنیم.

🔹 اگر یک یا چند مقدار در داده ها موجود نیست (null یا nan)، باید یه کاری براش انجام بدیم. چند روش برای هندل کردن این مشکل وجود داره:

- بجای مقدار خالی، یه عدد معقول قرار بدیم. (Constant)
- میانگین اون ستون رو به عنوان مقدار خالی بزاریم. (Mean / Trimmed Mean / Median)
- مقداری که بیشتر از همه تکرار شده رو قرار بدیم. (Most Frequent)
- استفاده از Random Select یا انتخاب تصادفی.
- حذف کلی سطر دارای مقدار خالی. (Remove)
- نزدیکترین همسایه (KNN).

🟣 منظور از همسایگی در KNN این نیست که به عنوان مثال مقدار مد نظر در سطر بالایی یا پایینی رو برای اون مقدار خالی قرار بدیم. در این روش سطری که از لحاظ مقادیر شباهت بیشتری داره رو انتخاب میکنه و مقدار مورد نظر رو از اون بر میداره و در جای خالی سطر قرار میده.

🔸 یکی از مشکلات قرار دادن میانگین به جای مقادیر خالی، اینه که توزیع داده ها بهم میخوره. در پیش پردازش باید حواسمون جمع باشه که توزیع داده ها رو عوض نکنیم.

🟩 روش های عددی کردن ستون های Categorical:

- روش های ابتکاری heuristic
- روش OHE: هر کدوم از مقادیر Categorical یک ستون رو تبدیل به یک ستون میکنه و با توجه به مقدار در ستون اصلی، یکی از ستون های جدیدا ایجاد شده مقدارش برابر 1 و مابقی 0 در نظر گرفته میشن.

🔹 ستونی عددی هست که در اون بزرگتر و کوچکتر و جمع تفریق معنا بده، مثل سن. مثلا ستون کد پستی یا کد ملی عددی نیست.

🟥 روش هایی برای اینکه تمامی ستون ها در یک بازه قرار بگیرند (Scaling):

- محاسبه ماکسیموم هر ستون، و تقسیم کردن هر عدد بر ماکسیموم ستون خودش. (Max Norm)
- هر عدد رو منهای مینیموم ستون خودش بکنیم، سپس تقسیم بر ماکسیموم ستون خودش منهای مینیموم ستون خودش بکنیم. (MinMax Norm)
- هر عدد منهای میانگین ستون خودش، تقسیم بر انحراف استاندارد ستون خودش. (Standard Scaler یا Z Scaler)
- هر عدد منهای median ستون خودش، تقسیم بر چارک سوم منهای چارک اول (Robust Scaler)

❗️ یکی از مشکلات روش Max Norm مخرج صفر هست. اعداد منفی هم مشکل این روش هستند.
📍 جداسازی تارگت (متغیر وابسته) و متغیرهای مستقل
X = data.iloc[:, :-1].values
y = data.iloc[:, -1].values
📚 کتابخانه Scikit-learn یکی از معروف ترین کتابخانه های حوزه ماشین لرنینگ هست.

🔸 پکیج SimpleImputer وظیفه پر کردن داده های missing رو بر عهده دارد.
from sklearn.impute import SimpleImputer
▫️ استفاده از پکیج SimpleImputer و روش پر کردن مقادیر خالی با mean ستون مد نظر (برای روش میانگین باید حتما دیتا تایپ ستون عددی باشد)
si = SimpleImputer(missing_values=np.nan, strategy='mean')
si.fit(X[:, 1:])
X[:, 1:] = si.transform(X[:, 1:])
🔴 منظور از fit کردن اینه که محاسبات مورد نیاز رو بر روی داده ها انجام بده. سپس محاسبات انجام شده رو در متغیر si ذخیره کن و در نهایت روی همون داده هایی که داریم اعمال کن (transform).

✳️ معمولا fit یکبار انجام میشه و transform برای n بار انجام میشه.

📥 ذخیره متغیر si در هارد دیسک:
import pickle

with open('si.h5', 'wb') as f:
pickle.dump(si, f)
📃 خواندن متغیر ذخیره شده در هارد دیسک توسط پکیج pickle:
with open('si.h5', 'rb') as f:
si2 = pickle.load(f)
🔍 استفاده از روش OHE برای عددی کردن ستون مد نظر (به هر کدوم از مقادیر یک عدد نسبت میده):
from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
X[:, 0] = le.fit_transform(X[:, 0])

با اینکار درواقع ستون عددی نشده و فقط یک لیبل عددی بهش نسبت داده شده. یعنی جمع و تفریق و بزرگتر کوچکتر معنی نداره. برای عددی کردن میتونیم از روش زیر استفاده کنیم.

🔻 استفاده از OHE و Column Transformer:
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer

ct = ColumnTransformer([('Country', OneHotEncoder(), [0])], remainder='passthrough')
X = ct.fit_transform(X)

* نام country دلخواه هست و هر چیزی میتونه باشه


🔸 مرحله آخر، Scaling داده ها. (استفاده از روش Standard Scaler)
from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
X = ss.fit_transform(X)


🔹 کار بر روی داده های واقعی تر (داده های دیابت افراد)

- نام گذاری برای داده هایی که ستون های آن بدون نام است:
data = pd.read_csv('pima-indians-diabetes.csv', names=['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'])


- بدست آوردن میانگین زخامت پوست و جایگذاری مقدار به جای null valueها:
skin_mean = data[data['skin'] != 0]['skin'].mean()
data.replace({'skin': 0}, skin_mean, inplace=True)


🟣 چون تعداد سطرهایی که مقدار skin اونها 0 بود خیلی زیاد بود، توزیع داده ها بعد از قرار دادن میانگین بجای مقادیر 0 بهم ریخت و kurtosis خیلی زیاد شد. برای رفع این مشکل میتونیم از روش هایی مثل KNN یا random استفاده کنیم.

- جایگذاری مقادیر null با استفاده از روش random:
data['skin'] = data['skin'].apply(lambda x: np.random.choice(data[data['skin'] != 0]['skin']) if x == 0 else x )


- استفاده از روش KNN (دنبال سه تا از نزدیک ترین همسایه ها بر اساس ویژگی ها میگرده):
from sklearn.impute import KNNImputer

data.replace({'test': 0, 'skin': 0}, np.nan, inplace=True)

imputer = KNNImputer(n_neighbors=3)
data = imputer.fit_transform(data)


⚠️ توجه: ستون تارگت در روش های بالا جدا نشده و اشتباه است. اگر قصد داشتیم مقادیر null رو درست کنیم قبلش حتما ستون تارگت و ستون های مستقل رو باید جدا کنیم.

⭕️ استفاده از MinMaxScaler برای scale کردن داده ها.
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(0, 1))
data = scaler.fit_transform(data)


‼️ استفاده از StandardScaler برای scale کردن مجدد داده ها.
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
data = scaler.fit_transform(data)


✳️ چند بار scale کردن داده ها تاثیر چندانی نداره و تقریبا بی فایده س. همینکه یبار scale کنیم کافیه.

▫️ نرمال سازی با استفاده از روش L2Normalizer. (در هر سطر اعداد رو به توان 2 میرسونه، باهم جمع میکنه و درنهایت ازشون رادیکال میگیره. سپس هر کدوم از اعداد رو تقسیم بر L2 سطر خودش میکنه)
from sklearn.preprocessing import Normalizer
norm = Normalizer()
data = norm.fit_transform(data)


🔴 اگر داده ها صفر زیادی دارن، میتونیم از L2Normalizer استفاده کنیم و برای این نوع ماتریس ها مناسب میباشد.
🖍 در پیش پردازش داده بعضی ستون ها که چیز خاصی ارائه نمیدن و اهمیت ندارن رو میتونیم حذف کنیم. مثل loan id در دیتاست Loan Data.

📆 برای ستون هایی مثل loan start و loan end که تاریخ رو ثبت کردن، میتونیم تفاضل اونها رو بدست بیاریم و سپس داخل یک ستون ذخیره کنیم.
df['loan_start'] = pd.to_datetime(df['loan_start'], format = '%Y-%m-%d')
df['loan_end'] = pd.to_datetime(df['loan_end'], format = '%Y-%m-%d')


✳️ بهتره که ستون تارگت رو به تایپ Category تبدیل کنیم. ستون هایی رو هم که احتیاج نداریم رو میتونیم به Object تبدیل کنیم.
df['loan_id'] = df['loan_id'].astype('object')
df['repaid'] = df['repaid'].astype('category')


🟣 یسری از ستون ها داده هایی به عنوان outlier یا noise دارند. داده هایی که بیشتر از 1.5 برابر IQR یا کمتر از 1.5 برابر IQR باشن رو به عنوان داده نویز میشناسیم.
* IQR: Q3 - Q1

🔸 مینیموم و ماکسیموم غیر نویز در داده ها:
min' (LC): Q1 - IQR * 1.5
max' (UC): Q3 + IQR * 1.5

🔻 بدست آوردن چارک اول و سوم و...:
Q1 = df3.rate.quantile(0.25)
Q2 = df3.rate.quantile(0.50)
Q3 = df3.rate.quantile(0.75)
IQR = Q3 - Q1
LC = Q1 - (1.5*IQR)
UC = Q3 + (1.5*IQR)


💭 گرفتن جذر ستون rate:
df['SQRT_RATE'] = df['rate']**0.5
or
df['sqrt_rate'] = np.sqrt(df['rate'])


🟢 با جذر گرفتن یا لگاریتم، چولگی رو نرمال میکنیم و به توزیع نرمالی تبدیل میشن. اینکار روی outlier ها هم تاثیر دارد.

🔹 داده های outlier رو میتونیم حذف کنیم ولی بخاطر از دست دادن داده ها اینکارو نمیکنیم. مقادیر ستونی که در اونها outlier هست رو سرکوب میکنیم. یا مقدارش رو به سه برابر انحراف استاندارد بزرگتر از میانگین تبدیل میکنیم یا به سه برابر انحراف استاندارد کوچکتر از میانگین.
🤖 یادگیری ماشین
——————————————————————————————

💡 الگوریتم درخت تصمیم (Decision Tree)
from sklearn.tree import DecisionTreeClassifier

dtree = DecisionTreeClassifier()
dtree.fit(df, y)

dtree.predict([
[1.1, 1.8, 1.2, 0.2],
[8.1, 2.1, 2.5, 2.9]
])


🔹 فرمول entropy به ما میگه توی هر کدوم از ستون ها چقدر اطلاعات نهفته شده است. ستونی که بیشترین اطلاعات داره رو انتخاب میکنه و روی اون ستون مقادیر مختلف رو امتحان میکنه. و چک میکنه کدام مقدار توی سطر بعدی درخت مقدار gini کمینه میشه و همون رو انتخاب میکنه.
import pandas as pd
import numpy as np

data = df

def entropy(column):
counts = column.value_counts()
probabilities = counts / counts.sum()
entropy = -np.sum(probabilities * np.log2(probabilities))
return entropy

entropies = {}
for column in data.columns:
entropies[column] = entropy(data[column])

print(entropies)


🟨 الگوریتم Decision Tree از فرمول entropy استفاده میکنه.

⁉️ نقاط ضعف الگوریتم Decision Tree:
- الگوریتم خیلی ساده ای هست.
- مشکل overfit شدن داره. چون الگوریتم خودش رو خیلی شبیه به داده های آموزشی کرده، این مشکل رخ میده.

🔍 برای اینکه الگوریتم Decision Tree مشکل overfit شدن نداشته باشه، میتونیم برای ارتفاع درخت یه حدی مشخص کنیم. مثلا اگه gini زیر 10 شد دیگه ادامه ندیم.
⭕️ مسائلی که یک تارگت دارن و یکسری عناصر مستقل دارند رو مسائل classification میگویند.

🤖 الگوریتم SVM یا Support Vector Machinge (ماشین بردار پشتیبان)

🔸 این الگوریتم یکسری بردار میکشه که این بردارها فضا رو با توجه به نمونه ها تفکیک میکنه. یکی از مشکلات SVM اینه که وقتی فضا پیچیده میشه، کشیدن بردارها سخت میشود.

🔹 سرعت کم در یادگیری یکی دیگر از مشکلات SVM هست. این الگوریتم میتونه داده های نویز رو با کیفیت بالا شناسایی کنه.
from sklearn.svm import SVC

svm_classifier = SVC(random_state=3432, C=0.5)
*پارامترهای تابع SVC اجباری نیست و میتونیم ندیم.
svm_classifier.fit(X, y)


🔴 استفاده از metrics برای evaluation (ارزیابی) کردن الگوریتم:
from sklearn import metrics

p = svm_new.predict(X[1000:])
e = y[1000:]
print(metrics.classification_report(e, p))


🔸 جدول Confusion (درهم ریختگی): این جدول دو سطر و دو ستون دارد. سطرها نشون دهنده expected و ستون ها نشون دهنده predict. در e یک سطر yes و یک سطر no داریم. در p هم یک ستون yes و یک ستون no.

🔻 فرمول بدست آوردن دقت (Accuracy) از طریق جدول Confusion:
(TP + TN) / (TP + FN + TN + FP)

- این فرمول برای هر لیبل محاسبه میشه. در این فرمول چون TN همیشه عدد بزرگی هست جواب نهایی رو به سمت خودش میکشونه.

⭕️ به همین خاطر بجای accuracy دو فرمول دیگه ارائه دادن:
- Percision (صحت): TP / TP + FP
- Recall (پوشش): TP / TP + FN

✳️ در بعضی مسائل صحت، و در بعضی مسائل پوشش مهم است. به همین خاطر ترکیبی از این دو به نام F1 به وجود اومد.
- F1: (2 * Percision * Recall) / (Percision + Recall)

⁉️ روش های بهبود دقت الگوریتم:
- افزایش نمونه ها
- افزایش تعداد ویژگی ها (ستون ها)
- تغییر الگوریتم
- تغییر پارامترهای الگوریتم

🤖 الگوریتم K NeighborsClassifier (KNN): این الگوریتم میاد نمونه هایی که روی فضای اقلیدسی داریم رو ذخیره میکنه. وقتی نمونه جدیدی وارد شد، فاصله اون نمونه با تمامی نمونه های دیگه رو پیدا میکنه و K تا نزدیکترین همسایه (k یک عدد دلخواه است) رو به این نمونه جدید بر میگردونه. لیبل اکثریت همسایه ها هرچیزی بود، اون نمونه جدید هم همون مقدار رو میگیره.

🔧 این الگوریتم عملا مدلی نمیسازه و فقط مدل ها رو ذخیره میکنه. به الگوریتم KNN، الگوریتم تنبل یا Lazy میگن چون مدلی نمیسازه.

from sklearn.neighbors import KNeighborsClassifier

knn_clf = KNeighborsClassifier(n_neighbors = 5)
knn_clf.fit(X[:1000], y[:1000])

p = knn_clf.predict(X[1000:])
e = y[1000:]

print(metrics.classification_report(e, p))
⚙️ الگوریتم های ترکیبی
————————————————————————————
🔮 الگوریتم Random Forest (جنگل تصادفی): در این الگوریتم، مثلا سه تا درخت تصمیم میسازه به اسم های A و B و C. سپس زیرمجموعه ای از ستون ها رو میده به درخت A و مدل A ساخته میشه. زیر مجموعه دیگه ای به درخت B داده میشه و مدل B ساخته میشه. زیر مجموعه ای از ستون ها هم به درخت C داده میشه و مدل C رو ایجاد میکنه. ازین به بعد که مدل جدیدی اومد، ستون هایی که داده بودیم به درخت A رو میدیم به مدل A، ستون هایی که به B داده بودیم رو میدیم به مدل B و ستون هایی که داده بودیم به درخت C رو میدیم به مدل C.

🗳 سپس رای گیری انجام میده و بررسی میکنه کدوم لیبل به نسبت بقیه بیشتر تکرار شده. پس اون لیبل رو به عنوان لیبل نهایی بر میگردونه.

- از مشکلات این الگوریتم، محاسبات زیاد است.

from sklearn.ensemble import RandomForestClassifier

rfc_clf = RandomForestClassifier(n_estimators=1000, bootstrap=True, oob_score=True)
rfc_clf.fit(X[:1000], y[:1000])

p = rfc_clf.predict(X[1000:])
e = y[1000:]
print(metrics.classification_report(e, p))


📐 الگوریتم های ترکیبی به داده های زیاد و ستون های زیادی نیاز دارند.


🤖 الگوریتم Adaboost: شبیه به RF است، یسری تفاوت های ریز دارد. در این الگوریتم هنگام train میفهمه کدوم مدل ها قوی تر هستن و موقع رای گیری به اون مدل ها ارزش بیشتری میده.
from sklearn.ensemble import AdaBoostClassifier
from sklearn.svm import SVC

ada_clf = AdaBoostClassifier(base_estimator=SVC(probability=True, kernel='rbf'), n_estimators=100)
ada_clf.fit(X[:1000], y[:1000])

p = ada_clf.predict(X[1000:])
e = y[1000:]
print(metrics.classification_report(e, p))
🧭 بهتره که سطرهای مجموعه داده رو ابتدا shuffle کنیم، سپس اونهارو به دو بخش train و test تقسیم کنیم.

💢 استفاده از الگوریتم KNN با روش گفته شده:
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=300)

clf = KNeighborsClassifier(n_neighbors=5)
clf.fit(X_train, y_train)

y_pred = clf.predict(X_test)
print(metrics.classification_report(y_test, y_pred))


استفاده از الگوریتم SVM با روش گفته شده:
clf = SVC(C=15, kernel="linear", random_state=3244)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
print(metrics.classification_report(y_test, y_pred))


با استفاده از GridSearch میتونیم هایپر پارامترهای مختلف رو بر روی الگوریتم تست کنیم و بهترینش رو پیدا کنیم.
from sklearn.model_selection import GridSearchCV

params = {
'C': [1, 5, 10, 15],
'kernel': ['linear'],
'gamma': ['auto', 0.1, 0.5]
}

gsh = GridSearchCV(SVC()), param_grid=params, scoring='accuracy', cv=2, n_jobs=-1, verbose=10)

gsh.fit(X, y)


⁉️ یکی از مشکلات GridSearch، محاسبات سنگینی هست که انجام میده.

💠 برای حل مشکل شافل کردن داده ها بصورت معمولی، از Cross Validation استفاده میکنیم. CV داده ها رو اول شافل میکنه، سپس داده ها رو به مقدار فرستاده شده به CV تقسیم میکنه. مثلا اگر CV=3 داده ها به سه قسمت مساوی تقسیم میشوند. سپس یبار داده ها رو روی دو قسمت اول train میکنه و روی قسمت سوم test میکنه. یبار دیگه روی قسمت یک و سه عملیات train رو انجام میده و روی قسمت دو test میکنه. و... . در نهایت از دقت ها میانگین میگیره و دقت نهایی الگوریتم رو مشخص میکنه. (K-Fold Cross Validation)


🤖 الگوریتم XGBoost: جزو الگوریتم های ترکیبی میباشد. مثل Random Forest کار میکنه منتها با استفاده از یکسری تکنیک ها اون رو تقویت کرده. یکی از خوبی های این الگوریتم اینه که میتونه روی کارت گرافیک هم کار کنه.
🔸 در مواردی که ستون تارگت عددی باشد، مسئله بجای classification از نوع regression میباشد.

▫️ جایی که تارگت عددی پیوسته بود مسئله از نوع Regression، و جایی که تارگت عدد غیر پیوسته بود مسئله از نوع Classification میباشد.

🔹 برای مثال در الگوریتم KNNR، لیبل نمونه جدید میانگینی میشه از kتا همسایه نزدیک به خودش.

🔻 الگوریتم CatBoost مثل XGBoost و RF کار میکنه، منتها نیاز به هایپرپارامتر tuning نداره. همچنین برای ویژگی های Categorical کافیه که شماره ش رو بهش بدیم تا OHE رو انجام بده.
!pip install -U catboost

▫️ اگر اکثریت داده ها در یک نقطه جمع شده باشن، الگوریتم بایاس پیدا میکنه به حالتی که تجمیع داده صورت گرفته. بهتره که داده های ستون تارگت وقتی به الگوریتم Regression میخواد داده بشه از توزیع نرمالی پیروی کنه. اگه روی داده ها sqrt یا log اعمال کنیم توزیع نرمال میشه. بعد از اینکه الگوریتم یاد گرفت و پیش بینی کرد، باید معکوس تابع رو (به توان رسیدن) اعمال کنیم.

from catboost import CatBoostRegressor
from sklearn.model_selection import train_test_split

model = CatBoostRegressor(iterations=120, learning_rate=0.05, depth=6, eval_metric='MAE', verbose=10)

X = data_train.drop(['id', 'loss'], axis=1)
y = np.log(data_train['loss'])
X_train, X_test, y_train, y_test = train_test_split(X, y)

model.fit(X_train, y_train, np.asarray(cat_index) - 1, eval_set=(X_test, y_test))



✳️ دسته مسائل Classification و Regression در دسته بندی Supervised Learning قرار میگیرند. یعنی در این مسائل ما تارگت داریم. اگر ستون تارگت نداشته باشیم مسائل به زیر حوزه Unsupervised Learning مربوط میشن.

⭕️ در حوزه Unsupervised میتونیم از الگوریتم های Clustering یا خوشه بندی استفاده کنیم. این الگوریتم ها میتوانند داده ها رو به گروه های شبیه به هم تقسیم کنند.

❇️ الگوریتم های حوزه خوشه بندی:

- الگوریتم K-Means: این الگوریتم داده ها رو دریافت میکنه و نمونه هایی که بهم نزدیک باشند رو میندازه داخل یک گروه. فقط در ابتدای کار تعداد گروه های نهایی رو از ما میخواد. این الگوریتم در مثال یسری ضربدر رنگی روی جاهای مختلف میزنه و هر نمونه ای که به اون ضربدر نزدیک تر باشه رو جزو اون گروه میگیره. سپس اون ضربدرها رو میبره به مرکز نمونه های خودش. بعد دسته ها پاک میشه و مجددا هر کدوم از نمونه ها به ضربدرهای موردنظر نزدیک تر باشند توی یک دسته قرار میگیرند. و همین کار رو چندین مرتبه تکرار میکنه تا توی دور های آخر نمونه هایی که به ضربدرها نزدیک تر باشن همون رنگ ضربدر رو به خودشون بگیرن. الگوریتم وقتی بفهمه همگرا شده دیگه ادامه نمیده.

⁉️ الگوریتم K-Means دو مشکل اساسی داره. مشکل اول سرعت الگوریتم هست. سرعت هرچقدر مجموعه داده ها بیشتر بشه کند میشه. مشکل بعدی انتخاب تعداد k هست.

- الگوریتم DBSCAN: این الگوریتم خودش تعداد خوشه ها رو حساب میکنه. فقط دو پارامتر دارد، یکی اپسیلون و یک min points. میاد اول یکی از نمونه ها رو به صورت تصادفی انتخاب میکنه و به اندازه اپسیلون، یک شعاع روی اون میزنه و چک میکنه توی شعاع زده شده، حداقل به اندازه mp نمونه وجود داره یا نه. این کار رو انقدر برای همسایه ها ادامه میده تا تمام نمونه هایی که نزدیک به هم هستند توی یه خوشه بیفتن. این الگوریتم نمونه هایی که توی هیچ خوشه ای نیفتادن رو به عنوان outlier شناسایی میکنه.

🔸 یکی از نقاط ضعف الگوریتم DBSCAN اینه که نمیشه پارامترها رو راحت مشخص کرد.

💭 در بازاریابی متدی داریم به اسم RFM. کلمه R یعنی Recency (آخرین زمانی که مشتری خرید کرده)، کلمه F یعنی Frequency (تعداد دفعات خرید مشتری از ما) و کلمه M یعنی Monetary (مجموع مبلغی که مشتری از ما خرید کرده).
🔔 روش Q Cut: در این روش، مقادیر یک ستون رو از کوچک به بزرگ مرتب میکنه، و به q قسمت مساوی تقسیم میکنه (مثلا q=4). هر کدوم از داده ها توی قسمت اول افتاده باشن، بجای عددشون یک میزاره. اونهایی که توی قسمت دوم افتاده باشن بجای عددشون دو میزاره و... . به قولی داده ها رو scale میکنه در بازه یک تا چهار.
r_labels = range(4, 0, -1) #[4, 3, 2, 1]
r_groups = pd.qcut(rfm['Recency'], q=4, labels=r_labels)
f_labels = range(1, 5) # [1, 2, 3, 4]
f_groups = pd.qcut(rfm['Frequency'], q=4, labels=f_labels)
m_labels = range(1, 5)
m_groups = pd.qcut(rfm['Monetary'], q=4, labels=m_labels)

rfm['R'] = r_groups.values
rfm['F'] = f_groups.values
rfm['M'] = m_groups.values


🟡 دلیل اینکه ستون R رو بر عکس عدد دادیم (از 4 به 1) اینه که مشتری که تازه خرید کرده ارزش بیشتری برامون داره.

X = rfm[['R', 'F', 'M']]
kmeans = KMeans(n_clusters=5, init='k-means++', max_iter=300)
kmeans.fit(X)

rfm['kmeans_cluster'] = kmeans.labels_


🔹 وقتی که خوشه بندی کردیم، روی اونها مدل های Classification پیاده سازی میکنیم که داده ها رو صحت سنجی یا evaluate کنیم.
⁉️ از روش elbow استفاده میکنیم که بفهمیم خوشه بندی مون خوب هست یا نه، و آیا تعداد خوشه ها مناسبه یا خیر.

✳️ مفهوم inertia (wcss): فاصله هر نمونه رو با مرکز خوشه خودش بدست میاره، و همه اون مقادیر رو باهم جمع میکنه. فاصله بدست اومده رو به توان دو میرسونه. عدد inertia باید متناسب باشد.

🔹 الگوریتم HDBSCAN: مثل همون DBSCAN است منتها به صورت سلسله مراتبی خوشه بندی رو انجام میده. یکی از خوبی های این الگوریتم اینه که خیلی احتیاج نداریم مقدار اپسیلون یا mp رو تشخیص بدیم.

‼️ الگوریتم DBSCAN بعضی از نمونه ها که نتونن در هیچ خوشه ای جای بگیرن رو 1- میده، یعنی اونها داده های outlier هستند.

معیار silhouette چیست؟ در این معیار تراکم درون هر خوشه اهمیت دارد (تراکم درونی خوشه ها). همچنین فاصله خوشه ها از همدیگر تا جای ممکن زیاد باشد. silhouette عددی بین 1- تا 1 برمیگردونه. اگر به 1- نزدیک باشه، یعنی خوشه هایی که ساختیم خوب نیستند و اگر عدد برگردونده شده نزدیک به 1 باشه یعنی خوشه ها خوب هستند. اگر عدد به 0 نزدیک باشد، یعنی خوشه ها مقداری به همدیگر نزدیک هستند. مقدار silhouette معمولا باید بالای 0.3 باشه که بگیم خوشه های خوبی ساختیم.


🔸 دسته الگوریتم های Outlier Detection:

- DBSCAN
- ABOD
- Isolation Forest
- OneClass SVM
- LOF
The Misgeneralization Mind
⁉️ از روش elbow استفاده میکنیم که بفهمیم خوشه بندی مون خوب هست یا نه، و آیا تعداد خوشه ها مناسبه یا خیر. ✳️ مفهوم inertia (wcss): فاصله هر نمونه رو با مرکز خوشه خودش بدست میاره، و همه اون مقادیر رو باهم جمع میکنه. فاصله بدست اومده رو به توان دو میرسونه.…
⭕️ یکی از مشکلات accuracy اینه که برای داده های غیر متوازن یا Imbalanced مناسب نیست.

🔸 پکیجی در پایتون موجود هست به اسم imblearn که وظیفه بالانس کردن داده ها رو بر عهده داره.
pip install imbalanced-learn

🔻 روش های مختلفی برای بالانس کردن داده ها وجود دارد. کاهش داده های کلاس اکثریت تا اینکه به اندازه داده های کلاس اقلیت برسه، یا افزایش داده های کلاس اقلیت تا به اندازه داده های کلاس اکثریت برسه. در پایین به چند مورد از این روش ها میپردازیم:

🔵 روش Random Under Sampler: این روش به صورت رندوم آنقدر از کلاس اکثریت داده حذف میکنه تا با کلاس اقلیت برابر بشه.
from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler()
X_rus, y_rus = rus.fit_resample(X, y)

X_train, X_test, y_train, y_test = train_test_split(X_rus, y_rus)


🟢 یکی از بدی های روش RUS اینه که خیلی از نمونه ها رو حذف میکنه و ممکنه خیلی از الگوها از دست بره.

▫️ ما فقط باید روی داده های train عملیات بالانس کردن دیتا رو انجام بدیم. اول داده ها رو به دو بخش تقسیم کنیم سپس روی X_train و y_train عملیات بالانس کردن رو انجام بدیم.

🔴 روش Random Over Sampler: در این روش آنقدر به نمونه های کلاس اقلیت اضافه میکنه تا نزدیک به کلاس اکثریت بشه.

◾️ مشکل روش ROS اینه که داده مصنوعی زیاد داریم.

✳️ روش Tomek Links: این روش مرز بین کلاس اقلیت و اکثریت رو شناسایی میکنه، و مرز رو به نفع کلاس اقلیت خالی میکنه تا فاصله بین مرز داده اقلیت و داده اکثریت زیاد بشه.

⁉️ روش SMOTE: در این روش بین کلاس اقلیت یال میکشه و گراف کامل رسم میکنه. سپس روی یال ها انقدر نمونه جدید اضافه میکنه تا کلاس اقلیت و اکثریت با هم برابر بشه.
from imblearn.over_sampling import SMOTE

sm = SMOTE()
X_sm, y_sm = sm.fit_resample(X, y)
✳️ دیپ لرنینگ قادر به یادگیری الگوهای پیچیده تری به نسبت ماشین لرنینگ است. استفاده از دیپ لرنینگ به دو شرط نیاز دارد:
🔸 حجم بالای داده ها
🔸 توان پردازش بالاتر

🔻 الگوریتم های دیپ لرنینگ نیاز زیادی به Feature Extraction ندارند و خودشون اینکار رو انجام میدهند.

🔹 Deep Learning: Deep Neural Networks (DNN)

▫️ شبکه های عصبی الگوریتم هایی هستند که از مغز موجودات زنده الهام گرفته اند. این شبکه ها سه جز اصلی دارند:
📌 نورون ها
📌 وزن ها
📌 لایه ها

🧬 شبکه های عصبی یک ورودی و یک خروجی دارند. یادگیری بر روی وزن ها انجام می‌شود. با افزایش تعداد نورون های شبکه عصبی، میتوانیم آن را پیچیده تر کنیم تا الگوهای پیچیده تری رو یاد بگیرند.

💡 به لایه های بین لایه ورودی و لایه خروجی، لایه مخفی (Hidden) میگویند. ما میتوانیم n تا لایه مخفی در شبکه عصبی داشته باشیم. نورون های هر لایه توسط وزن ها به نورون های لایه بعدی اتصال پیدا میکنند.

📍 تعداد نورون های لایه اول، به تعداد ویژگی های داده (ستون ها) بستگی دارد. لایه های پنهان اختیاری هستند. تعداد نورون های لایه آخر هم با توجه به تارگت مشخص میگردد. اگر تارگت بصورت 0 و 1 بود، دو نورون در لایه آخر کافی است.

🔍 به فازی که از لایه اول به لایه آخر حرکت میکنیم، Feed Forward گفته میشود. وقتی به لایه آخر رسیدیم خطا را محاسبه میکند و بر اساس خطا، فاز آپدیت را شروع میکند. فاز آپدیت از لایه آخر به اول است که به اصطلاح میگویند Back Propagation. بر اساس خطا، وزن ها طوری آپدیت میشوند که خطا کمتر بشود.

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

⭕️ یکی از مشکلات شبکه های عصبی عمیق محاسبات زیاد است و سرعت یادگیری کم میشود. همچنین به دلیل اینکه میخواهند الگوهای پیچیده ای یاد بگیرند، نیاز به حجم بالایی از داده ها دارند.

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

طراحی شبکه عصبی نیز چالش است.
⭕️ در شبکه عصبی با استفاده از اندازه ی دسته (batchsize)، میتونیم کاری کنیم که الگوریتم وزن خودش رو به ازای میانگین مقدار خطای اندازه دسته آپدیت کند.

📖 وزن های شبکه عصبی با یک ضریب آپدیت میشوند که به آن ضریب نرخ یادگیری (Learning Rate) میگویند. هرچقدر مقدار LR کمتر باشد، الگوریتم در یادگیری صبور‌تر است. و بالعکس.

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

📍 چند کتابخانه معروف برای کار در حوزه شبکه عصبی موجود است. یکی از آنها کتابخانه TensorFlow Keras میباشد. کتابخانه قوی دیگری به نام PyTorch نیز موجود است.

- نصب tensorflow از طریق anaconda prompt:
conda install tensorflow

- یا میتونیم داخل یک cell در Jupyter Notebook دستور زیر را وارد کنیم:
!conda install tensorflow

import tensorflow as tf


💭 همان پیش پردازش هایی که قبلا انجام میدادیم رو نیز باید در پروژه های مربوط به دیپ لرنینگ نیز انجام بدیم.

🔴 در اینجا باید ستون تارگت رو OHE کنیم. چون معماری شبکه عصبی این کار رو از ما میخواد.
y = pd.get_dummies(y)


🗂 ساخت شبکه عصبی:
model = tf.keras.models.Sequential([
tf.keras.layers.Dense(11, activation='relu', input_shape=(11,)),
tf.keras.layers.Dense(30, activation='relu'),
tf.keras.layers.Dense(2, activation='softmax'),

model.summary()


📊 لایه Dense (غلیظ) یعنی از تمامی نورون های لایه قبل به تمامی نورون های لایه بعد وزن متصل است.

🔹 رسم plot برای مدل:
from tensorflow.keras.utils import plot_model

plot_model(model, show_layer_activations=True, show_shapes=True)


🔔 بعد از ساختن مدل باید اون رو compile کنیم.
mode.compile(optimizer=tf.keras.optimizers.Adam(0.001), loss=tf.keras.losses.CategoricalCrossentropy(), metrics=[tf.keras.metrics.CategoricalAccuracy()])


▫️ الگوریتم آپدیت وزن ها رو در optimizer مشخص میکنیم. معمولا از Adam استفاده میکنند.
▪️ خطایی که الگوریتم محاسبه میکند با استفاده از فرمول loss انجام میگردد.
🔻 میتونیم metrics رو در هنگام compile کردن نزاریم، اما optimizer و loss رو حتما باید مشخص کنیم.

🔸 سپس مدل رو بر روی داده ها فیت میکنیم:
model.fit(X_train, y_train, epochs=10, validation_data=(X_test, y_test), batch_size=100)


🔹 اگر دقت شبکه عصبی عمیق خیلی نبود، میتونیم لایه های بیشتری اضافه کنیم و تعداد نورون ها رو افزایش بدیم.

🟧 الگوریتم های شبکه عصبی به مرور همگرا میشن و دقت افزایش پیدا نمیکنه.

- وقتی مدل یاد گرفت میتونیم اونها رو predict کنیم.
model.predict(X_test)[3]


📐 تابع فعال ساز softmax که بالاتر ازش استفاده کردیم، معمولا توی نورون لایه آخر استفاده میشه و با استفاده از یک فرمولی، جمع تمامی نورون ها در لایه آخر رو 1 میکنه.

🧮 دلیل اینکه از softmax در لایه های وسط استفاده نمیکنیم بخاطر اینه که حجم پردازشی بالایی نیاز داره.

🧷 چند مورد از توابع فعال ساز:
- Linear
- Sigmoid
- Tanh
- ReLu
- LeakyReLu
- Softmax

📚 در طراحی شبکه عصبی معمولا میگن اول با لایه های تقریبا مساوی با لایه ورودی شروع کنیم، بعد شبکه رو چاق کنیم و در نهایت شبکه رو لاغر کنیم.
✳️ یادگیری در شبکه های عصبی = پیدا کردن اعداد داخل وزن ها

🔸 اگر مشکل overfit در الگوریتم های دیپ لرنینگ اتفاق افتاده بود، میتونیم از لایه drop out استفاده کنیم. لایه drop out بین لایه ها در هنگام train یکسری از وزن ها و نورون ها رو به صورت رندوم غیرفعال میکنه. این کار از overfit جلوگیری میکنه.
model = tf.keras.models.Sequential([
tf.keras.layers.Dense(11, activation='relu', input_shape=(11,)),
tf.keras.layers.DropOut(0.3),
tf.keras.layers.Dense(30, activation='relu'),
tf.keras.layers.Dense(2, activation='softmax')
])


🔹 معماری های مختلف شبکه های عصبی:
- CNN: Convolutional Neural Networks

▫️ اگر حجم داده ها زیاد باشه اون ها رو به صورت incremental میخونیم.

🔻 اگر داده ها کم بود از روش Data Augmentation (افزایش مصنوعی داده ها) استفاده میکنیم. از این روش فقط برای داده های train استفاده میکنیم. به هیچ وجه نباید روی داده های train این کار رو انجام بدیم.

🟠 با استفاده از ImageDataGenerator میتونیم بر روی داده های ورودی از جنس تصویر تغییراتی اعمال کنیم.

import pandas as pd
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPool2D, Flatten, Dense
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau
from tensorflow.keras.utils import plot_model
from sklearn.utils.class_weight import compute_class_weight
from tensorflow.keras.callbacks import ModelCheckpoint

image_generator = ImageDataGenerator(
rescale=1./255.,
shear_range=0.1,
zoom_range=0.3,
)
image_generator_test = ImageDataGenerator(
rescale=1./255.
)


‼️ پکیج ImageDataGenerator قابلیت جالبی به نام FlowFromDirectory داره. در این قابلیت، یک دایرکتوری میسازیم و به ازای هر کلاس، یک فولدر ایجاد میکنه. داخل هر فولدر فقط تصاویری که مربوط به اون کلاس هستند قرار داده میشه.

train_data = image_generator.flow_from_directory(
'data',
target_size=(500, 500),
color_mode='grayscale',
class_mode='binary',
batch_size=10
)

test_data = image_generator.flow_from_directory(
'test_data',
target_size=(500, 500),
color_mode='grayscale',
class_mode='binary',
batch_size=10
)


✳️ ساخت مدل:
model = Sequential()
model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(500, 500, 1)))
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(1, activation='sigmoid'))


⭕️ کامپایل کردن مدل:
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']
❇️ در فیت کردن مدل، موردی داریم به اسم callbacks. این مجموعه‌ی callbacks یک سری فانکشن هستن که بعد از هر ایپاک فراخوانی میشن.

🔸 یکی از اون callbacks ها، es یا early stopping میباشد. این تابع بعد از هر ایپاک چک میکند اگر در سه ایپاک پشت سر هم (مقدار دلخواه هست)، مقدار validation loss کاهش پیدا نکرد، دیگه ادامه نده. در واقع الگوریتم همگرا شده است.
es = EarlyStopping(monitor='val_loss', mode='min', patience=3)


🔹 مورد بعدی در callbacks ها، rlrop یا reduce learning rate on plateau میباشد. این تابع، وقتی الگوریتم جلو میرود به مرور نرخ یادگیری را با ضریب خاص کاهش داده.
rlrop = ReduceLROnPlateaue(monitor='val_loss', patience=2, factor=0.2, min_lr=0.001)


🔻 مورد بعدی model checkpoint میباشد. این تابع بعد از هر ایپاک، اگر بهترین (کمترین) loss رو پیدا کرد، وزن ها رو ذخیره میکند.
mch = ModelCheckpoint('chestxray.h5', monitor='val_loss', mode='min', save_best_only=True)


🟢 شبکه های عصبی قابلیت جالبی به نام class weight دارند. معمولا کلاسی که از لحاظ تعداد در هنگام train کمتر هست، وزن بیشتری داشته باشد.
weights = compute_class_weight(class_weight='balanced', classes=np.unique(train_data.classes), y=train_data.classes)

class_weights = dict(zip(np.unique(train_data.classes), weights))



⭕️ تکنیک Transfer Learning (یادگیری انتقالی): در این روش، وزن های اولیه شبکه به جای اینکه تصادفی باشند، از همون وزن هایی که قبلا یاد گرفته استفاده میکنند.

از مشکلات این روش، اول از همه اینه که مجموعه داده ای پیدا کنیم که خیلی شبیه به پروژه ای که ما قصد انجام اون رو داریم باشه. سپس، معماری ای رو پیدا کنیم که روی مجموعه داده ما train شده باشه و وزن ها به صورت عمومی در دسترس باشه.

⁉️ در Transfer Learning معمولا نیازی به Data Augmentation نداریم.

🔍 اگر مسئله ما ساده بود و تعداد کمی داده داشتیم، در صورتی که به تعداد کافی ایپاک تعریف نکنیم ممکن است الگوریتم overift بشه. برای همین قسمتی از وزن ها رو freez میکنیم تا از این مشکل جلوگیری کنیم. سرعت یادگیری هم با این روش افزایش پیدا میکند.
1
❇️ اکثر اوقات بهتره که بجای اینکه داده‌ها رو به دو قسمت train و test تقسیم کنیم، به سه قسمت train و test و validation تقسیم کنیم.

⁉️ گاهی ممکنه معماری‌ای که طراحی کردیم روی داده‌های test دقت خوبی نده و مجبور بشیم معماری رو عوض کنیم که اینکار خیلی درست نیست. چون ما داریم معماری مدل رو برای داده‌های test بیش از اندازه تیون میکنیم.

⭕️ اگر سه دسته داده داشته باشیم، طبق معمول که از روی دسته train یادگیری انجام میده. اگه بخوایم هایپر پارامترها یا همون معماری مدل‌مون جوری عوض کنیم که روی داده‌های validation خوب کار کنه، اجازه‌ش رو داریم.

🔸 بعد ازینکه معماری نهایی رو ساختیم و تموم شد، و روی داده‌های validation بهترین دقت رو گرفتیم، یبار دیگه روی داده‌های test که کنار گذاشتیم و تا حالا ندیدیمش به عنوان آخرین بار دو مرتبه predict میکنیم.

🔻 دسته‌ی test حالت double check برای داده‌های validation رو داره.
👍1
🔹 لایه Batch Normalization نورون‌هایی که توی آخرین لایه (لایه قبلی) بودن رو نرمالایز میکنه (مثلا تقسیم بر ماکسیموم). اینکار باعث میشه نورون‌ها توی لایه‌های مختلف خیلی واگرا نشن و الگوریتم بهتر و دقیق‌تر یاد بگیره.

▫️ اگر دقت روی داده‌های train بالا باشه و روی داده‌های test پایین باشه یعنی مدل overfit شده. 🔹 لایه Batch Normalization نورون‌هایی که توی آخرین لایه (لایه قبلی) بودن رو نرمالایز میکنه (مثلا تقسیم بر ماکسیموم). اینکار باعث میشه نورون‌ها توی لایه‌های مختلف خیلی واگرا نشن و الگوریتم بهتر و دقیق‌تر یاد بگیره.

▫️ اگر دقت روی داده‌های train بالا باشه و روی داده‌های test پایین باشه یعنی مدل overfit شده.
⭕️ شبکه های عصبی چند کاناله (Multi Channel)

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

🔹 در شبکه های عصبی چند کاناله به ازای هر ورودی میتونیم یک کانال جدا داشته باشیم که هر کدوم یادگیری رو مستقل انجام بدن.