绪论
实验1 基本概念
第一关 什么是机器学习
下面哪种方法属于机器学习?
A、在猫狗分类问题中,先将猫与狗的特点总结出来,再告诉机器,如果符合猫的特点,则判定为猫,如果符合狗的特点,则判定为狗。
B、将大量名画的真品与赝品输入计算机,让计算机自己从数据中学习出一个模型用来判断是真品还是赝品。
C、让计算机通过对以往的房价数据进行分析,预测未来房价走势。
D、通过人为编写好代码,符合条件则判定为人脸,否则不是人脸,从而制作出人脸识别系统。
答案:BC
第二关 机器学习的常见术语
1、以下是我们的一份数据集,则 x 32 x_{32} x32表示的是?
A、青绿
B、硬挺
C、清脆
D、浊响
答案:B
第三关 机器学习的主要任务
1、我们现在手头上有大量的猫与狗的图片,我现在想训练出一个模型,能够区别出这张图片是猫还是狗,这是一个什么问题?
A、回归
B、分类
C、聚类
答案:B
2、我们现在手头上有大量的动物的图片,为了方便处理,我们想让同一种动物的图片放到同一个文件夹,这是一个什么问题?
A、聚类
B、回归
C、分类
D、无监督学习
答案:AD
3、在无人驾驶时,希望程序能够根据路况决策汽车的方向盘的旋转角度,那么该任务是?
A、分类
B、回归
C、聚类
D、降维
答案:B
模型评估与选择
实验1 模型评估、选择与验证
第1关:为什么要有训练集与测试集
1、下面正确的是?
A、将手头上所有的数据拿来训练模型,预测结果正确率最高的模型就是我们所要选的模型。
B、将所有数据中的前百分之70拿来训练模型,剩下的百分之30作为测试集,预测结果正确率最高的模型就是我们所要选的模型。
C、将所有数据先随机打乱顺序,一半用来训练模型,一半作为测试集,预测结果正确率最高的模型就是我们所要选的模型。
D、将所有数据先随机打乱顺序,百分之80用来训练模型,剩下的百分之20作为测试集,预测结果正确率最高的模型就是我们所要选的模型。
答案:D
2、训练集与测试集的划分对最终模型的确定有无影响?
A、有
B、无
答案:A
第2关:欠拟合与过拟合
1、请问,图中A与B分别处于什么状态?
A、欠拟合,欠拟合
B、欠拟合,过拟合
C、过拟合,欠拟合
D、过拟合,过拟合
答案:B
2、如果一个模型在训练集上正确率为99%,测试集上正确率为60%。我们应该怎么做?
A、加入正则化项
B、增加训练样本数量
C、增加模型复杂度
D、减少模型复杂度
答案:ABD
第3关 偏差与方差
1、如果一个模型,它在训练集上正确率为85%,测试集上正确率为80%,则模型是过拟合还是欠拟合?其中,来自于偏差的误差为?来自方差的误差为?
A、欠拟合,5%,5%
B、欠拟合,15%,5%
C、过拟合,15%,15%
D、过拟合,5%,5%
答案:B
第4关 验证集与交叉验证
1、假设,我们现在利用5折交叉验证的方法来确定模型的超参数,一共有4组超参数,我们可以知道,5折交叉验证,每一组超参数将会得到5个子模型的性能评分,假设评分如下,我们应该选择哪组超参数?
A、子模型1:0.8 子模型2:0.7 子模型3:0.8 子模型4:0.6 子模型5:0.5
B、子模型1:0.9 子模型2:0.7 子模型3:0.8 子模型4:0.6 子模型5:0.5
C、子模型1:0.5 子模型2:0.6 子模型3:0.7 子模型4:0.6 子模型5:0.5
D、子模型1:0.8 子模型2:0.8 子模型3:0.8 子模型4:0.8 子模型5:0.6
答案:B
2、下列说法正确的是?
A、相比自助法,在初始数据量较小时交叉验证更常用。
B、自助法对集成学习方法有很大的好处
C、使用交叉验证能够增加模型泛化能力
D、在数据难以划分训练集测试集时,可以使用自助法
答案:BCD
第5关 衡量回归性能的指标
1、下列说法正确的是?
A、相比MSE指标,MAE对噪声数据不敏感
B、RMSE指标值越小越好
C、R-Squared指标值越小越好
D、当我们的模型不犯任何错时,R-Squared值为0
答案:AB
第6关:准确度的陷阱与混淆矩阵
import numpy as np
def confusion_matrix(y_true, y_predict):
def TN(y_true, y_predict):
return np.sum((y_true == 0) & (y_predict == 0))
def FP(y_true, y_predict):
return np.sum((y_true == 0) & (y_predict == 1))
def FN(y_true, y_predict):
return np.sum((y_true == 1) & (y_predict == 0))
def TP(y_true, y_predict):
return np.sum((y_true == 1) & (y_predict == 1))
return np.array([
[TN(y_true, y_predict), FP(y_true, y_predict)],
[FN(y_true, y_predict), TP(y_true, y_predict)]
])
第7关:精准率与召回率
import numpy as np
def precision_score(y_true, y_predict):
'''
计算精准率并返回
:param y_true: 真实类别,类型为ndarray
:param y_predict: 预测类别,类型为ndarray
:return: 精准率,类型为float
'''
#********* Begin *********#
TP = np.sum((y_true == 1) & (y_predict == 1))
FP = np.sum((y_true == 0) & (y_predict == 1))
Precision = TP/(TP+FP)
return Precision
#********* End *********#
def recall_score(y_true, y_predict):
'''
计算召回率并召回
:param y_true: 真实类别,类型为ndarray
:param y_predict: 预测类别,类型为ndarray
:return: 召回率,类型为float
'''
#********* Begin *********#
TP = np.sum((y_true == 1) & (y_predict == 1))
FN = np.sum((y_true == 1) & (y_predict == 0))
Recall = TP/(TP+FN)
return Recall
#********* End *********#
第8关:F1 Score
import numpy as np
def f1_score(precision, recall):
'''
计算f1 score并返回
:param precision: 模型的精准率,类型为float
:param recall: 模型的召回率,类型为float
:return: 模型的f1 score,类型为float
'''
#********* Begin *********#
f1 = (2*precision*recall)/(precision+recall)
return f1
#********* End ***********#
第9关:ROC曲线与AUC
import numpy as np
def calAUC(prob, labels):
'''
计算AUC并返回
:param prob: 模型预测样本为Positive的概率列表,类型为ndarray
:param labels: 样本的真实类别列表,其中1表示Positive,0表示Negtive,类型为ndarray
:return: AUC,类型为float
'''
#********* Begin *********#
f = list(zip(prob, labels))
rank = [values2 for values1, values2 in sorted(f, key=lambda x:x[0])]
rankList = [i+1 for i in range(len(rank)) if rank[i] == 1]
posNum = 0
negNum = 0
for i in range(len(labels)):
if(labels[i] == 1):
posNum += 1
else:
negNum += 1
auc = (sum(rankList) - (posNum*(posNum+1))/2)/(posNum*negNum)
return auc
#********* End *********#
第10关:sklearn中的分类性能指标
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score
def classification_performance(y_true, y_pred, y_prob):
'''
返回准确度、精准率、召回率、f1 Score和AUC
:param y_true:样本的真实类别,类型为`ndarray`
:param y_pred:模型预测出的类别,类型为`ndarray`
:param y_prob:模型预测样本为`Positive`的概率,类型为`ndarray`
:return:
'''
#********* Begin *********#
return accuracy_score(y_true, y_pred), precision_score(y_true, y_pred), recall_score(y_true, y_pred), f1_score(y_true, y_pred,y_prob), roc_auc_score(y_true, y_prob)
#********* End *********#
实验2 理解机器学习基本概念:从电影评分预测讲起
第1关:统计数据集的基本属性
# -*- coding:utf-8 -*-
def stat_data(train_data):
"""求出用户数和电影数,评分数目, 平均评分, 最大评分, 最小评分
参数:
train_data - Pandas的DataFrame对象,有四列'user','movie','rating','timestamp',是训练数据集
返回值:
num_user - 整数,用户数
num_movie - 整数,电影数
num_rating - 整数,评分数目
avg_rating - 浮点数,平均评分
max_rating - 浮点数,最大评分
min_rating - 浮点数,最小评分
"""
num_user = 0
num_movie = 0
num_rating = 0
avg_rating = 0
max_rating = 0
min_rating = 0
# 请在此添加实现代码
#********** Begin *********#
num_user = train_data['user'].nunique()
num_movie = train_data['movie'].nunique()
num_rating = train_data['rating'].size
avg_rating = train_data['rating'].mean()
max_rating = train_data['rating'].max()
min_rating = train_data['rating'].min()
#********** End *********#
return num_user, num_movie, num_rating, avg_rating, max_rating, min_rating
第2关:进一步探索数据集
# -*- coding:utf-8 -*-
def avg_rating_of_users_movies(data):
"""求出每个用户的平均评分
参数:
data - Pandas的DataFrame对象,有四列'user','movie','rating','timestamp',是训练数据集
返回值:
user2avg_r - Pandas的DataFrame对象,有一列'rating'
movie2avg_r - Pandas的DataFrame对象,有一列'rating'
"""
user2avg_r = ''
movie2avg_r = ''
# 请在此添加实现代码
#********** Begin *********#
user2avg_r = data.groupby('user')['rating'].mean().reset_index(name='rating')
movie2avg_r = data.groupby('movie')['rating'].mean().reset_index(name='rating')
#********** End *********#
return user2avg_r, movie2avg_r
def top_10_user_movie_on_avg_rating(user2avg_r, movie2avg_r):
"""求出平均评分最高的10个用户和10个电影
参数:
user2avg_r - Pandas的DataFrame对象,有一列'rating'
movie2avg_r - Pandas的DataFrame对象,有一列'rating'
返回值:
top10_users - 整数列表,用户ID数组,比如[3,4,5,6]代表前4个用户账户是3,4,5,6
top10_movies - 整数列表,电影ID数组,比如[30,40,50,60]代表前4个电影编号是3,4,5,6
"""
top10_users = []
top10_movies = []
# 请在此添加实现代码
#********** Begin *********#
top10_users = user2avg_r.sort_values(by='rating',ascending=False).head(10)['user'].tolist()
top10_movies = movie2avg_r.sort_values(by='rating',ascending=False).head(10)['movie'].tolist()
#********** End *********#
return top10_users, top10_movies
第3关:实现基础预测评分算法
def learn(train_data, N, M):
"""从训练数据中学习得到模型
参数:
train_data - Pandas的DataFrame对象,有四列'user','movie','rating','timestamp',是训练数据集
N - 整数,用户数目
M - 整数,电影数目
返回值:
g - 数据集中的平均每用户每电影评分值参数
alpha - 浮点数组,用户评分偏差参数数组,举例alpha[9]表示用户9的评分偏差
beta - 浮点数组,电影评分偏差参数数组,举例beta[90]表示电影90的评分偏差
"""
# 导入Step2的模块
from stat_rating import avg_rating_of_users_movies
import numpy as np
# 模型参数
g = 0 # 模型参数:所有用户所有电影的平均评分
alpha = np.zeros(N) # 模型参数:每个用户的评分偏好
beta = np.zeros(M) # 模型参数:每个电影的评分偏好
# 计算平均每用户每电影评分值参数g
g = np.mean(train_data['rating'])
# 计算用户评分偏差参数alpha
for i in range(N):
user_ratings = train_data[train_data['user'] == i]['rating']
# 检查该用户是否有评分数据
if len(user_ratings) == 0:
alpha[i] = 0 - g;
else:
alpha[i] = np.mean(user_ratings) - g
# 计算电影评分偏差参数beta
for j in range(M):
movie_ratings = train_data[train_data['movie'] == j]['rating']
# 检查该电影是否有评分数据
if len(movie_ratings) == 0:
beta[j] = 0 - g;
else:
beta[j] = np.mean(movie_ratings) - g
return g, alpha, beta
第4关:应用模型做预测
def predict(g, alpha, beta, test_data):
"""预测用户对电影的评分
参数:
g - 浮点数,模型参数平均电影评分参数
alpha - 浮点数组,用户评分偏差参数数组
beta - 浮点数组,电影评分偏差参数数组
test_data - Pandas的DataFrame对象,有两列'user','movie',是测试数据集
返回值:
ret - 浮点数数组,预测的评分数组,每个值对应test_data中的每一行的评分值
"""
ret = []
N = len(alpha)
M = len(beta)
# 预测每条测试数据的评分
for index, row in test_data.iterrows():
user = row['user']
movie = row['movie']
# 防止索引超出范围
if user >= N or movie >= M:
ret.append(g)
else:
# 预测评分公式:预测评分 = 模型参数g + 用户评分偏差alpha + 电影评分偏差beta
prediction = g + alpha[user] + beta[movie]
ret.append(prediction)
return ret
第5关:评估机器学习模型
import numpy as np
def RMSE(predicted_rating, true_rating):
"""计算RMSE值
参数:
predicted_rating - list,预测的评分
true_rating - list,真实的评分
返回值:
rmse - 浮点数,RMSE值
"""
rmse = 0
# 将列表转换为numpy数组
predicted_rating = np.array(predicted_rating)
true_rating = np.array(true_rating)
# 计算平方差和
squared_error = np.square(predicted_rating - true_rating).sum()
# 计算均方根误差
mean_squared_error = squared_error / len(predicted_rating)
rmse = np.sqrt(mean_squared_error)
return rmse
第6关:基于梯度下降法的模型参数估计
# -*- coding:utf-8 -*-
def gradient(u, m, r, g, alpha, beta):
"""求出用户权重的梯度
参数:
u - 整数,用户ID
m - 整数,电影ID
r - 整数,实际评分
g - 浮点数,平均评分参数
alpha - 浮点数组,用户评分偏差参数数组
beta - 浮点数组,电影评分偏差参数数组
返回值:
grad_alpha - 浮点数,用户梯度值,举例grad_alpha[9]表示用户9的评分偏差梯度
grad_beta - 浮点数,电影梯度值,举例grad_beta[90]表示电影90的评分偏差梯度
"""
grad_alpha = 0
grad_beta = 0
# 请在此添加实现代码
#********** Begin *********#
# 获取用户u对电影m的预测评分
predict_rating = g + alpha[u] + beta[m]
# 计算梯度
grad_alpha = -2 * (r - predict_rating)
grad_beta = -2 * (r - predict_rating)
#********** End *********#
return grad_alpha, grad_beta
def learn(train_data, N, M, steps, tao, g):
"""学习模型
参数:
train_data - Pandas的DataFrame对象,有四列'user','movie','rating','timestamp',是训练数据集
N - 整数,用户数目
M - 整数,电影数目
steps - 整数,迭代次数
tao - 浮点数,学习速率
g - 浮点数,平均电影评分
返回值:
alpha - 浮点数组,用户评分偏差参数数组,举例alpha[9]表示用户9的评分偏差
beta - 浮点数组,电影评分偏差参数数组,举例beta[90]表示电影90的评分偏差
"""
import numpy as np
#以正态分布初始化模型参数bu和bi
alpha = np.zeros(N)+0.01
beta = np.zeros(M)+0.01
#迭代循环
for step in range(steps):
for row in train_data.itertuples():
u = row.user
m = row.movie
r = row.rating
# 请在此添加实现代码
#********** Begin *********#
# 计算梯度
grad_alpha, grad_beta = gradient(u, m, r, g, alpha, beta)
# 更新参数
alpha[u] -= tao * grad_alpha
beta[m] -= tao * grad_beta
#********** End *********#
return alpha, beta
线性模型
实验1 回归的概念与类型
1、以下哪种方法为无监督类型机器学习方法?
A、回归
B、分类
C、聚类
答案: C
2、以下哪些为连续型变量?
A、温度
B、身高
C、房价
D、国籍
答案: ABC
3、以下哪些模型适用于回归的任务?
A、简单回归模型
B、多项式回归模型
C、多元线性回归模型
D、逻辑回归模型
答案: ABC
4、以下哪个统计指标能反映机器学习结果的自身不稳定性?
A、偏差
B、方差
C、平方差
答案: B
5、在多项式回归中,随着多项式的最大指数p增加,训练得到的回归模型表现会是下面怎样的情形?
A、在训练集合上偏差大
B、在训练集合上偏差小
C、在测试集合上方差大
D、在测试集合上方差小
答案: BC
6、以下哪种回归模型可以有效利用特征之间的交互?
A、线性回归模型
B、多项式回归模型
C、神经网络回归模型
答案: C
实验2 线性回归
第1关:简单线性回归与多元线性回归
下面属于多元线性回归的是?
A、求得正方形面积与对角线之间的关系。
B、建立股票价格与成交量、换手率等因素之间的线性关系。
C、建立西瓜价格与西瓜大小、西瓜产地、甜度等因素之间的线性关系。
D、建立西瓜书销量与时间之间的线性关系。
答案: BC
2、若线性回归方程得到多个解,下面哪些方法能够解决此问题?
A、获取更多的训练样本
B、选取样本有效的特征,使样本数量大于特征数
C、加入正则化项
D、不考虑偏置项b
答案: ABC
3、下列关于线性回归分析中的残差(预测值减去真实值)说法正确的是?
A、残差均值总是为零
B、残差均值总是小于零
C、残差均值总是大于零
D、以上说法都不对
答案: A
第2关:线性回归的正规方程解
#encoding=utf8
import numpy as np
def mse_score(y_predict,y_test):
'''
input:y_predict(ndarray):预测值
y_test(ndarray):真实值
ouput:mse(float):mse损失函数值
'''
#********* Begin *********#
mse = np.mean((y_predict-y_test)**2)
#********* End *********#
return mse
class LinearRegression :
def __init__(self):
'''初始化线性回归模型'''
self.theta = None
def fit_normal(self,train_data,train_label):
'''
input:train_data(ndarray):训练样本
train_label(ndarray):训练标签
'''
#********* Begin *********#
x=np.hstack([np.ones((len(train_data),1)),train_data])
self.theta=np.linalg.inv(x.T.dot(x)).dot(x.T).dot(train_label)
#********* End *********#
return self.theta
def predict(self,test_data):
'''
input:test_data(ndarray):测试样本
'''
#********* Begin *********#
x=np.hstack([np.ones((len(test_data),1)),test_data])
return x.dot(self.theta)
#********* End *********#
第3关:衡量线性回归的性能指标
#encoding=utf8
import numpy as np
#mse
def mse_score(y_predict,y_test):
mse = np.mean((y_predict-y_test)**2)
return mse
#r2
def r2_score(y_predict,y_test):
'''
input:y_predict(ndarray):预测值
y_test(ndarray):真实值
output:r2(float):r2值
'''
#********* Begin *********#
from sklearn.metrics import r2_score
r2 = r2_score(y_test,y_predict)
#y_mean=np.mean(y_test)
#r2 = 1-(sum(y_predict-y_test)**2)/(sum(y_mean-y_test)**2)
#********* End *********#
return r2
class LinearRegression :
def __init__(self):
'''初始化线性回归模型'''
self.theta = None
def fit_normal(self,train_data,train_label):
'''
input:train_data(ndarray):训练样本
train_label(ndarray):训练标签
'''
#********* Begin *********#
x=np.hstack([np.ones((len(train_data),1)),train_data])
self.theta=np.linalg.inv(x.T.dot(x)).dot(x.T).dot(train_label)
#********* End *********#
return self.theta
def predict(self,test_data):
'''
input:test_data(ndarray):测试样本
'''
#********* Begin *********#
x=np.hstack([np.ones((len(test_data),1)),test_data])
return x.dot(self.theta)
#********* End *********#
第4关:scikit-learn线性回归实践 - 波斯顿房价预测
#encoding=utf8
#********* Begin *********#
import pandas as pd
from sklearn.linear_model import LinearRegression
#获取训练数据
train_data = pd.read_csv('./step3/train_data.csv')
#获取训练标签
train_label = pd.read_csv('./step3/train_label.csv')
train_label = train_label['target']
#获取测试数据
test_data = pd.read_csv('./step3/test_data.csv')
# 实例化API
estimator = LinearRegression()
# 使用fit方法进行训练
estimator.fit(train_data,train_label)
predict = estimator.predict(test_data)
predict = pd.DataFrame({'result':predict})
predict.to_csv('./step3/result.csv')
#********* End *********#
实验3 分类的概念
第1关:分类之“三顾茅庐”
1、分类问题属于下列哪一类?
A、有监督学习
B、无监督学习
C、弱监督学习
D、远程监督学习
答案:A
2、下列哪些不属于分类问题的典型应用?
A、识别邮箱收件是否为垃圾文件
B、智能音箱控制家电
C、根据症状与检查结果自动诊断疾病
D、购物网站为顾客推荐“猜你喜欢”
答案:BD
3、分类问题需要预测的变量为离散整数值或者连续实数均可。
A、正确
B、错误
答案:B
第2关:分类之“华山论剑”
1、根据输出结果形式,分类器可分为概率和非概率分类器。
A、正确
B、错误
答案:A
2、下列哪些属于非概率分类器?
A、贝叶斯分类
B、逻辑回归分类
C、k近邻
D、支持向量机
答案:CD
3、手写数字识别应该采用何种方法?
A、概率分类器
B、非概率分类器
C、这不是分类问题,无需分类器
答案:B
实验4 逻辑回归
第1关:逻辑回归核心思想
#encoding=utf8
import numpy as np
def sigmoid(t):
'''
完成sigmoid函数计算
:param t: 负无穷到正无穷的实数
:return: 转换后的概率值
:可以考虑使用np.exp()函数
'''
#********** Begin **********#
y=1/(1+np.exp(-t))
return y
#********** End **********#
第2关:逻辑回归的损失函数
1、逻辑回归的损失函数可以写成如下形式
A、对
B、错
答案:A
2、下列说法正确的是
A、损失值能够衡量模型在训练数据集上的拟合程度
B、sigmoid函数不可导
C、sigmoid函数的输入越大,输出就越大
D、训练的过程,就是寻找合适的参数使得损失函数值最小的过程
答案:ACD
3、sigmoid函数(对数几率函数)相对于单位阶跃函数有哪些好处?
A、sigmoid函数可微分
B、sigmoid函数处处连续
C、sigmoid函数不是单调的
D、sigmoid函数最多计算二阶导
答案:AB
4、逻辑回归的优点有哪些?
A、需要事先对数据的分布做假设
B、可以得到“类别”的真正的概率预测
C、可以用闭式解求解
D、可以用现有的数值优化算法求解
答案:D
第3关:梯度下降
# -*- coding: utf-8 -*-
import numpy as np
import warnings
warnings.filterwarnings("ignore")
def gradient_descent(initial_theta,eta=0.05,n_iters=1000,epslion=1e-8):
'''
梯度下降
:param initial_theta: 参数初始值,类型为float
:param eta: 学习率,类型为float
:param n_iters: 训练轮数,类型为int
:param epslion: 容忍误差范围,类型为float
:return: 训练后得到的参数
'''
# 请在此添加实现代码 #
#********** Begin *********#
theta=initial_theta
i=0
while i<n_iters:
gra = 2*(theta-3)
last_theat = theta
theta = theta-eta*gra
if(abs(theta-last_theat)<epslion):
break
i=i+1
return theta
#********** End **********#
第4关:动手实现逻辑回归 - 癌细胞精准识别
# -*- coding: utf-8 -*-
import numpy as np
import warnings
warnings.filterwarnings("ignore")
def sigmoid(x):
'''
sigmoid函数
:param x: 转换前的输入
:return: 转换后的概率
'''
return 1/(1+np.exp(-x))
def fit(x,y,eta=1e-3,n_iters=10000):
'''
训练逻辑回归模型
:param x: 训练集特征数据,类型为ndarray
:param y: 训练集标签,类型为ndarray
:param eta: 学习率,类型为float
:param n_iters: 训练轮数,类型为int
:return: 模型参数,类型为ndarray
'''
# 请在此添加实现代码 #
#********** Begin *********#
theta = np.zeros(x.shape[1])
i_iter = 0
while i_iter < n_iters:
gradient = (sigmoid(x.dot(theta))-y).dot(x)
theta = theta -eta*gradient
i_iter += 1
return theta
#********** End **********#
第5关:手写数字识别
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
import matplotlib.pyplot as plt
def digit_predict(train_image, train_label, test_image):
'''
实现功能:训练模型并输出预测结果
:param train_sample: 包含多条训练样本的样本集,类型为ndarray,shape为[-1, 8, 8]
:param train_label: 包含多条训练样本标签的标签集,类型为ndarray
:param test_sample: 包含多条测试样本的测试集,类型为ndarry
:return: test_sample对应的预测标签
'''
#************* Begin ************#
flat_train_image = train_image.reshape((-1, 64))
# 训练集标准化
train_min = flat_train_image.min()
train_max = flat_train_image.max()
flat_train_image = (flat_train_image-train_min)/(train_max-train_min)
# 测试集变形
flat_test_image = test_image.reshape((-1, 64))
# 测试集标准化
test_min = flat_test_image.min()
test_max = flat_test_image.max()
flat_test_image = (flat_test_image - test_min) / (test_max - test_min)
# 训练--预测
rf = LogisticRegression(C=4.0)
rf.fit(flat_train_image, train_label)
return rf.predict(flat_test_image)
#************* End **************#
实验5 多分类学习
第1关:OvO多分类策略
import numpy as np
# 逻辑回归
class tiny_logistic_regression(object):
def __init__(self):
#W
self.coef_ = None
#b
self.intercept_ = None
#所有的W和b
self._theta = None
#01到标签的映射
self.label_map = {}
def _sigmoid(self, x):
return 1. / (1. + np.exp(-x))
#训练,train_labels中的值可以为任意数值
def fit(self, train_datas, train_labels, learning_rate=1e-4, n_iters=1e3):
#loss
def J(theta, X_b, y):
y_hat = self._sigmoid(X_b.dot(theta))
try:
return -np.sum(y*np.log(y_hat)+(1-y)*np.log(1-y_hat)) / len(y)
except:
return float('inf')
# 算theta对loss的偏导
def dJ(theta, X_b, y):
return X_b.T.dot(self._sigmoid(X_b.dot(theta)) - y) / len(y)
# 批量梯度下降
def gradient_descent(X_b, y, initial_theta, leraning_rate, n_iters=1e2, epsilon=1e-6):
theta = initial_theta
cur_iter = 0
while cur_iter < n_iters:
gradient = dJ(theta, X_b, y)
last_theta = theta
theta = theta - leraning_rate * gradient
if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
break
cur_iter += 1
return theta
unique_labels = list(set(train_labels))
labels = np.array(train_labels)
# 将标签映射成0,1
self.label_map[0] = unique_labels[0]
self.label_map[1] = unique_labels[1]
for i in range(len(train_labels)):
if train_labels[i] == self.label_map[0]:
labels[i] = 0
else:
labels[i] = 1
X_b = np.hstack([np.ones((len(train_datas), 1)), train_datas])
initial_theta = np.zeros(X_b.shape[1])
self._theta = gradient_descent(X_b, labels, initial_theta, learning_rate, n_iters)
self.intercept_ = self._theta[0]
self.coef_ = self._theta[1:]
return self
#预测X中每个样本label为1的概率
def predict_proba(self, X):
X_b = np.hstack([np.ones((len(X), 1)), X])
return self._sigmoid(X_b.dot(self._theta))
#预测
def predict(self, X):
proba = self.predict_proba(X)
result = np.array(proba >= 0.5, dtype='int')
# 将0,1映射成标签
for i in range(len(result)):
if result[i] == 0:
result[i] = self.label_map[0]
else:
result[i] = self.label_map[1]
return result
class OvO(object):
def __init__(self):
# 用于保存训练时各种模型的list
self.models = []
def fit(self, train_datas, train_labels):
'''
OvO的训练阶段,将模型保存到self.models中
:param train_datas: 训练集数据,类型为ndarray
:param train_labels: 训练集标签,标签值为0,1,2之类的整数,类型为ndarray,shape为(-1,)
:return:None
'''
#********* Begin *********#
unique_labels = list(set(train_labels))
for i in range(len(unique_labels)):
for j in range(i+1,len(unique_labels)):
datas=train_datas[(train_labels == unique_labels[i]) | (train_labels == unique_labels[j])]
labels = train_labels[(train_labels == unique_labels[i]) |(train_labels == unique_labels[j])]
lr = tiny_logistic_regression()
lr.fit(datas,labels)
self.models.append(lr)
#********* End *********#
def predict(self, test_datas):
'''
OvO的预测阶段
:param test_datas:测试集数据,类型为ndarray
:return:预测结果,类型为ndarray
'''
#********* Begin *********#
def _predict(models, test_data):
# 变形
test_data = np.reshape(test_data, (1, -1))
vote = {}
# 计票
for model in models:
pred = model.predict(test_data)[0]
if pred not in vote:
vote[pred] = 1
else:
vote[pred] += 1
vote = sorted(vote.items(), key=lambda x: x[1], reverse=True)
return vote[0][0]
predict = []
for data in test_datas:
predict.append(_predict(self.models, data))
return np.array(predict)
#********* End *********#
第2关:OvR多分类策略
import numpy as np
# 逻辑回归
class tiny_logistic_regression(object):
def __init__(self):
#W
self.coef_ = None
#b
self.intercept_ = None
#所有的W和b
self._theta = None
#01到标签的映射
self.label_map = {}
def _sigmoid(self, x):
return 1. / (1. + np.exp(-x))
#训练
def fit(self, train_datas, train_labels, learning_rate=1e-4, n_iters=1e3):
#loss
def J(theta, X_b, y):
y_hat = self._sigmoid(X_b.dot(theta))
try:
return -np.sum(y*np.log(y_hat)+(1-y)*np.log(1-y_hat)) / len(y)
except:
return float('inf')
# 算theta对loss的偏导
def dJ(theta, X_b, y):
return X_b.T.dot(self._sigmoid(X_b.dot(theta)) - y) / len(y)
# 批量梯度下降
def gradient_descent(X_b, y, initial_theta, leraning_rate, n_iters=1e2, epsilon=1e-6):
theta = initial_theta
cur_iter = 0
while cur_iter < n_iters:
gradient = dJ(theta, X_b, y)
last_theta = theta
theta = theta - leraning_rate * gradient
if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
break
cur_iter += 1
return theta
X_b = np.hstack([np.ones((len(train_datas), 1)), train_datas])
initial_theta = np.zeros(X_b.shape[1])
self._theta = gradient_descent(X_b, train_labels, initial_theta, learning_rate, n_iters)
self.intercept_ = self._theta[0]
self.coef_ = self._theta[1:]
return self
#预测X中每个样本label为1的概率
def predict_proba(self, X):
X_b = np.hstack([np.ones((len(X), 1)), X])
return self._sigmoid(X_b.dot(self._theta))
#预测
def predict(self, X):
proba = self.predict_proba(X)
result = np.array(proba >= 0.5, dtype='int')
return result
class OvR(object):
def __init__(self):
# 用于保存训练时各种模型的list
self.models = []
# 用于保存models中对应的正例的真实标签
# 例如第1个模型的正例是2,则real_label[0]=2
self.real_label = []
def fit(self, train_datas, train_labels):
'''
OvO的训练阶段,将模型保存到self.models中
:param train_datas: 训练集数据,类型为ndarray
:param train_labels: 训练集标签,类型为ndarray,shape为(-1,)
:return: None
'''
# 获取所有不同的类别标签
unique_labels = np.unique(train_labels)
for label in unique_labels:
# 创建一个新的二元分类器
binary_classifier = tiny_logistic_regression()
# 将当前类别作为正例,其余类别作为负例
binary_train_labels = (train_labels == label).astype(int)
# 训练二元分类器
binary_classifier.fit(train_datas, binary_train_labels)
# 保存训练好的模型和对应的真实标签
self.models.append(binary_classifier)
self.real_label.append(label)
def predict(self, test_datas):
'''
OvR的预测阶段
:param test_datas:测试集数据,类型为ndarray
:return:预测结果,类型为ndarray
'''
# 存储每个类别的预测概率
class_probabilities = []
for model in self.models:
# 对每个二元分类器进行预测
class_probabilities.append(model.predict_proba(test_datas))
# 将概率最高的类别作为预测结果
predicted_labels = np.array(self.real_label)[np.argmax(class_probabilities, axis=0)]
return predicted_labels