机器学习基本概念
- 有监督学习
- 分类、回归
- 无监督学习
- 聚类、降维
一维数组
import numpy as np
data = np.array([1,2,3,4,5])
print(data)
print(data.shape)
print(len(data.shape))
[1 2 3 4 5]
(5,)
1
二维数组
data2 = np.array([[1,2,3],[4,5,6]])
print(data2)
print(data2.shape)
print(len(data2.shape))
[[1 2 3]
[4 5 6]]
(2, 3)
2
稀疏矩阵
- scipy.sparse
可调用对象
- 函数,lambd表达式,类,类的方法,对象的方法,实现了特殊方法__call__的类的对象
样本
- 定义:样本是数据集中单个数据点的具体实例。每个样本由一组特征和可能的目标值组成。
- 例子:在房价预测中,一个样本可以是一个房屋,包含特征(如面积、卧室数量)和目标值(房价)。
特征、特征向量
- 特征:描述样本属性的变量,例如年龄、身高、性别。
- 特征向量:将一个样本的所有特征组合成一个向量(数组),表示该样本。
- 例子:对于一个人,特征可能是 [年龄: 25, 性别: 男, 身高: 175cm]。
特征提取器
- 定义:一种方法或算法,用于从原始数据中提取有意义的特征。
- 例子:
- 从文本中提取关键词。
- 从图像中提取边缘或纹理特征(如 HOG 特征)。
- 例子:
目标
- 定义:机器学习模型试图预测的值。
- 例子:
- 分类问题中的类别(例如,猫或狗)。
- 回归问题中的数值(例如,房价)。
- 例子:
偏差、方差
- 偏差:模型预测值与真实值之间的平均差距,表示模型的拟合能力。高偏差可能导致欠拟合。
- 方差:模型对训练数据中噪声的敏感程度。高方差可能导致过拟合。
- 例子:
- 偏差高的模型可能会忽略数据中的重要模式。
- 方差高的模型可能会记住训练数据中的噪声。
- 例子:
维度
- 定义:特征的数量。每个特征可以被看作数据的一个维度。
- 例子:
- 如果一个样本有 3 个特征(年龄、身高、体重),则数据是 3 维的。
- 例子:
早停法
- 定义:一种正则化技术,当验证集的性能不再提升时提前终止训练,以防止过拟合。
- 作用:通过停止训练,避免模型过度学习训练数据。
评估度量
- 定义:用来衡量模型性能的指标。
- 分类问题:准确率、召回率、F1 分数。
- 回归问题:均方误差 (MSE)、平均绝对误差 (MAE)。
拟合
- 定义:训练模型使其学习数据模式的过程。
- 过拟合:模型学习了训练数据中的噪声。
- 欠拟合:模型未能充分学习数据模式。
填充算法
- 定义:处理缺失数据的算法。
- 例子:用均值、中位数或众数填充缺失值。
数据泄漏
- 定义:训练数据中包含了测试数据的信息,导致模型性能虚高。
- 例子:将目标变量作为特征的一部分。
有监督学习
- 定义:使用带标签的数据进行训练。
- 例子:预测房价,数据包含历史房价(标签)。
半监督学习
- 定义:使用少量带标签数据和大量未带标签数据进行训练。
- 例子:网页分类,部分网页有类别标签,部分没有。
无监督学习
- 定义:不使用标签数据,模型通过数据的结构进行学习。
- 例子:聚类分析(如 K-Means)。
分类器
- 定义:将输入数据分到特定类别的模型。
- 例子:支持向量机(SVM)、决策树。
聚类器
- 定义:将数据分组为若干簇的算法。
- 例子:K-Means、层次聚类。
离群点检测器
- 定义:检测数据中的异常点。
- 例子:银行系统检测信用卡欺诈。
交叉验证生成器
- 定义:生成交叉验证的训练集和验证集。
- 作用:确保模型性能的评估更加稳定。
损失函数
- 定义:衡量模型预测值和真实值之间差异的函数。
- 例子:均方误差 (MSE)、交叉熵损失。
梯度下降
- 定义:一种优化算法,通过最小化损失函数找到模型的最佳参数。
- 变种:
- 批量梯度下降:使用整个数据集计算梯度。
- 随机梯度下降 (SGD):每次只用一个样本更新梯度。
- 变种:
正则化
- 定义:防止模型过拟合的一种方法,通过限制模型的复杂度。
- 例子:L1 正则化(Lasso)、L2 正则化(Ridge)。
泛化
- 定义:模型在未见过的数据上的表现能力。
- 良好的泛化能力:模型在训练集和测试集上都能表现良好。
学习曲线
- 定义:显示模型性能随训练数据量变化的曲线。
- 作用:帮助诊断过拟合或欠拟合。
召回率
- 定义:模型正确识别出所有正例的比例。
- 公式:召回率 = 真正例 / (真正例 + 假反例)
准确率
- 定义:模型预测正确的样本占总样本的比例。
- 公式:准确率 = (真正例 + 真反例) / 总样本数
机器学习库scikit-learn简介
# datasets -包含加载常用数据集的函数和生成随机数据的函数
线性回归算法原理与应用
1.简单线性回归(预测儿童身高)
import copy
import numpy as np
from sklearn import linear_model
# 训练数据,每一行表示一个样本,包含的信息分别为:
# 儿童年龄,性别(0女1男)
# 父亲、母亲、祖父、祖母、外祖父、外祖母的身高
x = np.array([[1, 0, 180, 165, 175, 165, 170, 165],
[3, 0, 180, 165, 175, 165, 173, 165],
[4, 0, 180, 165, 175, 165, 170, 165],
[6, 0, 180, 165, 175, 165, 170, 165],
[8, 1, 180, 165, 175, 167, 170, 165],
[10, 0, 180, 166, 175, 165, 170, 165],
[11, 0, 180, 165, 175, 165, 170, 165],
[12, 0, 180, 165, 175, 165, 170, 165],
[13, 1, 180, 165, 175, 165, 170, 165],
[14, 0, 180, 165, 175, 165, 170, 165],
[17, 0, 170, 165, 175, 165, 170, 165]])
# 儿童身高,单位:cm
y = np.array([60, 90, 100, 110, 130, 140, 150, 164, 160, 163, 168])
# 创建线性回归模型
lr = linear_model.LinearRegression()
# 根据已知数据拟合最佳直线
lr.fit(x, y)
# 待测的未知数据,其中每个分量的含义和训练数据相同
xs = np.array([[10, 0, 180, 165, 175, 165, 170, 165],
[17, 1, 173, 153, 175, 161, 170, 161],
[34, 0, 170, 165, 170, 165, 170, 165]])
for item in xs:
# 为不改变原始数据,进行深复制,并假设超过18岁以后就不再长高了
# 对于18岁以后的年龄,返回18岁时的身高
item1 = copy.deepcopy(item)
if item1[0] > 18:
item1[0] = 18
print(item, ':', lr.predict(item1.reshape(1,-1)))
[ 10 0 180 165 175 165 170 165] : [140.56153846]
[ 17 1 173 153 175 161 170 161] : [158.41]
[ 34 0 170 165 170 165 170 165] : [176.03076923]
2.岭回归
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import RidgeClassifier
from sklearn.model_selection import train_test_split
# 加载乳腺癌数据,共569个样本,每个样本有30个特征
X, y = load_breast_cancer(return_X_y=True)
# 使用默认参数创建岭回归分类器对象
clf = RidgeClassifier()
# 划分训练集与测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# 使用训练集拟合模型
clf.fit(X_train, y_train)
# 使用测试集,评估模型得分
print(clf.score(X_test, y_test))
0.9649122807017544
3.Lasso回归
from time import time
from scipy.sparse import coo_matrix
from sklearn.datasets import make_regression
from sklearn.linear_model import Lasso
X, y = make_regression(n_samples=1000, n_features=8000, # 样本数量,特征数量
n_informative=20, # 实际有效的特征数量
noise=0.9, # 高斯噪声的标准差
random_state=20230409, # 使得每次运行结果相同
)
# 把部分数据置0,使数据稀疏
X[X<2] = 0
# 创建压缩稀疏列格式的矩阵,可以使用toarray()转换为稠密格式的数组
X_sparse = coo_matrix(X).tocsc()
# 查看压缩比,nnz属性的值为稀疏矩阵实际保存的数据个数
print(f'压缩后数据量变为原来的:{X_sparse.nnz/X.size:.3%}')
# 创建套索回归对象,参数alpha的值越大,选择的特征数量越少
estimator = Lasso(alpha=3, fit_intercept=False, max_iter=10000)
# 使用原始数据拟合模型,记录所用时间以及训练后的模型参数
start = time()
estimator.fit(X, y)
print(f'原始稠密数据训练用时:{time()-start}秒')
coef_dense = estimator.coef_
# 使用稀疏矩阵格式的数据重新拟合模型,记录所用时间以及训练后的模型参数
start = time()
estimator.fit(X_sparse, y)
print(f'稀疏矩阵格式的数据训练用时:{time()-start}秒')
coef_sparse = estimator.coef_
print(f'两种格式的数据训练后模型参数之差的最大值为:{(coef_sparse-coef_dense).max()}')
压缩后数据量变为原来的:2.271%
原始稠密数据训练用时:0.8571333885192871秒
稀疏矩阵格式的数据训练用时:0.21027755737304688秒
两种格式的数据训练后模型参数之差的最大值为:7.72715225139109e-14
逻辑回归算法基本原理与应用
使用logistic回归预测考试是否及格
from sklearn.linear_model import LogisticRegression
# 复习情况,格式为(时长,效率),其中时长等位为小时
X_train = [(1, 0),(3, 0.5),(4, 0.5),(6, 0.5),(8, 1),(10, 1),(11, 1),(12, 1),(13, 1),(14, 1),(17, 1)]
y_train = [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
# 创建逻辑回归模型
reg = LogisticRegression()
# 拟合模型
reg.fit(X_train, y_train)
# 测试数据
X_test = [(3,0.5) ,(8,1) ,(9,1) ,(10,0)]
y_test = [0, 1, 1, 0]
score = reg.score(X_test, y_test)
print("模型的准确率为:", score)
# 预测
learning = [(8.5,0.5)]
result = reg.predict_proba(learning)
msg = '''模型得分为:{0}
复习时长为:{1[0]}小时,效率为:{1[1]}
预测为及格的概率为:{2[1]}
预测为不及格的概率为:{2[0]}
及格的概率为:{2[1]}
综合判断,您会:{3}'''.format(score, learning[0], result[0], "不及格" if result[0][0] > 0.5 else "及格")
print(msg)
# 使用递归算法寻找最优参数得出最小复习时长可以及格
def find_min_study_time(current_hours, efficiency, model, increment=0.1, max_hours=24.0):
"""
使用递归算法寻找在给定效率下,能够及格的最小复习时长。
:param current_hours: 当前尝试的复习时长
:param efficiency: 复习效率 (0到1之间)
:param model: 训练好的逻辑回归模型
:param increment: 每次递归增加的时长
:param max_hours: 允许尝试的最大复习时长
:return: 最小及格复习时长,如果超过max_hours仍未及格则返回None
"""
if current_hours > max_hours:
return None # 超过最大时长限制,未找到
test_data = [(current_hours, efficiency)]
pass_probability = model.predict_proba(test_data)[0][1] # 获取及格的概率
if pass_probability > 0.5:
return current_hours # 找到最小及格时长
else:
# 递归调用,增加时长
return find_min_study_time(current_hours + increment, efficiency, model, increment, max_hours)
# 示例:寻找效率为0.5时的最小及格复习时长
efficiency_to_test = 0.5
initial_hours = 0.1 # 从一个较小的初始时长开始
min_time_eff_0_5 = find_min_study_time(initial_hours, efficiency_to_test, reg)
if min_time_eff_0_5 is not None:
print(f"\n在效率为 {efficiency_to_test} 时,预测的最小及格复习时长为: {min_time_eff_0_5:.1f} 小时")
# 验证一下这个时长
prob_eff_0_5 = reg.predict_proba([(min_time_eff_0_5, efficiency_to_test)])[0]
print(f" - 对应及格概率: {prob_eff_0_5[1]:.4f}, 不及格概率: {prob_eff_0_5[0]:.4f}")
else:
print(f"\n在效率为 {efficiency_to_test} 时,在 {max_hours} 小时内未能找到及格的复习时长。")
# 示例:寻找效率为1.0时的最小及格复习时长
efficiency_to_test_2 = 1.0
min_time_eff_1_0 = find_min_study_time(initial_hours, efficiency_to_test_2, reg)
if min_time_eff_1_0 is not None:
print(f"\n在效率为 {efficiency_to_test_2} 时,预测的最小及格复习时长为: {min_time_eff_1_0:.1f} 小时")
# 验证一下这个时长
prob_eff_1_0 = reg.predict_proba([(min_time_eff_1_0, efficiency_to_test_2)])[0]
print(f" - 对应及格概率: {prob_eff_1_0[1]:.4f}, 不及格概率: {prob_eff_1_0[0]:.4f}")
else:
print(f"\n在效率为 {efficiency_to_test_2} 时,在 {max_hours} 小时内未能找到及格的复习时长。")
# 以上代码实现了一个简单的逻辑回归模型来预测复习情况,并使用递归算法寻找在给定效率下,能够及格的最小复习时长。
模型的准确率为: 0.75
模型得分为:0.75
复习时长为:8.5小时,效率为:0.5
预测为及格的概率为:0.8134531096860228
预测为不及格的概率为:0.1865468903139772
及格的概率为:0.8134531096860228
综合判断,您会:及格
在效率为 0.5 时,预测的最小及格复习时长为: 7.1 小时
- 对应及格概率: 0.5183, 不及格概率: 0.4817
在效率为 1.0 时,预测的最小及格复习时长为: 7.0 小时
- 对应及格概率: 0.5141, 不及格概率: 0.4859
8.5朴素贝叶斯算法原理与应用(中文邮件分类)
import numpy as np
x= np.array([[-1,-1],[-2,-1],[-3,-2],[1,1],[2,1],[3,2]])
y=np.array([1,1,1, 2,2, 2])
from sklearn.naive_bayes import GaussianNB
clf = GaussianNB()#创建高斯朴素贝叶斯模型
clf.fit(x,y)#训练模型
GaussianNB(priors=None)
clf.predict([[-0.8,-1]])
array([1])
# 分类
clf.predict_proba([[-0.8,-1]])#样本属于不同类别的概率
clf.score([[-0.8, -1]],[1])
1.0
# 评分
clf.score([[-0.8, -1],[0, 0]],[1, 2]) # 评分
0.5
重要:中文邮件分类
- 对文件夹贝叶斯中文邮件分类中的份邮件的文本内容进行训练,其中0.txt 到 126.txt 为垃圾邮件,127.txt 到 253.txt 为正常邮件,模型训练结束后使用 5 封邮件 (151.txt 到 155.txt)的文本内容进行测试,判断这 5 封邮件是否为垃圾邮件。
from re import sub
from os import listdir
from collections import Counter
from itertools import chain
from numpy import array
from jieba import cut
from sklearn.naive_bayes import MultinomialNB
def getWordsFromFile(txtFile):
# 获取每一封邮件中的所有词语
words = []
# 所有存储邮件文本内容的记事本文件都使用UTF8编码
with open(txtFile, encoding='utf8') as fp:
for line in fp:
# 遍历每一行,删除两端的空白字符
line = line.strip()
# 过滤干扰字符或无效字符
line = sub(r'[.【】0-9、—。,!~\*]', '', line)
# 分词
line = cut(line)
# 过滤长度为1的词
line = filter(lambda word: len(word)>1, line)
# 把本行文本预处理得到的词语添加到words列表中
words.extend(line)
# 返回包含当前邮件文本中所有有效词语的列表
return words
# 存放所有文件中的单词
# 每个元素是一个子列表,其中存放一个文件中的所有单词
allWords = []
def getTopNWords(topN):
# 按文件编号顺序处理当前文件夹中所有记事本文件
# 训练集中共151封邮件内容,0.txt到126.txt是垃圾邮件内容
# 127.txt到150.txt为正常邮件内容
txtFiles = [str(i)+'.txt' for i in range(151)]
# 获取训练集中所有邮件中的全部单词
for txtFile in txtFiles:
allWords.append(getWordsFromFile(txtFile))
# 获取并返回出现次数最多的前topN个单词
freq = Counter(chain(*allWords))
return [w[0] for w in freq.most_common(topN)]
# 全部训练集中出现次数最多的前600个单词
topWords = getTopNWords(600)
# 获取特征向量,前600个单词的每个单词在每个邮件中出现的频率
vectors = []
for words in allWords:
temp = list(map(lambda x: words.count(x), topWords))
vectors.append(temp)
vectors = array(vectors)
# 训练集中每个邮件的标签,1表示垃圾邮件,0表示正常邮件
labels = array([1]*127 + [0]*24)
# 创建模型,使用已知训练集进行训练
model = MultinomialNB()
model.fit(vectors, labels)
def predict(txtFile):
# 获取指定邮件文件内容,返回分类结果
words = getWordsFromFile(txtFile)
currentVector = array(tuple(map(lambda x: words.count(x),
topWords)))
result = model.predict(currentVector.reshape(1, -1))[0]
return '垃圾邮件' if result==1 else '正常邮件'
# 151.txt至155.txt为测试邮件内容
for mail in ('%d.txt'%i for i in range(151, 156)):
print(mail, predict(mail), sep=':')
151.txt:垃圾邮件
152.txt:垃圾邮件
153.txt:垃圾邮件
154.txt:垃圾邮件
155.txt:正常邮件
方式二:训练模型进行保存,格式化存储,直接调用函数进行训练识别
from re import sub
from jieba import cut
def getWordsFromFile(txtFile):
# 获取每一封邮件中的所有词语
words = []
# 所有存储邮件文本内容的记事本文件都使用UTF8编码
with open(txtFile, encoding='utf8') as fp:
for line in fp:
# 遍历每一行,删除两端的空白字符
line = line.strip()
# 过滤干扰字符或无效字符
line = sub(r'[.【】0-9、—。,!~\*]', '', line)
# 分词
line = cut(line)
# 过滤长度为1的词
line = filter(lambda word: len(word)>1, line)
# 把本行文本预处理得到的词语添加到words列表中
words.extend(line)
# 返回包含当前邮件文本中所有有效词语的列表
return words
from os import listdir
from collections import Counter
from itertools import chain
from numpy import array
from sklearn.externals import joblib
from sklearn.naive_bayes import MultinomialNB
from get_words_from_file import getWordsFromFile
# 存放所有文件中的单词
# 每个元素是一个子列表,其中存放一个文件中的所有单词
allWords = []
def getTopNWords(topN):
# 按文件编号顺序处理当前文件夹中所有记事本文件
# 训练集中共151封邮件内容,0.txt到126.txt是垃圾邮件内容
# 127.txt到150.txt为正常邮件内容
txtFiles = [str(i)+'.txt' for i in range(151)]
# 获取训练集中所有邮件中的全部单词
for txtFile in txtFiles:
allWords.append(getWordsFromFile(txtFile))
# 获取并返回出现次数最多的前topN个单词
freq = Counter(chain(*allWords))
return [w[0] for w in freq.most_common(topN)]
# 全部训练集中出现次数最多的前600个单词
topWords = getTopNWords(600)
# 获取特征向量,前600个单词的每个单词在每个邮件中出现的频率
vectors = []
for words in allWords:
temp = list(map(lambda x: words.count(x), topWords))
vectors.append(temp)
vectors = array(vectors)
# 训练集中每个邮件的标签,1表示垃圾邮件,0表示正常邮件
labels = array([1]*127 + [0]*24)
# 创建模型,使用已知训练集进行训练
model = MultinomialNB()
model.fit(vectors, labels)
joblib.dump(model, "垃圾邮件分类器.pkl")
print('保存模型和训练结果成功。')
with open('topWords.txt', 'w', encoding='utf8') as fp:
fp.write(','.join(topWords))
print('保存topWords成功。')
from numpy import array
from sklearn.externals import joblib
from sklearn.naive_bayes import MultinomialNB
from get_words_from_file import getWordsFromFile
model = joblib.load("垃圾邮件分类器.pkl")
print('加载模型和训练结果成功。')
with open('topWords.txt', encoding='utf8') as fp:
topWords = fp.read().split(',')
def predict(txtFile):
# 获取指定邮件文件内容,返回分类结果
words = getWordsFromFile(txtFile)
currentVector = array(tuple(map(lambda x: words.count(x),
topWords)))
result = model.predict(currentVector.reshape(1, -1))[0]
return '垃圾邮件' if result==1 else '正常邮件'
# 151.txt至155.txt为测试邮件内容
for mail in ('%d.txt'%i for i in range(151, 156)):
print(mail, predict(mail), sep=':')
151.txt:垃圾邮件
152.txt:垃圾邮件
153.txt:垃圾邮件
154.txt:垃圾邮件
155.txt:正常邮件
8.6决策树与随机森林算法原理与应用
基尼值 G i n i = 1 − ∑ i = 1 n P i 2 Gini=1-\sum_{i=1}^{n}P_i^{2} Gini=1−∑i=1nPi2(考点)
使用python决策树算法实现学员的python水平
import numpy as np
from sklearn import tree
questions = ('《Python程序设计与数据采集》',
'《Python数据分析、挖掘与可视化》',
'《Python程序设计基础(第3版)》',
'《Python程序设计基础与应用(第2版)》',
'《Python程序设计实例教程(第2版)》',
'《Python程序设计(第3版)》', '《Python网络程序设计》',
'《Python数据分析与数据可视化》',
'《大数据的Python基础(第2版)》',
'《Python程序设计开发宝典》',
'《Python可以这样学》', '《中学生可以这样学Python》',
'《Python编程基础与案例集锦(中学版)》',
'《Python程序设计实验指导书》',
'《Python程序设计入门与实践》',
'《Python程序设计实用教程》',
'微信公众号“Python小屋”的免费资料')
# 每个样本的数据含义:0没看过,1很多看不懂,2大部分可以看懂,3没压力
answers = [[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 2, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 2, 2, 2, 1],
[2, 2, 3, 3, 3, 1, 1, 1, 3, 2, 2, 3, 3, 3, 0, 3, 2],
[2, 2, 3, 2, 2, 1, 1, 3, 1, 2, 2, 3, 3, 2, 2, 2, 1],
[3, 3, 3, 0, 3, 2, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 2],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3],
[0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
]
labels = ['超级高手', '门外汉', '初级选手', '初级选手', '高级选手',
'中级选手', '高级选手', '超级高手', '初级选手', '初级选手']
clf = tree.DecisionTreeClassifier().fit(answers, labels) # 训练
yourAnswer = []
print('在下面的问卷中,'
'没看过输入0,很多看不懂输入1,大部分可以看懂输入2,没压力输入3')
# 显示调查问卷,并接收用户输入
for question in questions:
print('=========\n你看过董付国老师的', question, '吗?')
# 确保输入有效
while True:
try:
answer = int(input('请输入:'))
assert 0<=answer<=3
break
except:
print('输入无效,请重新输入。')
pass
yourAnswer.append(answer)
print(clf.predict(np.array(yourAnswer).reshape(1,-1))) # 分类
在下面的问卷中,没看过输入0,很多看不懂输入1,大部分可以看懂输入2,没压力输入3
=========
你看过董付国老师的 《Python程序设计与数据采集》 吗?
请输入: 1
=========
你看过董付国老师的 《Python数据分析、挖掘与可视化》 吗?
请输入: 1
=========
你看过董付国老师的 《Python程序设计基础(第3版)》 吗?
请输入: 1
=========
你看过董付国老师的 《Python程序设计基础与应用(第2版)》 吗?
请输入: 1
=========
你看过董付国老师的 《Python程序设计实例教程(第2版)》 吗?
请输入: 1
=========
你看过董付国老师的 《Python程序设计(第3版)》 吗?
请输入: 1
=========
你看过董付国老师的 《Python网络程序设计》 吗?
请输入: 1
=========
你看过董付国老师的 《Python数据分析与数据可视化》 吗?
请输入: 1
=========
你看过董付国老师的 《大数据的Python基础(第2版)》 吗?
请输入: 1
=========
你看过董付国老师的 《Python程序设计开发宝典》 吗?
请输入: 1
=========
你看过董付国老师的 《Python可以这样学》 吗?
请输入: 1
=========
你看过董付国老师的 《中学生可以这样学Python》 吗?
请输入: 1
=========
你看过董付国老师的 《Python编程基础与案例集锦(中学版)》 吗?
请输入: 1
=========
你看过董付国老师的 《Python程序设计实验指导书》 吗?
请输入: 1
=========
你看过董付国老师的 《Python程序设计入门与实践》 吗?
请输入: 1
=========
你看过董付国老师的 《Python程序设计实用教程》 吗?
请输入: 1
=========
你看过董付国老师的 微信公众号“Python小屋”的免费资料 吗?
请输入: 1
['初级选手']
支持向量机(实现手写文子数字图像分类)
'''
from os import mkdir, listdir
from os.path import isdir, basename
from random import choice, randrange
from string import digits
from PIL import Image, ImageDraw # pillow
from PIL.ImageFont import truetype
from sklearn import svm
from sklearn.model_selection import train_test_split
# 图像尺寸、图片中的数字字体大小、噪点比例
width, height = 30, 60
fontSize = 40
noiseRate = 8
def generateDigits(dstDir='datasets1', num=400):
# 生成num个包含数字的图片文件存放于当前目录下的datasets子目录
if not isdir(dstDir):
mkdir(dstDir)
# digits.txt用来存储每个图片对应的数字
with open(dstDir+'/digits.txt', 'w') as fp:
font = truetype('SimHei.ttf',
fontSize)
for i in range(num):
# 随机选择一个数字,生成对应的彩色图像文件
digit = choice(digits)
im = Image.new('RGB', (width,height), (255,255,255))
imDraw = ImageDraw.Draw(im)
imDraw.text((0,0), digit, font=font, fill=(0,0,0))
# 加入随机干扰
for j in range(int(noiseRate*width*height)):
w, h = randrange(1, width-1), randrange(height)
# 水平交换两个相邻像素的颜色
c1 = im.getpixel((w,h))
c2 = im.getpixel((w+1,h))
imDraw.point((w,h), fill=c2)
imDraw.point((w+1,h), fill=c1)
im.save(dstDir+'/'+str(i)+'.jpg')
fp.write(digit+'\n')
def loadDigits(dstDir='datasets1'):
# 获取所有图像文件名
digitsFile = [dstDir+'/'+fn for fn in listdir(dstDir)
if fn.endswith('.jpg')]
# 按编号排序,1.jpg,10.jpg,100.jpg
digitsFile.sort(key=lambda fn: int(basename(fn)[:-4]))
# digitsData用于存放读取的图片中数字信息
# 每个图片中所有像素值存放于digitsData中的一行数据
digitsData = []
for fn in digitsFile:
with Image.open(fn) as im:
data = [sum(im.getpixel((w,h)))/len(im.getpixel((w,h)))
for w in range(width)
for h in range(height)]
digitsData.append(data)
# digitsLabel用于存放图片中数字的标准分类
with open(dstDir+'/digits.txt') as fp:
digitsLabel = fp.readlines()
# digitsLabel = [label.strip() for label in digitsLabel]
digitsLabel = list(map(str.strip, digitsLabel))
return (digitsData, digitsLabel)
# 生成图片文件
generateDigits(num=100)
# 加载数据
data = loadDigits()
print('数据加载完成。')
# 随机划分训练集和测试集,其中参数test_size用来指定测试集大小
X_train, X_test, y_train, y_test = train_test_split(data[0],
data[1],
test_size=0.1)
# 创建并训练模型
svcClassifier = svm.SVC(kernel="linear", C=1000, gamma=0.001)
svcClassifier.fit(X_train, y_train)
print('模型训练完成。')
# 使用测试集对模型进行评分
score = svcClassifier.score(X_test, y_test)
print('模型测试得分:', score)
'''
KNN算法原理与应用
使用KNN判断交通工具类型
from sklearn.neighbors import KNeighborsClassifier
# X中存储交通工具的参数
# 总长度(米)、时速(km/h)、重量(吨)、座位数量
X = [[96, 85, 120, 400], # 普通火车
[144, 92, 200, 600],
[240, 87, 350, 1000],
[360, 90, 495, 1300],
[384, 91, 530, 1405],
[240, 360, 490, 800], # 高铁
[360, 380, 750, 1200],
[290, 380, 480, 960],
[120, 320, 160, 400],
[384, 340, 520, 1280],
[33.4, 918, 77, 180], # 飞机
[33.6, 1120, 170.5, 185],
[39.5, 785, 230, 240],
[33.84, 940, 150, 195],
[44.5, 920, 275, 275],
[75.3, 1050, 575, 490]]
# y中存储类别,0表示普通火车,1表示高铁,2表示飞机
y = [0]*5+[1]*5+[2]*6
# labels中存储对应的交通工具名称
labels = ('普通火车', '高铁', '飞机')
# 创建并训练模型
knn = KNeighborsClassifier(n_neighbors=3,
weights='distance')
knn.fit(X, y)
# 对未知样本进行分类
unKnown = [[300, 79, 320, 900],
[36.7, 800, 190, 220]]
result = knn.predict(unKnown)
for para, index in zip(unKnown, result):
print(para, labels[index], sep=':')
[300, 79, 320, 900]:普通火车
[36.7, 800, 190, 220]:飞机
KMeans聚类分析算法原理与应用
颜色图像处理
import numpy as np
from sklearn.cluster import KMeans
from PIL import Image
import matplotlib.pyplot as plt
from copy import deepcopy
# 打开并读取原始图像中像素颜色值,转换为三维数组
imOrigin = Image.open('颜色压缩测试图像.jpg')
dataOrigin = np.array(imOrigin)
# 然后再转换为二维数组,-1表示自动计算该维度的大小
data = dataOrigin.reshape(-1,3)
n_clusters = 64
while n_clusters >= 4:
plt.cla()
print(n_clusters)
# 使用KMeans算法把所有像素的颜色值划分为4类
kmeansPredicter = KMeans(n_clusters=n_clusters)
kmeansPredicter.fit(data)
# 使用每个像素所属类的中心值替换该像素的颜色
# temp中存放每个数据所属类的标签
temp = kmeansPredicter.labels_
dataNew = kmeansPredicter.cluster_centers_[temp]
data = deepcopy(dataNew)
dataNew = np.uint8(dataNew)
dataNew.shape = dataOrigin.shape
plt.imshow(dataNew)
plt.pause(0.01)
n_clusters //= 2
KMeans聚类算法压缩图像颜色
import numpy as np
from sklearn.cluster import KMeans
from PIL import Image
import matplotlib.pyplot as plt
# 打开并读取原始图像中像素颜色值,转换为三维数组
imOrigin = Image.open('颜色压缩测试图像.jpg')
dataOrigin = np.array(imOrigin)
# 然后再转换为二维数组,-1表示自动计算该维度的大小
data = dataOrigin.reshape(-1,3)
# 使用KMeans算法把所有像素的颜色值划分为4类
kmeansPredicter = KMeans(n_clusters=4, n_init=10)
kmeansPredicter.fit(data)
# 使用每个像素所属类的中心值替换该像素的颜色
# temp中存放每个数据所属类的标签
temp = kmeansPredicter.labels_
dataNew = kmeansPredicter.cluster_centers_[temp]
dataNew = np.uint8(dataNew)
dataNew.shape = dataOrigin.shape
plt.imshow(dataNew)
plt.imsave('结果图像.jpg', dataNew)
plt.show()
分层聚类算法原理与应用
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.cluster import AgglomerativeClustering
def AgglomerativeTest(n_clusters):
assert 1 <= n_clusters <= 4
predictResult = AgglomerativeClustering(n_clusters=n_clusters,
linkage='ward').fit_predict(data)
# 定义绘制散点图时使用的颜色和散点符号
colors = 'rgby'
markers = 'o*v+'
# 依次使用不同的颜色和符号绘制每个类的散点图
for i in range(n_clusters):
subData = data[predictResult==i]
plt.scatter(subData[:,0], subData[:,1], c=colors[i], marker=markers[i], s=40)
plt.show()
# 生成随机数据,200个点,分成4类,返回样本及标签
data, labels = make_blobs(n_samples=200, centers=4)
print(data)
AgglomerativeTest(4)
DBSCAN算法原理与应用
- 基于密度相连对象的最大集合
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_blobs
def DBSCANtest(data, eps=0.6, min_samples=8):
# 聚类
db = DBSCAN(eps=eps, min_samples=min_samples).fit(data)
# 聚类标签(数组,表示每个样本所属聚类)和所有聚类的数量
# 标签-1对应的样本表示噪点
clusterLabels = db.labels_
uniqueClusterLabels = set(clusterLabels)
# 标记核心对象对应下标为True
coreSamplesMask = np.zeros_like(db.labels_, dtype=bool)
coreSamplesMask[db.core_sample_indices_] = True
# 绘制聚类结果
colors = ['red', 'green', 'blue', 'gray', '#88ff66',
'#ff00ff', '#ffff00', '#8888ff', 'black',]
markers = ['v', '^', 'o', '*', 'h', 'd', 'D', '>', 'x']
for label in uniqueClusterLabels:
# 使用最后一种颜色和符号绘制噪声样本
# clusterIndex是个True/False数组
# 其中True表示对应样本为cluster类
clusterIndex = (clusterLabels==label)
# 绘制核心对象
coreSamples = data[clusterIndex&coreSamplesMask]
plt.scatter(coreSamples[:, 0], coreSamples[:, 1],
c=colors[label], marker=markers[label],
s=100)
# 绘制非核心对象
nonCoreSamples = data[clusterIndex & ~coreSamplesMask]
plt.scatter(nonCoreSamples[:, 0], nonCoreSamples[:, 1],
c=colors[label], marker=markers[label],
s=20)
plt.show()
data, labels = make_blobs(n_samples=300, centers=5)
DBSCANtest(data)
#DBSCANtest(data, 0.8, 15)
协同过滤算法进行电影推荐(期末考试重点)
- 协同过滤算法常用于商品推荐或者类似的场合,根据用户之间或商品之间的相似性进行精准推荐,可以分为基于用户的协同过滤算法和基于商品的协同过滤算法。
- 以电影推荐为例,假设用户1喜欢看电影A、B、C、D、G,用户2喜欢看电影A、D、E、F,用户3喜欢看电影A、B、D,现在用户3想再看个没看过的电影,向用户1和用户2寻求推荐。简单分析易知,与用户2相比,用户1和用户3更相似,所以根据用户1喜欢的电影进行推荐,也就是用户1看过但用户3还没看过的电影C或G。
协同过滤算法是推荐系统中最常用的方法之一,以下是对您描述内容的进一步整理和分析:
协同过滤算法的基本概念
- 协同过滤算法的核心思想是利用用户或商品之间的相似性,推荐用户可能感兴趣的内容。
- 分类:
- 基于用户的协同过滤:根据用户之间的相似性推荐商品。
- 基于商品的协同过滤:根据商品之间的相似性推荐商品。
以电影推荐为例
数据:
- 用户1看过:A、B、C、D、G
- 用户2看过:A、D、E、F
- 用户3看过:A、B、D
- 目标:为用户3推荐一部电影。
分析:
计算用户相似性:
- 用户3与用户1的共有电影:A、B、D,共3部。
- 用户3与用户2的共有电影:A、D,共2部。
- 结论:用户3与用户1更相似。
推荐过程:
- 找出用户1看过但用户3没看过的电影:C、G。
- 推荐结果:C 或 G。
协同过滤算法的步骤
1. 数据表示
构建用户-商品偏好矩阵。例如:
A B C D E F G
用户1 1 1 1 1 0 0 1
用户2 1 0 0 1 1 1 0
用户3 1 1 0 1 0 0 0
其中:
- 1 表示用户看过某电影。
- 0 表示用户没看过某电影。
2. 计算相似性
- 使用相似性度量方法(如余弦相似度、皮尔逊相关系数)计算用户之间的相似性。
- 例如,余弦相似度公式:
相似度 ( 用户 A , 用户 B ) = A和B的交集数 A的电影数 × B的电影数 \text{相似度}(用户A, 用户B) = \frac{\text{A和B的交集数}}{\sqrt{\text{A的电影数}} \times \sqrt{\text{B的电影数}}} 相似度(用户A,用户B)=A的电影数×B的电影数A和B的交集数
3. 推荐候选集
- 找出与目标用户最相似的用户。
- 从相似用户看过但目标用户未看过的商品中选择推荐。
4. 生成推荐
- 对候选商品进行排序(例如根据相似用户的评分权重排序)。
- 推荐排名靠前的商品。
优缺点
优点:
- 简单易实现,推荐结果可解释性强。
- 无需商品的具体内容信息,适用于各种类型的数据。
缺点:
- 冷启动问题:对新用户或新商品,缺乏足够的数据支撑相似性计算。
- 稀疏性问题:用户-商品矩阵通常非常稀疏,可能导致相似性难以计算准确。
- 扩展性问题:随着用户和商品数量的增加,计算相似性可能变得非常耗时。
改进方向
- 结合内容信息:在协同过滤中加入商品的内容特征(如电影的类型、导演信息)。
- 矩阵分解:将用户-商品矩阵分解为低维的用户和商品向量,例如 SVD(奇异值分解)。
- 引入深度学习:使用神经网络建模用户和商品的关系,例如通过嵌入层学习用户和商品的隐式特征。
from random import randrange
#模拟历史电影打分数据,共10个用户,每个用户打分的电影数量不等
data = {'user'+str(i):{'film'+str(randrange(1, 15)):randrange(1, 6)
for j in range (randrange(3, 10))}
for i in range(10)}
# 寻求推荐的用户对电影打分的数据
user = {'film'+str (randrange (1, 15)):randrange (1, 6) for i in range (5)}
#最相似的用户及其对电影打分情况
#两个最相似的用户共同打分的电影最多,同时所有电影打分差值的平方和最小
rule = lambda item:(-len(item[1].keys ()&user),
sum(((item[1].get(film) -user.get (film))**2
for film in user.keys()&item[1].keys())))
similarUser, films = min(data.items (),key=rule)
#输出信息以便验证,每行数据有3列
#分别为该用户与当前用户共同打分的电影数量、打分差的平方和、该用户打分数据
print ('known data'.center(50,'='))
for item in data.items ():
print (len(item[1].keys ()&user.keys()),
sum(((item[l].get(film) -user.get (film))**2
for film in user.keys ()&item[l].keys())),
item,
sep=':')
print('current user'.center (50, '='),user, sep='ln')
print('most similar user and his films'.center (50, '='))
print(similarUser, films, sep=':')
print ('recommended film'.center(50, '='))
#在当前用户没看过的电影中选择打分最高的进行推荐
print (max (films.keys ()-user.keys (), key=lanbda film: films[film]))
关联规则分析(期末考试重点)
常用概念:
- 项集:包含若干物品或条目的集合。包含k的物品的集合称作k-项集。
- 频繁项集:经常一起出现的物品的集合。如果某个项集是频繁的,那么它的所有子集都是频繁的;如果某个项集不是频繁的,那么它的所有超集都不是频繁的。这一点是避免页集数量过多的重要基础,使得快速计算频繁项集成为可能。
- 关联规则:可以表示为一个蕴含式R:X==>Y,其中X&Y为空集。这样一条关联规则的含义是,如果X发生,那么Y很可能也会发生。
项集
- 定义:项集是由若干物品(或条目)组成的集合。
- k-项集:如果一个项集中包含 ( k ) 个物品,则称其为 ( k )-项集。
- 例子:在购物篮分析中,{牛奶, 面包} 是一个 2-项集。
频繁项集
定义:频繁项集是指在数据集中经常出现的项集,满足用户设定的最小支持度阈值。
- 支持度:某个项集在数据集中出现的次数占总事务数的比例。
- 例子:如果 {牛奶, 面包} 出现在 60% 的交易中,并且最小支持度设定为 50%,则该项集为频繁项集。
性质:
- 子集性质:
- 如果一个项集是频繁项集,则它的所有子集也是频繁项集。
- 剪枝性质:
- 如果一个项集不是频繁项集,则它的所有超集都不是频繁项集。
- 作用:利用这些性质可以减少计算项集的数量,提高频繁项集挖掘的效率。
- 子集性质:
关联规则
定义:关联规则是从频繁项集中挖掘出的规则,表示某些物品之间的关联关系。规则的形式为:
R : X ⟹ Y R: X \implies Y R:X⟹Y- 解释:如果项集 ( X ) 发生,则 ( Y ) 很可能也会发生。
- 例子:{牛奶} ⇒ {面包},表示购买牛奶的人很可能也会购买面包。
指标:
- 支持度 (Support):
规则:
X ⟹ Y X \implies Y X⟹Y的支持度是 X ∪ Y X \cup Y X∪Y出现的概率。
S u p p o r t ( X ⟹ Y ) = 事务中同时包含 X 和 Y 的置信度 X 发生时 Y 也发生的概率。 Support(X \implies Y )= \frac{\text{事务中同时包含 } X \text{ 和 } Y \text{的} 置信度 }{X 发生时 Y 也发生的概率。} Support(X⟹Y)=X发生时Y也发生的概率。事务中同时包含 X 和 Y的置信度C o n f i d e n c e ( X ⟹ Y ) = 事务中同时包含 X 和 Y 的次数 事务表示 X 和 Y 是否独立。 Confidence(X \implies Y) = \frac{\text{事务中同时包含 } X \text{ 和 } Y \text{ 的次数}}{\text{事务表示 X 和 Y 是否独立。}} Confidence(X⟹Y)=事务表示 X 和 Y 是否独立。事务中同时包含 X 和 Y 的次数
L i f t ( X ⟹ Y ) = C o n f i d e n c e ( X ⟹ Y ) S u p p o r t ( Y ) Lift(X \implies Y) = \frac{Confidence(X \implies Y)}{Support(Y)} Lift(X⟹Y)=Support(Y)Confidence(X⟹Y)
例子:
- 给定事务数据:
T1: {牛奶, 面包, 黄油} T2: {牛奶, 面包} T3: {牛奶, 黄油} T4: {面包, 黄油}
- 规则 {牛奶} ⇒ {面包}:
- 支持度:2/4 = 50%
- 置信度:2/3 ≈ 66.7%
- 给定事务数据:
总结
- 项集:物品的集合,包含 ( k ) 个物品的集合称为 ( k )-项集。
- 频繁项集:满足最小支持度阈值,且具有子集和超集性质。
- 关联规则:从频繁项集中挖掘的规则,描述物品之间的关联性,通常通过支持度、置信度和提升度来衡量规则的质量。
代码实现(例如 Apriori 或 FP-Growth 算法)
import pandas as pd
# 使用关联规则算法分析演员关系
ws = pd.read_excel('电影导演演员.xlsx')
print(ws.head())
电影名称 导演 演员
0 电影1 导演1 演员1,演员2,演员3,演员4
1 电影2 导演2 演员3,演员2,演员4,演员5
2 电影3 导演3 演员1,演员5,演员3,演员6
3 电影4 导演1 演员1,演员4,演员3,演员7
4 电影5 导演2 演员1,演员2,演员3,演员8
from itertools import chain, combinations
from openpyxl import load_workbook
def loadDataSet():
'''加载数据,返回包含若干集合的列表'''
# 返回的数据格式为 [{1, 3, 4}, {2, 3, 5}, {1, 2, 3, 5}, {2, 5}]
result = []
# xlsx文件中有3列,分别为电影名称、导演名称、演员清单
# 同一个电影的多个主演演员使用逗号分隔
ws = load_workbook('电影导演演员.xlsx').worksheets[0]
for index, row in enumerate(ws.rows):
# 跳过第一行表头
if index==0:
continue
result.append(set(row[2].value.split(',')))
return result
def createC1(dataSet):
'''dataSet为包含集合的列表,每个集合表示一个项集
返回包含若干元组的列表,
每个元组为只包含一个物品的项集,所有项集不重复'''
return sorted(map(lambda i:(i,), set(chain(*dataSet))))
def scanD(dataSet, Ck, Lk, minSupport):
'''dataSet为包含集合的列表,每个集合表示一个项集
ck为候选项集列表,每个元素为元组
minSupport为最小支持度阈值
返回Ck中支持度大于等于minSupport的那些项集'''
# 数据集总数量
total = len(dataSet)
supportData = {}
for candidate in Ck:
# 加速,k-频繁项集的所有k-1子集都应该是频繁项集
if Lk and (not all(map(lambda item: item in Lk,
combinations(candidate,
len(candidate)-1)))):
continue
# 遍历每个候选项集,统计该项集在所有数据集中出现的次数
# 这里隐含了一个技巧:True在内部存储为1
set_candidate = set(candidate)
frequencies = sum(map(lambda item: set_candidate<=item,
dataSet))
# 计算支持度
t = frequencies/total
# 大于等于最小支持度,保留该项集及其支持度
if t >= minSupport:
supportData[candidate] = t
return supportData
def aprioriGen(Lk, k):
'''根据k项集生成k+1项集'''
result = []
for index, item1 in enumerate(Lk):
for item2 in Lk[index+1:]:
# 只合并前k-2项相同的项集,避免生成重复项集
# 例如,(1,3)和(2,5)不会合并,
# (2,3)和(2,5)会合并为(2,3,5),
# (2,3)和(3,5)不会合并,
# (2,3)、(2,5)、(3,5)只能得到一个项集(2,3,5)
if sorted(item1[:k-2]) == sorted(item2[:k-2]):
result.append(tuple(set(item1)|set(item2)))
return result
def apriori(dataSet, minSupport=0.5):
'''根据给定数据集dataSet,
返回所有支持度>=minSupport的频繁项集'''
C1 = createC1(dataSet)
supportData = scanD(dataSet, C1, None, minSupport)
k = 2
while True:
# 获取满足最小支持度的k项集
Lk = [key for key in supportData if len(key)==k-1]
# 合并生成k+1项集
Ck = aprioriGen(Lk, k)
# 筛选满足最小支持度的k+1项集
supK = scanD(dataSet, Ck, Lk, minSupport)
# 无法再生成包含更多项的项集,算法结束
if not supK:
break
supportData.update(supK)
k = k+1
return supportData
def findRules(supportData, minConfidence=0.5):
'''查找满足最小置信度的关联规则'''
# 对频繁项集按长度降序排列
supportDataL = sorted(supportData.items(),
key=lambda item:len(item[0]),
reverse=True)
rules = []
for index, pre in enumerate(supportDataL):
for aft in supportDataL[index+1:]:
# 只查找k-1项集到k项集的关联规则
if len(aft[0]) < len(pre[0])-1:
break
# 当前项集aft[0]是pre[0]的子集
# 且aft[0]==>pre[0]的置信度大于等于最小置信度阈值
if set(aft[0])<set(pre[0]) and\
pre[1]/aft[1]>=minConfidence:
rules.append([pre[0],aft[0]])
return rules
# 加载数据
dataSet = loadDataSet()
# 获取所有支持度大于0.2的项集
supportData = apriori(dataSet, 0.2)
# 在所有频繁项集中查找并输出关系较好的演员二人组合
bestPair = [item for item in supportData if len(item)==2]
print(bestPair)
# 查找支持度大于0.6的强关联规则
for item in findRules(supportData, 0.6):
pre, aft = map(set, item)
print(aft, pre-aft, sep='==>')
[('演员1', '演员3'), ('演员1', '演员4'), ('演员3', '演员4'), ('演员3', '演员5'), ('演员4', '演员9')]
{'演员1', '演员4'}==>{'演员3'}
{'演员1'}==>{'演员3'}
{'演员1'}==>{'演员4'}
{'演员3'}==>{'演员4'}
{'演员4'}==>{'演员3'}
{'演员5'}==>{'演员3'}
{'演员9'}==>{'演员4'}
数据降维
交叉验证、网格搜索、学习曲线
1.评估模型的泛化能力
from time import time
from os import listdir
from os.path import basename
from PIL import Image
from sklearn import svm
from sklearn.model_selection import cross_val_score,\
ShuffleSplit, LeaveOneOut
# 图像尺寸
width, height = 30, 60
def loadDigits(dstDir='datasets'):
# 获取所有图像文件名
digitsFile = [dstDir+'/'+fn for fn in listdir(dstDir)
if fn.endswith('.jpg')]
# 按编号排序
digitsFile.sort(key=lambda fn: int(basename(fn)[:-4]))
# digitsData用于存放读取的图片中数字信息
# 每个图片中所有像素值存放于digitsData中的一行数据
digitsData = []
for fn in digitsFile:
with Image.open(fn) as im:
data = [sum(im.getpixel((w,h)))/len(im.getpixel((w,h)))
for w in range(width)
for h in range(height)]
digitsData.append(data)
# digitsLabel用于存放图片中数字的标准分类
with open(dstDir+'/digits.txt') as fp:
digitsLabel = fp.readlines()
digitsLabel = [label.strip() for label in digitsLabel]
return (digitsData, digitsLabel)
# 加载数据
data = loadDigits()
print('数据加载完成。')
# 创建模型
svcClassifier = svm.SVC(kernel="linear", C=1000, gamma=0.001)
# 交叉验证
start = time()
scores = cross_val_score(svcClassifier, data[0], data[1], cv=8)
print('交叉验证(k折叠)得分情况:\n', scores)
print('平均分:\n', scores.mean())
print('用时(秒):', time()-start)
print('='*20)
start = time()
scores = cross_val_score(svcClassifier, data[0], data[1],
cv=ShuffleSplit(test_size=0.3,
train_size=0.7,
n_splits=10))
print('交叉验证(随机拆分)得分情况:\n', scores)
print('平均分:\n', scores.mean())
print('用时(秒):', time()-start)
print('='*20)
start = time()
scores = cross_val_score(svcClassifier, data[0], data[1],
cv=LeaveOneOut())
print('交叉验证(逐个测试)得分情况:\n', scores)
print('平均分:\n', scores.mean())
print('用时(秒):', time()-start)
2.使用网格搜索确定最佳参数
from time import time
from os import listdir
from os.path import basename
from PIL import Image
from sklearn import svm
from sklearn.model_selection import GridSearchCV
# 图像尺寸
width, height = 30, 60
def loadDigits(dstDir='datasets'):
# 获取所有图像文件名
digitsFile = [dstDir+'/'+fn for fn in listdir(dstDir)
if fn.endswith('.jpg')]
# 按编号排序
digitsFile.sort(key=lambda fn: int(basename(fn)[:-4]))
# digitsData用于存放读取的图片中数字信息
# 每个图片中所有像素值存放于digitsData中的一行数据
digitsData = []
for fn in digitsFile:
with Image.open(fn) as im:
data = [sum(im.getpixel((w,h)))/len(im.getpixel((w,h)))
for w in range(width)
for h in range(height)]
digitsData.append(data)
# digitsLabel用于存放图片中数字的标准分类
with open(dstDir+'/digits.txt') as fp:
digitsLabel = fp.readlines()
digitsLabel = [label.strip() for label in digitsLabel]
return (digitsData, digitsLabel)
# 加载数据
data = loadDigits()
print('数据加载完成。')
# 创建模型
svcClassifier = svm.SVC()
# 待测试的参数
parameters = {'kernel': ('linear', 'rbf'),
'C': (0.001, 1, 1000),
'gamma':(0.001, 1, 10)}
# 网格搜索
start = time()
clf = GridSearchCV(svcClassifier, parameters)
clf.fit(data[0], data[1])
# 解除注释可以查看详细结果
# print(clf.cv_results_)
print(clf.best_params_)
print('得分:', clf.score(data[0], data[1]))
print('用时(秒):', time()-start)
数据加载完成。
3.绘制学习曲线
from os import listdir
from os.path import basename, join
import numpy as np
from PIL import Image
from sklearn import svm
from sklearn.model_selection import learning_curve, ShuffleSplit
import matplotlib.pyplot as plt
# 图像尺寸
width, height = 30, 60
def loadDigits(dstDir='datasets'):
# 获取所有图像文件名
digitsFile = [join(dstDir,fn) for fn in listdir(dstDir)
if fn.endswith('.jpg')]
# 按编号排序
digitsFile.sort(key=lambda fn: int(basename(fn)[:-4]))
# digitsData用于存放读取的图片中数字信息
# 每个图片中所有像素值存放于digitsData中的一行数据
digitsData = []
for fn in digitsFile:
with Image.open(fn) as im:
# 原始图像尺寸不一样,先调整成统一尺寸,确保每个子列表的长度相同
digitsData.append(np.array(im.resize((width,height)))
.mean(axis=2).flatten('F').tolist())
# digitsLabel用于存放图片中数字的标准分类
with open(fr'{dstDir}/digits.txt') as fp:
digitsLabel = fp.read().splitlines(keepends=False)
return (digitsData, digitsLabel)
# 加载数据
X, y = loadDigits()
print('数据加载完成。')
svcClassifier = svm.SVC(kernel='linear', C=1000, gamma=0.001)
# 使用20%的样本进行测试,80%的样本进行训练,重复10次,计算每次的得分
cv = ShuffleSplit(test_size=0.2, train_size=0.8, n_splits=10)
# 使用交叉验证计算不同数量样本作为训练集时的模型平均得分
train_sizes, train_scores, test_scores = learning_curve(svcClassifier, X, y, cv=cv,
train_sizes=np.linspace(0.1,1.0,10))
# 对于不同大小的训练集10次训练与测试结果得分求均值
train_scores = np.mean(train_scores, axis=1)
test_scores = np.mean(test_scores, axis=1)
plt.plot(train_sizes, train_scores, 'r-o', lw=2, label='training score')
plt.plot(train_sizes, test_scores, 'g--v', lw=2, label='cross validation score')
plt.legend()
plt.show()