Skip to content

Commit

Permalink
2023/12/1
Browse files Browse the repository at this point in the history
  • Loading branch information
BlackTea-c committed Dec 1, 2023
1 parent 68d1a9d commit 0de2487
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 34 deletions.
2 changes: 1 addition & 1 deletion .idea/Mygithub.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 5 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,10 @@
# 感知机(Perceptron)教程
# 李航 《统计学习方法》 第二版 代码复现以及相关公式推导
#代码注释会写得很详细.

## 感知机简介
感知机是最简单的人工神经网络形式之一,用于解决二元分类问题。
参考repo lihang-code

## 感知机的工作原理

### 大致思想
- 感知机接收多个输入(x1, x2, ..., xn),每个输入都有一个对应的权重(w1, w2, ..., wn)。
- 输入和权重相乘并求和,加上偏置项(bias)。
- 将得到的结果传递给激活函数(通常为阶跃函数),输出最终的分类结果。

### 数学原理
感知机的数学表达式如下所示:
- 输入和权重的线性组合: \( \sum_{i=1}^{n} w_i \cdot x_i + b \)
- 阶跃函数: \( f(x) = \begin{cases} 1, & \text{if } \sum_{i=1}^{n} w_i \cdot x_i + b > 0 \\ 0, & \text{otherwise} \end{cases} \)
Bug修正

### 权重更新算法
感知机的学习规则使用简单的权重更新算法,通过随机梯度下降(Stochastic Gradient Descent)来更新权重和偏置项以最小化误差。
在每一轮训练中,对于每个输入样本(xi)和对应的真实标签(yi),权重更新规则如下:
- \( w_i = w_i + \alpha \cdot (y_i - \hat{y_i}) \cdot x_i \),其中 \(\alpha\) 是学习率(learning rate),\(\hat{y_i}\) 是预测值,\(y_i\) 是真实值。
- \( b = b + \alpha \cdot (y_i - \hat{y_i}) \)

### 对偶形式
感知机还有一种对偶形式,使用输入数据和标签的内积(dot product)计算权重更新。
对于权重更新,可以使用以下公式进行更新:
- \( w_i = w_i + \alpha \cdot (y_i - \hat{y_i}) \cdot x_i \)
- \( b = b + \alpha \cdot (y_i - \hat{y_i}) \cdot 1 \),其中 \(x_i\)\(1\) 是输入数据和偏置项,通过内积计算。



## 总结
感知机是最简单的神经网络形式之一,通过调整权重和偏置项,它可以学习并完成简单的二元分类任务。

## 文件解释
eg1.py 原始问题
eg_dual_form.py 对偶形式(起始就是计算下Gram矩阵)
# 2023/11/30 提升方法 eg8.1 lihang-code运行出来最后score=0.4 而书上是1.0 原因是lihang-code里把G3(x)弄错了(应该为positive),关键在于 if weight_error_positive <= weight_error_nagetive: #这里应该改成<= 代码第60行。
123 changes: 123 additions & 0 deletions 提升方法/Boosting Tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@





import numpy as np


class AdaBoost:
def __init__(self, X, y, tol=0.05, max_iter=10):
# 训练数据 实例
self.X = X
# 训练数据 标签
self.y = y
# 训练中止条件 right_rate>self.tol
self.tol = tol
# 最大迭代次数
self.max_iter = max_iter
# 初始化样本权重w
self.w = np.full((X.shape[0]), 1 / X.shape[0])
self.G = [] # 弱分类器

def build_stump(self): #决策树桩
"""
以带权重的分类误差最小为目标,选择最佳分类阈值
best_stump['dim'] 合适的特征所在维度
best_stump['thresh'] 合适特征的阈值
best_stump['ineq'] 树桩分类的标识lt,rt
"""
m, n = np.shape(self.X)
# 分类误差
e_min = np.inf
# 小于分类阈值的样本属于的标签类别
sign = None
# 最优分类树桩
best_stump = {}
for i in range(n):
range_min = self.X[:, i].min() # 求每一种特征的最大最小值
range_max = self.X[:, i].max()
step_size = (range_max - range_min) / n
for j in range(-1, int(n) + 1):
thresh_val = range_min + j * step_size
# 计算左子树和右子树的误差
for inequal in ['lt', 'rt']:
predict_vals = self.base_estimator(self.X, i, thresh_val,
inequal)
err_arr = np.array(np.ones(m))
err_arr[predict_vals.T == self.y.T] = 0
weighted_error = np.dot(self.w, err_arr)
if weighted_error < e_min:
e_min = weighted_error
sign = predict_vals
best_stump['dim'] = i
best_stump['thresh'] = thresh_val
best_stump['ineq'] = inequal
return best_stump, sign, e_min

def updata_w(self, alpha, predict):
"""
更新样本权重w
"""
# 以下2行根据公式8.4 8.5 更新样本权重
P = self.w * np.exp(-alpha * self.y * predict)
self.w = P / P.sum()

@staticmethod
def base_estimator(X, dimen, threshVal, threshIneq):
"""
计算单个弱分类器(决策树桩)预测输出
"""
ret_array = np.ones(np.shape(X)[0]) # 预测矩阵
# 左叶子 ,整个矩阵的样本进行比较赋值
if threshIneq == 'lt':
ret_array[X[:, dimen] <= threshVal] = -1.0
else:
ret_array[X[:, dimen] > threshVal] = -1.0
return ret_array

def fit(self):
"""
对训练数据进行学习
"""
G = 0
for i in range(self.max_iter):
best_stump, sign, error = self.build_stump() # 获取当前迭代最佳分类阈值
alpha = 1 / 2 * np.log((1 - error) / error) # 计算本轮弱分类器的系数
# 弱分类器权重
best_stump['alpha'] = alpha
# 保存弱分类器
self.G.append(best_stump)
# 以下3行计算当前总分类器(之前所有弱分类器加权和)分类效率
G += alpha * sign
y_predict = np.sign(G)
error_rate = np.sum(
np.abs(y_predict - self.y)) / 2 / self.y.shape[0]
if error_rate < self.tol: # 满足中止条件 则跳出循环
print("迭代次数:", i + 1)
break
else:
self.updata_w(alpha, y_predict) # 若不满足,更新权重,继续迭代

def predict(self, X):
"""
对新数据进行预测
"""
m = np.shape(X)[0]
G = np.zeros(m)
for i in range(len(self.G)):
stump = self.G[i]
# 遍历每一个弱分类器,进行加权
_G = self.base_estimator(X, stump['dim'], stump['thresh'],
stump['ineq'])
alpha = stump['alpha']
G += alpha * _G
y_predict = np.sign(G)
return y_predict.astype(int)

def score(self, X, y):
"""对训练效果进行评价"""
y_predict = self.predict(X)
error_rate = np.sum(np.abs(y_predict - y)) / 2 / y.shape[0]
return 1 - error_rate

0 comments on commit 0de2487

Please sign in to comment.