# Machine Learning Homework 2 LDA
Department : Forsetry
Student ID : M10912004
Name : De-Kai Kao (高得愷)
E-mail : block58697@gmail.com
## 介紹
線性判別分析(Linear Discriminate Analysis, LDA)是一種常用的統計分析方法,主要用於分類問題。它是一種監督式學習方法,即需要有已知類別的樣本作為訓練數據,以建立分類模型。LDA通常用於二元分類(binary classification),但也可以擴展到多類別分類(multiclass classification)。
<br/>
LDA基於貝葉斯定理,假設不同類別的樣本分布是高斯分布(Gaussian Distribution),且各類別的協方差相等(equal covariance)。在這個假設下,LDA可以通過計算樣本的平均值、標準差和協方差矩陣等統計量,得到一個判別函數(discriminant function),用於將新的樣本分到類別中。
<br/>
LDA將訓練數據中每一個類別的樣本視為一個高斯分布,假設不同類別的高斯分布具有相同的協方差矩陣,即同一類別的樣本具有相同的變異程度,而不同類別之間的協方差矩陣相等。這樣可以將類別的判別函數表示為線性函數,並且可以通過最大化類別之間的分離程度來得到判別函數。
<br/>
在使用LDA進行分類時,將新的樣本投影到判別函數上,並計算其所在的類別,即為該樣本的分類結果。此外,LDA還可以計算出分類錯誤率和ROC曲線等評價指標,以評估分類模型的性能。
<br/>
優點:
1. 可以處理高維數據,對於數據的線性分離效果較好。
2. 在滿足假設條件的情況下,LDA具有較高的分類準確率。
3. 可以得到判別函數的解析式,計算方便。
<br/>
缺點:
1. 對數據的假設比較嚴格,假設各類別的樣本分布是高斯分布且協方差矩陣相等,如果這些假設不成立,可能會導致分類結果不準確。
2. 在處理類別不平衡的問題時效果不佳,即某一類別的樣本數遠遠多於其他類別的樣本數。
3. LDA是一種線性模型,對於非線性問題的分類效果不佳。如果數據呈現非線性分布,可能需要使用其他非線性分類器,如支持向量機(Support Vector Machine, SVM)或神經網絡(Neural Network)等。
4. 對特徵選擇較為敏感,如果選擇的特徵不具有顯著差異,可能會導致分類效果不佳。
<br/>
<br/>
<br/>
## Python實作
### Import
```
import numpy as np
import matplotlib.pyplot as plt
```
### 生成隨機資料
```
# Set up the parameters for the normal distributions
mean1 = 20
std1 = 5
mean2 = 50
std2 = 14
n = 200
# Generate n random samples of x1 and x2
x1 = np.random.normal(mean1, std1, n)
y1 = np.random.normal(mean1, std1, n)
x2 = np.random.normal(mean2, std2, n)
y2 = np.random.normal(mean2, std2, n)
# stack
a = np.stack((x1, y1), axis=1)
b = np.stack((x2, y2), axis=1)
a.shape # (200, 2)
plt.plot(a[:,0], a[:,1], 'g.', b[:,0], b[:,1], 'y.')
plt.gca().axis('equal')
```

### 計算特徵向量
```
# calclate each class of mean vector
mu_a, mu_b = a.mean(axis=0).reshape(-1,1), b.mean(axis=0).reshape(-1,1)
Sw = np.cov(a.T) + np.cov(b.T)
inv_S = np.linalg.inv(Sw)
Sb = (mu_a-mu_b)*((mu_a-mu_b).T)
eig_vals, eig_vecs = np.linalg.eig(inv_S.dot(Sb))
res = np.array([-eig_vecs[0].max(), -eig_vecs[1].min()]).reshape(-1,1)
```
Unit Vector: [-0.77810883 -0.62812948]
### Plot
```
# plot the project axis with an infinitely line
plt.axline((-res[0], -res[1]), (res[0], res[1]), color='red', label='by points')
# project data point on new axis
r = res.reshape(2,)
n2 = np.linalg.norm(r)**2
aprj = []
bprj = []
for pt in a:
prj = r * r.dot(pt) / n2
aprj += [prj]
# plt.plot([x1, x2], [y1, y2])
plt.plot([prj[0], pt[0]], [prj[1], pt[1]], 'g.:', alpha=0.5)
for pt in b:
prj = r * r.dot(pt) / n2
bprj += [prj]
plt.plot([prj[0], pt[0]], [prj[1], pt[1]], 'y.:', alpha=0.5)
# get boundary point
mu_aprj, mu_bprj = np.array(aprj).mean(axis=0).reshape(-1,1), np.array(bprj).mean(axis=0).reshape(-1,1)
muprj = (mu_aprj + mu_bprj) / 2
plt.plot(muprj[0], muprj[1], 'ro')
print('boundary point:', muprj[0], muprj[1])
# plot the decision boundary on boundary point
muprj = muprj.reshape(2, )
x1 = -res[1] + muprj[0]
y1 = res[0] + muprj[1]
x2 = muprj[0]
y2 = muprj[1]
plt.axline((x1, y1), (x2, y2), color='green', label='by points')
```

### Decision
```
x0 = 20
y0 = 40
m = (y2-y1)/(x2-x1)
x = np.linspace(plt.xlim()[0], plt.xlim()[1], 100)
y = m * (x - x2) + y2
if m * (x0 - x2) + y2 -y0 <0:
plt.fill_between(x, y, max(plt.ylim()), color='green', alpha=0.2)
plt.plot(x0, y0, 'bo')
elif m * (x0 - x2) + y2 -y0 >0:
plt.fill_between(x, y, min(plt.ylim()), color='yellow', alpha=0.2)
plt.plot(x0, y0, 'bo')
else:
plt.plot(x0, y0, 'bo')
```

---
https://hackmd.io/IoZA6SnWT-WW4AYmyjGweA?view
