机器学习[Python]
一.Web服务器
二.一些原理
三.Redis
四.爬虫
五.数据分析
六.机器学习
七.深度学习
六.机器学习
0.基础知识
- 基础概念
训练集:用来进行训练,产生模型/算法的数据集。
测试集:用来进行测试已经学习好模型/算法的数据集。
特征向量:属性的集合,通常用一个向量表示,影响目标结果的一组元素。
标记:实例类别的标记,目标结果的值。
分类:目标标记为类别型数值。
回归:目标标记为连续性数值。
有监督学习:训练集有类别标记。
无监督学习:无类别标记。
半监督学习:有类别标记的训练集+无类别标记的训练集。 - 基础步骤
a.把数据拆分为训练集和测试集
b.用训练集和训练集的特征向量训练算法
c.用学习来的算法在测试集上来评估算法(可能涉及到调整参数用验证集)
1.特征工程
特征是数据中抽取出来的对结果预测有用的信息,可以是文本或者数据。
关键步骤是数据采集(清洗,采样),特征处理
数据采集:哪些数据对最后的结果预测有帮助就采集哪些数据,处理其中脏数据和过多缺省数据,采样正负均衡的数据。
特征处理,包括数值型,类别型,时间型数据的处理。
可以使用scikit-learn模块,基于numpy数据做统一处理。
对于特征为数值型数据的预处理(此时每个特征的重要性看为同等重要):
- 归一化
- 标准化
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
"""数值数据特征预处理"""
#使用MinMaxScaler进行归一化处理
"""
按列进行x=(x-min/max-min)*(mx-mi)+mi
其中min=该列最小数值
max=该列最大数值
mx=要求结果集范围最大上限,默认1
mi=要求结果集范围最小下限,默认0
特点:异常数据(极端值)对结果影响大
"""
def minmaxsc():
mm=MinMaxScaler(feature_range=(2,3)) #默认(0,1)
narray =[[53,9,22],[18,66,70],[12,32,91]]
data=mm.fit_transform(narray)
print(data)
#使用StandardScaler行标准化处理
"""
按列进行x=(x-mean)/标准差
其中mean=该列平均值
方差=(x1-mean)²+(x2-mean)²+.../n,标准差=方差的平方根
每一列计算的结果相加为0
特点:异常数据对结果影响小
标准差反应数据的稳定性,越大表示数据波动性越强
"""
def standarsc():
ss=StandardScaler()
narray =[[53,9,22],[18,66,70],[12,32,91]]
data=ss.fit_transform(narray)
print(data)
对类别数据特征处理,比如文本数据(one-hot方式):
- 先进行数据的提取,
- 再按照规则使用数值表示
from sklearn.feature_extraction import DictVectorizer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
import jieba
"""
字典处理
构成二维矩阵
分词的数量代表处理的行索引;数据个数作为列索引
分词原则是非数值数据直接连接为特征(name=zs),对应的二维数组中满足为1,不满足为0
数值型数据直接赋值到指定二维数组位置
"""
def dictvec():
dv=DictVectorizer(sparse=False)
data=dv.fit_transform([{"name":"zs","age":18},{"name":"mm","age":24},{"name":"cc","age":28}])
#数据提取结果
print(dv.get_feature_names())
#数据显示样式
print(data)
"""
文本数据处理-普通方式
同样分词结果作为行索引,矩阵中的数字代表分词出现的次数
"""
def countvec():
cv=CountVectorizer()
#英文会自动按照空格分词,单字母忽略(认为对预测结果无意义)
earray=["i am zs,i like mm","she is mm,like zs,hi zs"]
#中文可以先用jieba模块进行分词处理
zarray=["我是一个小企鹅,我喜欢吃鱼","我是一个大白熊,我喜欢吃企鹅"]
temp=[]
for zh in zarray:
temp.append(jiebafilter(zh))
print(temp)
data=cv.fit_transform(temp)
#单字母不作为特征抽取的元素
print(cv.get_feature_names())
print(data.toarray())
"""
文本数据处理-tfidf更优化的方式
tfidf方式可以计算出分词的重要性
一个分词在同一段文字中出现的次数越多,且在整个段落中出现的次数越少,那么越重要
比如我们,那么,等等之类的分词虽然经常出现,但并不重要
"""
def tfidfvec():
tf = TfidfVectorizer()
zarray = ["我是一个小企鹅,我喜欢吃鱼", "我是一个大白熊,我喜欢吃企鹅","我是大鲨鱼,我喜欢吃大白熊"]
temp = []
for zh in zarray:
temp.append(jiebafilter(zh))
print(temp)
data = tf.fit_transform(temp)
print(tf.get_feature_names())
print(data.toarray())
#使用jieba模块进行中文分词处理
def jiebafilter(str):
list=jieba.cut(str)
content=" ".join(iter(list))
return content
通过数据抽取或者降维精化特征数据
在用统计分析方法研究多变量的课题时,变量个数太多就会增加课题的复杂性。人们自然希望变量个数较少而得到的
信息较多。在很多情形,变量之间是有一定的相关关系的,当两个变量之间有一定相关关系时,可以解释为这两个变量反
映此课题的信息有一定的重叠。主成分分析是对于原先提出的所有变量,将重复的变量(关系紧密的变量)删去多余,建立
尽可能少的新变量,使得这些新变量是两两不相关的,而且这些新变量在反映课题的信息方面尽可能保持原有的信息。
常用方式:
- 数据特征的抽取
- 主成分分析之PCA
from sklearn.feature_selection import VarianceThreshold
from sklearn.decomposition import PCA
"""
数据抽取
"""
def varienceth():
#指定方差为0的列被屏蔽
vt=VarianceThreshold(threshold=0.0)
data=vt.fit_transform([[1,2,3],[2,2,3],[3,3,3]])
print(data)
"""
主成分分析
PCA主要通过把数据从高维映射到低维来降低特征维度。(投影)
尽可能的保留能够反映真实特征数据的数据量,且去除重复数据
"""
def pca():
#保留90%的有效数据
pc=PCA(n_components=0.9)
data=pc.fit_transform([[53,9,22,1],[18,66,70,16],[12,32,91,30],[23,76,45,22]])
print(data)
print(data.shape)
2.机器学习算法
开发流程
- 准备数据(75%用于训练,25%用于测试)
- 建立模型,明确做的事情
- 基础数据处理
- 特征工程
- 使用合适算法
- 评估模型
- 上线API
from sklearn.datasets import load_iris,fetch_20newsgroups,load_boston
from sklearn.model_selection import train_test_split
"""展示一组机器算法监督类目标离散的数据"""
def testir():
li=load_iris()
#输入数据
print(li.data)
#目标数据
print(li.target)
#描述
print(li.DESCR)
#把数据按照75%的训练数据,25%的测试数据切分
xtrain,xtest,ytrain,ytest=train_test_split(li.data,li.target,test_size=0.25)
#75%训练的特征值和目标值
print(xtrain,ytrain)
#25%测试的特征值和目标值
print(xtest,ytest)
"""展示一组机器算法监督类目标连续的数据"""
def testlb():
lb=load_boston()
print(lb.data)
print(lb.target)
机器学习算法使用:
监督学习-处理分类[离散目标值]:K-邻近算法,决策树,支持向量机SVM,神经网络
监督学习-处理回归[连续目标值]:线性回归,非线性回归
非监督学习[无目标值]:K-Means,层次聚类
K-邻近算法
k近邻法(k-nearest neighbor, k-NN)是1967年由Cover T和Hart P提出的一种基本分类与回归方法。它的工作原理是:存在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
参考:https://cuijiahua.com/blog/2017/11/ml_1_knn.html
0.简单理解
show.png【我们想要预测打斗101,接吻20次的电影分类,该如何使用KNN做呢?】
本例子中影响电影分类的因素只有两个特征值,把打斗次数和接吻作为平面坐标系x,y。在直角坐标系中可以绘制出几个点。
(如果特征数是N个,那就是在N维坐标系好了)
把想要预测的点绘制到该坐标系中,计算和其他点之间的距离
show1.jpeg
利用距离公式:
ml_1_3.jpeg
通过计算,我们可以得到如下结果:
(101,20)->动作片(108,5)的距离约为16.55
(101,20)->动作片(115,8)的距离约为18.44
(101,20)->爱情片(5,89)的距离约为118.22
(101,20)->爱情片(1,101)的距离约为128.69
令K=3,选择距离最近的3个点坐标,其中2个动作片,1个爱情片,取多数,预测结果为爱情片。
(如果特征数是N个,使用欧拉公式,一般K取奇数,目的是能选到多数值)
ml_1_6.jpeg
以上KNN模型可以看出:
优点:简单,数据不需要迭代训练
缺点:计算量大(数据量越大,性能越差);K值定义不准影响结果(过大过小都不好);无法给出数据内在定义。做图像识别表现不好,因为使用的为像素特征,结果可能是颜色相近的距离更近。
改进方向:距离加权重
图中x点应该更贴近红色点,但是犹豫周边蓝色点多,影响预测,所以把距离上权重一起判断更准确。
WX20210623-160336.png
1.代码实现
使用sklearn-datasets数据集预测花的种类
from sklearn import neighbors
from sklearn import datasets
#指定K=3的KNN模型算法
knn=neighbors.KNeighborsClassifier(n_neighbors=3)
#使用sklearn自带数据集(花朵识别)
iris=datasets.load_iris()
print(iris)
#使用knn构建模型
knn.fit(iris.data,iris.target)
#预测一个[[0.1,0.2,0.3,0.4]]的结果
predictedLabel=knn.predict([[0.1,0.2,0.3,0.4]])
print("predictedLabel=",predictedLabel)
拆分sklearn-datasets数据集,判断预测准确性
from sklearn.neighbors import KNeighborsClassifier
from sklearn import datasets
from sklearn.model_selection import train_test_split
def knn():
li = datasets.load_iris()
xtrain, xtest, ytrain, ytest = train_test_split(li.data, li.target, test_size=0.25)
#构建一个K=3的K-近邻算法模型
knn=KNeighborsClassifier(n_neighbors=3)
#根据拆分的训练特征值和目标值进行计算
knn.fit(xtrain,ytrain)
#预测测试数据集
y_predict=knn.predict(xtest)
#预测结果和真实结果进行比较
print("预测结果:%s 实际结果:%s"%(y_predict,ytest))
#得出准备率
res=knn.score(xtest,ytest)
print("准确率:%s"%res)
使用交叉验证和网格搜索优化找更合适的K值
def knn():
li = load_iris()
xtrain, xtest, ytrain, ytest = train_test_split(li.data, li.target, test_size=0.25)
knn = KNeighborsClassifier()
params={"n_neighbors":[3,5,10]}
gs=GridSearchCV(knn,param_grid=params,cv=2)
gs.fit(xtrain,ytrain)
print("测试集准确率:",gs.score(xtest,ytest))
print("交叉集最好的结果:",gs.best_score_)
print("选择最好的模型:",gs.best_estimator_)
print("每个交叉参数集结果:",gs.cv_results_)
个人理解:
把训练集特征数据构建N维图形中(eg:2个特征就对应一个平面的点,3个特征就对应一个三维空间的点),输入一个未知目标的特征数据组,映射到该图形中,找到附近已知目标特征中的数据,哪个多就选哪个。
朴素贝叶斯算法
原理:朴素贝叶斯(naive Bayes)法是是基于贝叶斯定理 和特征条件独立假设的分类方法,对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合分布概率;然后基于此模型,对给定的输入x,再利用贝叶斯定理求出其后验概率最大的输出y。主要用于文本分类。
基础知识:
1.概率论中条件概率P(A|B)=满足B条件下A事件的概率
2.P(A1,A2|B)=P(A1|B)P(A2|B) (A1,A2相互独立)
3.P(A|B)=P(B|A)P(A)/P(B)
4.如果有的数据为0,使用拉普拉斯平滑,让分子和分母加一个数字,eg:1
5.精确率:预测结果为正例样本中真实为正例的比例(准)
召回率:真实为正例中预测结果为正例比例(全)
参考:https://blog.csdn.net/zhengzhenxian/article/details/79052185
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics.classification import classification_report
"""朴素贝叶斯算法"""
def mnb():
newsdata=fetch_20newsgroups()
xtrain, xtest, ytrain, ytest = train_test_split(newsdata.data,newsdata.target,test_size=0.25)
tf=TfidfVectorizer()
#fit_transform训练数据,tranform测试数据
xtrain=tf.fit_transform(xtrain)
xtest=tf.transform(xtest)
print(tf.get_feature_names())
print(xtrain.toarray())
print(xtest.toarray())
mnb=MultinomialNB(alpha=1.0)
mnb.fit(xtrain,ytrain)
y_predict=mnb.predict(xtest)
print(y_predict)
print("准确率:%s"%mnb.score(xtest,ytest))
print("新闻数据每种类型的准确率和召回率:",classification_report(ytest,y_predict,target_names=newsdata.target_names))
优点:稳定,对缺失值不敏感
缺点:条件独立性假设
个人理解:
适合多分类任务,特征为离散型数据且相互独立,利用概率论基础,统计这些离散型特征数据对目标影响概率,对于未知目标数据,选择最优概率解。
决策树算法
参考:https://www.cnblogs.com/yonghao/p/5061873.html
image.png通过以上数据构建一颗决策树:
image.png
通过该决策树,可以直观看出,通过该模型直接可以预测结果,难么如何构建决策树【根节点和叶子节点选取】呢?需要引入一些概念和方法。
0.基础概念
- 熵(Entropy):熵描述了数据的混乱程度,熵越大,混乱程度越高,也就是纯度越低。
833682-20151221204156921-2018891490.png ,单位是bit
其中Pi表示类i的数量占比。以二分类问题为例,如果两类的数量相同,此时分类节点的纯度最低,熵等于1;如果节点的数据属于同一类时,此时节点的纯度最高,熵等于0。
eg:2个因素对结果影响概率都是1/2,那么Entropy=[-(1/2)log2(1/2)]+[-(1/2)log2(1/2)]=1
2个因素对结果影响概率一个是1,一个是0,那么Entropy=[-(0/2)log2(0/2)]+[-(1)log2(1)]=0 - 信息获取量(Information_Gain):Info(A)=Info(D)-Info_A(D)
【本例中,Age作为跟节点,说明Age对预测结果Buys Computer影响最大,那么如何选取到Age特征作为根节点呢】
A的信息获取量=目标熵-去除特征A的熵。用测试数据表示Age的Information_Gain:
Info(D)[5-NO 9-YES]=-9/14log2(9/14)-5/14log(5/14)=0.94bit
Info_A(D)[5-Youth 4-Middle_age 5-Senior]=5/14[-2/5log2(2/5)-3/5log2(3/5)]+4/14[-4/4log2(4/4)-0/4log2(0/4)]+5/14[-2/5log2(2/5)-3/5*log2(3/5)]=0.69bit
那么,Gain(Age)=Info(A)=0.94-0.69=0.25bit
同理,Gain(Income)=0.029 Gain(Student)=0.151 Gain(Credit)=0.048
所以,使用Age为根节点。
1.构建过程
使用每一个特征值计算该特征值的Information_Gain。
选取最大的Information_Gain作为根节点,其他节点通过该特征值分类分到不同分支中。
在分支中,同样把每个特征值计算该特征值的Information_Gain,以此循环。
直到没有可分的特征值,如果还有多种目标值,那么把目标结果最多的作为结果。
优缺点:
直观,便于理解,小规模数据集有效;
处理连续变量不好,类别较多时错误增加较多;
2.代码实现
from sklearn.feature_extraction import DictVectorizer
import csv
from sklearn import preprocessing
from sklearn import tree
"""
sklearn提供相关机器学习的算法,但是数据格式需要整理成sklearn的标准
例如age属性:youth,middle_age,senior
如果对应youth,则化为100,middle_age化为010 senior化为001(顺序可能有变化),其他属性也类似
原始数据第一行 Youth(Youth,Middle_age,Senior) High(High,Low,Medium) No(No,Yes) Fair(Fair,Excellent) No(Yes,No)
转化成-> 1 0 0 1 0 0 0 1 1 0 0
"""
#把原始数据用csv导入
allData=open(r"origindata.csv","r")
reader=csv.reader(allData)
headers=next(reader)
#第一行数据表示表头,不作为学习模型数据
print("headers:",headers)
#定义特征数组和目标数组
featureList=[]
labelList=[]
#csv数据整理成字典数组
for row in reader:
labelList.append(row[len(row)-1])
rowDict={}
for i in range(1,len(row)-1):
rowDict[headers[i]]=row[i]
featureList.append(rowDict)
print(featureList)
#使用整理好的字典数组生成01特征数据和01目标数据格式(顺序按照feature_names对应)
vec=DictVectorizer()
dummyX=vec.fit_transform(featureList).toarray()
print("dummyX:",dummyX)
print(vec.get_feature_names())
print("labelList:",labelList)
lb=preprocessing.LabelBinarizer()
dummyY=lb.fit_transform(labelList)
print("dummyY:",dummyY)
#使用决策树策略-熵算法进行模型创建
clf=tree.DecisionTreeClassifier(criterion="entropy")
clf=clf.fit(dummyX,dummyY)
print("clf:",clf)
#改变第一行原始数据值,并做一个预测
oneRowX=dummyX[0]
print("oneRowX",oneRowX)
newRowX=oneRowX
newRowX[0]=1
newRowX[1]=0
newRowX[2]=0
print("newRowX:",newRowX)
predictedY=clf.predict(newRowX.reshape(1,-1))
print("predictedY",predictedY)
个人理解:
以信息论为基础,构建一颗子节点按照重要程度下降的决策树(影响越大的结点越接近根节点),对于未知目标的特征数据,按照路径判断最终所属节点。
其中:如何找到最重要影响特征以及分裂的属性的选择都是利用信息论方法决定。
支持向量机SVM
参考:https://zhuanlan.zhihu.com/p/77750026
0.基本理解
大体上,按照两种方式划分,一种是线性可分,另一种是线性不可分。
用两个特征值举例,绘制到平面直角坐标系空间中:
线性可分.jpeg
线性不可分.jpeg
对于2维的线性可分空间,如何找到最合适的分界线呢?
该分界线要满足划分特质值的前提下,距离两边临界边界点最远的线。这条线叫最大超平面,临界点叫支撑向量。因为拓展到3维空间就是一个平面,拓展到N维空间就是一个超平面。
支撑向量.jpeg
如何利用数学知识找到这个最大超平面呢(此处忽略N个字,利用向量距离公式+拉格朗日定律),最终求得超平面的表达式为
wTx+b=0。
那么,对于线性不可分的超平面该如何找呢?
用2维不可分举例,将2维线性不可分样本映射到高维空间中,让样本点在高维空间线性可分,然后该超平面映射回低维度的切线就是该线性不可分的超平面。
高维映射.jpeg
低维切线.jpeg
简易模型如下:
简易模型.png
那么,如果将低维空间映射到高维空间呢,这里需要使用向量和内积运算。
eg:将3维空间向量映射到9维空间向量中
x=(x1,x2,x3) y=(y1,y2,y3) ,定义向量运算f(x)=(x1x1,x1x2,x1x3,x2x1,x2x2,x3x3,x3x1,x3x2,x3x3)
x=(1,2,3) y=(4,5,6)
f(x)=(1,2,3,2,4,6,3,6,9) f(y)=(16,20,24,20,25,30,24,30,36)
内积运算<f(x),f(y)>=116+220+324+220+425+630+324+630+936=1024
这样产生另一个问题,因为低维空间映射到高维空间后维度可能会很大,如果将全部样本的点乘全部计算好,这样的计算量太大了。所以引入核函数K,简化向量计算复杂度的同时,似的结果偏差最小。
其中一种核函数定义为 K(x,y)=K(<x,y>)²
K(x,y)=(4+10+18)²=1024,结果和之前复杂计算量结果相同。
同样的结果,使用Kernel计算量小很多。
以上,全是两类分类问题,那么,如果是多分类问题呢,该如何解决?
对于每个类,把其他类都当成另外一种分类进行二分类,转化成二分类问题。
1.代码实现
2维2类特征值3点利用SVM划分超平面
from sklearn import svm
#定义3个2维坐标点,并给定目标值
x=[[2,0],[1,1],[2,3]]
y=[0,0,1]
#使用svm建立模型
clf=svm.SVC(kernel="linear")
clf.fit(x,y)
print(clf)
#打印支撑向量
print(clf.support_vectors_)
#打印支撑向量index
print(clf.support_)
#打印支撑向量数量
print(clf.n_support_)
#预测[2,0]的目标值
pred=clf.predict([[2,0]])
print(pred)
结果.png
2维2类特征值随机20个点利用SVM划分超平面
import numpy as np
from matplotlib import pylab as pl
from sklearn import svm
#随机生成20具有正态分布的坐标点集和固定目标集
np.random.seed(0)
x=np.r_[np.random.randn(20,2)-[2,2],np.random.randn(20,2)+[2,2]]
y=[0]*20+[1]*20
print("x:",x)
print("y:",y)
#使用SVM训练模型
clf=svm.SVC(kernel="linear")
clf.fit(x,y)
#利用pylab绘制图形
w=clf.coef_[0]
a=-w[0]/w[1]
xx=np.linspace(-5,5)
yy=a*xx-(clf.intercept_[0])/w[1]
b=clf.support_vectors_[0]
yy_down=a*xx+(b[1]-a*b[0])
b=clf.support_vectors_[-1]
yy_up=a*xx+(b[1]-a*b[0])
pl.plot(xx,yy,"k-")
pl.plot(xx,yy_down,"k--")
pl.plot(xx,yy_up,"k--")
pl.scatter(clf.support_vectors_[:,0],clf.support_vectors_[:,1],
s=80,facecolors="none")
pl.scatter(x[:,0],x[:,1],c=y,cmap=pl.cm.Paired)
pl.axis("tight")
pl.show()
运行结果.png
非线性划分SVM人脸识别
from __future__ import print_function
from time import time
import logging
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_lfw_people
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
#获取人脸数据集
logging.basicConfig(level=logging.INFO,format="%(asctime)s%(message)s")
lfw_people=fetch_lfw_people(min_faces_per_person=70,resize=0.4)
#shape返回numpy数据的维度,eg:3行2列->(3,2) shape[0]->3 shape[1]->2
n_samples,h,w=lfw_people.images.shape
x=lfw_people.data
n_features=x.shape[1]
y=lfw_people.target
target_names=lfw_people.target_names
n_classes=target_names.shape[0]
print("Total dataset size:")
print("n_samples:%d"%n_samples)
print("n_features:%d"%n_features)
print("n_classes:%d"%n_classes)
#拆分数据集为训练集和测试集
x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.25)
#使用PCA减少人脸训练数据集特征向量的维度[降低数据计算复杂度]
n_components=150
print("extracting the top %d eigenfaces from %d faces"%(n_components,x_train.shape[0]))
t0=time()
pca = PCA(n_components=n_components,svd_solver='randomized',whiten=True).fit(x_train)
print("done in %0.3fs"%(time()-t0))
eigenfaces=pca.components_.reshape((n_components,h,w))
t0=time()
x_train_pca=pca.transform(x_train)
x_test_pca=pca.transform(x_test)
print("done in %0.3fs"%(time()-t0))
#使用SVM建立模型
t0=time()
param_grid={"C":[1e3,5e3,1e4,5e4,1e5],
"gamma":[0.0001,0.0005,0.001,0.005,0.01,0.1],}
clf=GridSearchCV(SVC(kernel="rbf",class_weight="balanced"),param_grid)
clf=clf.fit(x_train_pca,y_train)
print("done in %0.3fs"%(time()-t0))
print(clf.best_estimator_)
#预测测试集,并使用matplotlib绘制图形
t0=time()
y_pred=clf.predict(x_test_pca)
print("done in %0.3fs"%(time()-t0))
print(classification_report(y_test,y_pred,target_names=target_names))
print(confusion_matrix(y_test,y_pred,labels=range(n_classes)))
def plot_gallery(images,titles,h,w,n_row=3,n_col=4):
plt.figure(figsize=(1.8*n_col,2.4*n_row))
plt.subplots_adjust(bottom=0,left=.01,right=.99,top=.90,hspace=.35)
for i in range(n_row*n_col):
plt.subplot(n_row,n_col,i+1)
plt.imshow(images[i].reshape((h,w)),cmap=plt.cm.gray)
plt.title(titles[i],size=12)
plt.xticks(())
plt.yticks(())
def title(y_pred,y_test,target_names,i):
pred_name=target_names[y_pred[i]].rsplit(" ",1)[-1]
true_name=target_names[y_test[i]].rsplit(" ",1)[-1]
return 'predicted:%s\ntrue:%s'%(pred_name,true_name)
prediction_titles=[title(y_pred,y_test,target_names,i) for i in range(y_pred.shape[0])]
plot_gallery(x_test,prediction_titles,h,w)
eigenfaces_titles=["eigenface %d"%i for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces,eigenfaces_titles,h,w)
plt.show()
运行结果.png
运行结果.png
神经网络
0.基本介绍
组成结构
1、输入层是有训练集的实例特征向量传入
2、经过连接接点的权重(weight)传入下一层,一层的输出是下一层的输入
3、隐藏层的个数可以是任意的,输入层有一层,输出层有一层
4、每个单元也可以称之为神经结点,根据生物学来源定义
5、以上成为两层的神经网络,输入层是不算在里面的
6、一层中加权求和,然后根据非线性方程转化输出
7、作为多层向前神经网络,理论上,如果有足够的隐藏层,和足够的训练集,可以模拟出任何方程
设计结构
1、使用神经网络训练数据之前,必须确定神经网络的层数,以及每层单元的个数
2、特征向量在被传入输入层时通常要先标准化到0-1之间(为了加速学习过程)
3、离散型变量可以被编码成每一个输入单元对应一个特征值可能赋的值
比如:特征值A可能取三个值(a0, a1, a2), 可以使用3个输入单元来代表A。
如果A=a0, 那么代表a0的单元值就取1, 其他取0;
如果A=a1, 那么代表a1的单元值就取1,其他取0,以此类推
4、神经网络即可以用来做分类问题,也可以解决回归问题
(1)对于分类问题,如果是2类,可以用一个输出单元表示(0和1分别代表2类),如果多余2类,则每一个类别用一个输出单元表示
(2)没有明确的规则来设计最好有多少个隐藏层,可以根据实验测试和误差以及精准度来实验并改进
交叉验证
这里有一堆数据,我们把他切成3个部分(当然还可以分的更多)
第一部分做测试集,二三部分做训练集,算出准确度;
第二部分做测试集,一三部分做训练集,算出准确度;
第三部分做测试集,一二部分做训练集,算出准确度;
之后算出三个准确度的平局值,作为最后的准确度,如下图:
算法
他是通过迭代性来处理训练集中的实例,对比经过神经网络后,输人层预测值与真实值之间的误差,再通过反向法(从输出层=>隐藏层=>输入层)以最小化误差来更新每个连接的权重。
输入:D(数据集),学习率(learning rate),一个多层向前神经网络
输出:一个训练好的神经网络(a trained neural network)
1.初始化权重和偏向:随机初始化在-1到1之间,或者-0.5到0.5之间,每个单元有一个偏向
2.开始对数据进行训练,步骤如下:
算法.png
a.由输入层向前传送
1.png
Ij:要对其进行非线性转化,为下一单元的值
Oi:是输入的值
wij:为每个单元到下一个单元连线之间的权重
θj:偏向
对Ij进行非线性转化,得到下一个单元的值
1.png
b.根据误差(error)反向传送
2.png
对于输出层: 2
对于隐藏层:
Errj:用于更新偏向
Oj:为输出的值
Tj:为标签的值
2
权重更新:
括号里为小l ,是学习率(learning rate)
2 偏向更新: 2
c.终止条件
方法一:权重的更新低于某个阈值
方法二:预测的错误率低于某个阈值
方法三:达到预设一定的循环次数
举例:
例子
w14…w56这些权重是初始化随机生成的,同样θ4到θ6也是随机生成的
将x的值与每一项的权重相乘求和算出Ij,之后对Ij进行非线性转化,求出输出值
之后算出结点上的误差,并对其更新,在如此反复
1.代码实现
根据算法描述,定义神经网络类:
import numpy as np
"""
定义两种非线性方程和其导函数
把数据映射到[-1,1]范围中
"""
def tanh(x):
return np.tanh(x)
def tanh_deriv(x):
return 1.0-np.tanh(x)*np.tanh(x)
def logistic(x):
return 1/(1+np.exp(-x))
def logistic_derivative(x):
return logistic(x)*(1-logistic(x))
"""
定义神经网络类
用来建立模型和预测数据
"""
class NN:
def __init__(self,layers,activation='tanh'):
if(activation=='logistic'):
self.activation=logistic
self.activation_deriv=logistic_derivative
elif (activation=='tanh'):
self.activation=tanh
self.activation_deriv=tanh_deriv
#随机初始化权重weights
self.weights=[]
for i in range(1,len(layers)-1):
self.weights.append((2*np.random.random((layers[i-1]+1,layers[i]+1))-1)*0.25)
self.weights.append((2 * np.random.random((layers[i]+1,layers[i+1]))-1)*0.25)
def fit(self,x,y,learning_rate=0.2,epochs=10000):
x=np.atleast_2d(x)
temp=np.ones([x.shape[0],x.shape[1]+1])
temp[:,0:-1]=x
x=temp
y=np.array(y)
for k in range(epochs):
i=np.random.randint(x.shape[0])
a=[x[i]]
for l in range(len(self.weights)):
a.append(self.activation(np.dot(a[l],self.weights[l])))
error=y[i]-a[-1]
deltas=[error*self.activation_deriv(a[-1])]
for l in range(len(a)-2,0,-1):
deltas.append(deltas[-1].dot(self.weights[l].T)*self.activation_deriv(a[l]))
deltas.reverse()
for i in range(len(self.weights)):
layer=np.atleast_2d(a[i])
delta=np.atleast_2d(deltas[i])
self.weights[i]+=learning_rate*layer.T.dot(delta)
def predict(self,x):
x=np.array(x)
temp=np.ones(x.shape[0]+1)
temp[0:-1]=x
a=temp
for l in range(0,len(self.weights)):
a=self.activation(np.dot(a,self.weights[l]))
return a
使用该神经网络预测异或运算:
from NerualNetWorks import NN
import numpy as np
"""
预测异或运算 [0,0]->0 [0,1]->1 ...
"""
#[2,2,1]-输入层2个单元,隐藏层-2个单元(自己指定),输出层2个单元
nn=NN([2,2,1],'tanh')
x=np.array([[0,0],[0,1],[1,0],[1,1]])
y=np.array([0,1,1,0])
nn.fit(x,y)
for i in [[0,0],[0,1],[1,0],[1,1]]:
print(i,nn.predict(i))
使用该神经网络预测手写数字:
from sklearn.datasets import load_digits
from matplotlib import pylab as pl
"""
查看datasets中提供的数字图片
"""
digits=load_digits()
print(digits.data.shape)
# pl.gray()
pl.matshow(digits.images[1])
pl.show()
import numpy as np
from sklearn.datasets import load_digits
from sklearn.metrics import confusion_matrix,classification_report
from NerualNetWorks import NN
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
digits=load_digits()
x=digits.data
y=digits.target
#数据处理成到(0,1)范围内
x-=x.min()
x/=x.max()
#图片为8x8数据源,设置100个单元的隐藏层,10个单元[0-9]输出层
nn=NN([64,100,10],'logistic')
x_train,x_test,y_train,y_test=train_test_split(x,y)
labels_train=LabelBinarizer().fit_transform(y_train)
labels_test=LabelBinarizer().fit_transform(y_test)
nn.fit(x_train,labels_train,epochs=3000)
predictions=[]
for i in range(x_test.shape[0]):
o=nn.predict(x_test[i])
predictions.append(np.argmax(o))
print(confusion_matrix(y_test,predictions))
print(classification_report(y_test,predictions))
线性回归
1.简单的线性回归
0.原理解析
对于一个特征向量x和一个目标值y的情况。
目的是找一条直线方程y=b0+b1*x,即根据数据x,y找到b0,b1的值。
对于一个假设的数据
那么,b0,b1要满足什么条件呢?
条件.png
满足 ∑(y实际值-y估算值)^2最小。直观讲就是最接近每一个点的直线方程。
那么,如何确定b0,b1的值呢?
【省略原理,直接给结论】
b1的值.png
b0的值.png
那么,根据公式,给出算法推导过程:
1.代码实现[不使用sklearn包,自定义方法实现]
import numpy as np
#简单线性回归的模型建立
def fitSLR(x,y):
n=len(x)
dinominator=0
numerator=0
for i in range(0,n):
numerator+=(x[i]-np.mean(x))*(y[i]-np.mean(y))
dinominator+=(x[i]-np.mean(x))**2
b1=numerator/float(dinominator)
b0=np.mean(y)/float(np.mean(x))
return b0,b1
#简单线性回归的模型预测
def predict(x,b0,b1):
return b0+x*b1
x=[1,3,2,1,3]
y=[14,24,18,17,27]
b0,b1=fitSLR(x,y)
print("b0=",b0,"b1=",b1)
pred=predict(6,b0,b1)
print("pred=",pred)
2.简单的线性回归[N个特征向量]
0.原理
同1个特征向量和1个目标一样。
目标是寻找
满足 ∑(y实际值-y估算值)^2最小。直观讲就是最接近每一个点的直线方程。
只不过目标方程是:
y=b0+b1 * x1+b2 * x2+b3 * x3...,即根据数据x1,x2,x3...,y找到b0,b1,b2,b3...的值。
基于以下数据,我们要预测外卖骑手送货时间:
测试数据.png
特别的,如果自变量是分类数据,需要进行一步处理
处理分类数据.png
处理完的csv文件
csv.png
1.代码实现[使用sklearn包]
from numpy import genfromtxt
import numpy as np
from sklearn import datasets,linear_model
#使用处理好的csv文件
dataPath="timedata.csv"
deliverData=genfromtxt(dataPath,delimiter=",")
print(deliverData)
#拆分为特征值和目标值
x=deliverData[:,:-1]
y=deliverData[:,-1]
print("x=",x)
print("y=",y)
#使用sklearn中线性回归类处理数据集
regr=linear_model.LinearRegression()
regr.fit(x,y)
print("regr=",regr.coef_,"intercept=",regr.intercept_)
#进行预测
xPred=[[200,6,1,0,0]]
yPred=regr.predict(xPred)
print("yPred=",yPred)
3.非线性回归[逻辑回归]
0.原理分析
对于有一些目标值是[0,1]的情况,使用线性回归并不能完全契合该目标值。
比如,根据肿瘤尺寸,预测是否患有癌症。
如果建立线性回归模型,预测目标值很可能超出[0,1]范围,且受到个别数据影响。
我们想出一个办法,让目标值范围落到[0,1],就引入了逻辑回归。
那么如何让预测的目标值落到[0,1]中呢?
我们引入sigmoid函数:
sigmoid.png
把线性回归预测模型y=wx+b代入其中,得到
逻辑回归函数.png
那么,和线性回归一样,我们依然要找到(y实际值-y估算值)^2最小时,参数w,b的值。因为函数并不是线性的,所以借用对数函数,变形一下【省略原理】,用损失函数cost表示该预测值和目标值差最小值。
损失函数.png
这个式子中,m是样本数,y是标签,取值0或1,i表示第i个样本,f(x)表示预测的输出。
那么,如何求出该函数最小值呢?
这里引入梯度下降的概念。
首先来看看梯度下降的一个直观的解释。比如我们在一座大山上的某处位置,由于我们不知道怎么下山,于是决定走一步算一步,也就是在每走到一个位置的时候,求解当前位置的梯度,沿着梯度的负方向,也就是当前最陡峭的位置向下走一步,然后继续求解当前位置梯度,向这一步所在位置沿着最陡峭最易下山的位置走一步。这样一步步的走下去,一直走到觉得我们已经到了山脚。当然这样走下去,有可能我们不能走到山脚,而是到了某一个局部的山峰低处。
梯度下降.png
大概思路就是,在一个点按照一定区间[步长/学习率],对函数求偏导,找到下降速率最快的方向,然后走一步,再不断循环该步骤。每次走步的长度逐渐减小,使得计算的结果更加精确。
那么,经过梯度下降算法,求出损失函数最小,以此推出模型中参数的值,代入新特征值进行预测。
1.代码实现
自定义梯度下降函数实现
import numpy as np
import random
#theta-模型训练参数 alpha-学习率 m-数据个数 numIterations-梯度下降次数
def gradientDescent(x,y,theta,alpha,m,numIterations):
xTrans=x.transpose()
for i in range(0,numIterations):
#利用点积进行梯度下降算法实现
hypothesis=np.dot(x,theta)
loss=hypothesis-y
#定义简单线性回归的损失函数
cost=np.sum(loss**2)/(2*m)
print("numIterations",i,"cost=",cost)
gradient=np.dot(xTrans,loss)/m
theta=theta-alpha*gradient
return theta
def genData(numPoints,bias,variance):
#初始化100行2列的100*[0,0]数据
x=np.zeros(shape=(numPoints,2))
#初始化100行1列的100*[0]数据
y=np.zeros(shape=numPoints)
for i in range(0,numPoints):
x[i][0]=1
x[i][1]=i
y[i]=(i+bias)+random.uniform(0,1)*variance
return x,y
#生成100行,偏差25,随机变量*10的随机数据
x,y=genData(100,25,10)
print("x=",x)
print("y=",y)
m,n=np.shape(x)
print("m=",m,"n=",n)
numIterations=100
alpha=0.0005
theta=np.ones(n)
print("---",theta)
theta=gradientDescent(x,y,theta,alpha,m,numIterations)
print("***",theta)
4.回归算法中相关性和R平方值
0.基础概念
线性相关性:衡量两个数据相关性强度的量。
正相关:>0 负相关:<0 无相关:=0
比如一组数据:
X Y
1 10
3 12
8 24
7 21
9 34
28 101
经过公式计算求出 correlation=0.94 正相关。
展示.png
R²值:范围(0,1),如果=80%,表示回归关系可以解释因变量80%的变异。
简单回归中:R²=r*r
参数分别是:y估计值,y平均值,y真实值
5.总结
使用sklearn实现线性回归和逻辑回归
import numpy as np
from sklearn.linear_model import LinearRegression,SGDRegressor
from sklearn.linear_model import Ridge
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error
def linear():
lbdata=load_boston()
xtrain, xtest, ytrain, ytest = train_test_split(lbdata.data, lbdata.target, test_size=0.25)
#特征值和目标值都进行标准化处理
#因为维度不同,所以需要初始化两个StandardScaler
std_x=StandardScaler()
xtrain=std_x.fit_transform(xtrain)
xtest=std_x.transform(xtest)
print(xtrain)
print(xtest)
std_y=StandardScaler()
ytrain=std_y.fit_transform(ytrain.reshape(-1,1))
ytest=std_y.transform(ytest.reshape(-1,1))
print(ytrain)
print(ytest)
"""
利用矩阵计算,求得最符合的线性函数权重值
"""
#正规方程
lr=LinearRegression()
lr.fit(xtrain,ytrain)
print("回归系数:",lr.coef_)
y_predict=lr.predict(xtest)
print("预测标准化后价格:",y_predict)
print("预测价格:", std_y.inverse_transform(y_predict))
print("均方误差",mean_squared_error(std_y.inverse_transform(ytest),std_y.inverse_transform(y_predict)))
"""
损失函数记录偏差值,通过不断学习减低偏差值优化线性函数权重的方式
"""
#梯度下降
sgd=SGDRegressor()
sgd.fit(xtrain, ytrain)
print("回归系数:", sgd.coef_)
sgd_y_predict = sgd.predict(xtest)
print("预测标准化后价格:",sgd_y_predict)
print("预测价格:", std_y.inverse_transform(sgd_y_predict))
print("均方误差", mean_squared_error(std_y.inverse_transform(ytest), std_y.inverse_transform(sgd_y_predict)))
"""
使用正则化方式优化过拟合和欠拟合的问题
"""
#岭回归
rd = Ridge(alpha=1.0)
rd.fit(xtrain, ytrain)
print("回归系数:", rd.coef_)
rd_y_predict = rd.predict(xtest)
print("预测标准化后价格:", rd_y_predict)
print("预测价格:", std_y.inverse_transform(rd_y_predict))
print("均方误差", mean_squared_error(std_y.inverse_transform(ytest), std_y.inverse_transform(rd_y_predict)))
个人理解:
根据训练数据的特征值和目标值,以线性代数为基础,进行矩阵计算,推测线性函数参数。线性函数:y=k1x1+k2x2+k3x3...+b。
逻辑回归
目标值是二分类数值(结果是是否的问题)
from sklearn.linear_model import LinearRegression,SGDRegressor,LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics.classification import classification_report
def logic():
"""
可以使用正则化优化
"""
# 正规方程
lr = LogisticRegression()
lr.fit(xtrain, ytrain)
print("回归系数:",lr.coef_)
y_predict = lr.predict(xtest)
#因为目标值是分类定值,所以可以使用准确率和召回率表示结果
print("准确率:",lr.score(xtest,ytest))
print("召回率:",classification_report(ytest,y_predict,target_names=lbdata.target_names))
个人理解:
以线性回归算法为基础,利用signomid函数做处理,使得预测结果为二分类数值。
参考:https://blog.csdn.net/ustbbsy/article/details/80423294
保存估算模型和使用模型API
from sklearn.externals import joblib
lr=LinearRegression()
lr.fit(xtrain,ytrain)
#保存模型
joblib.dump(lr,"./linemodel.pkl")
#获取模型
linemodel=joblib.load("./linemodel.pkl")
y_predict = linemodel.predict(xtest)
K-Means算法
0.基础概念
非监督算法,没有明确的目标值,把数据分为指定数目的类别。
算法接受参数K,然后将事先输入的n个数据对象划分为K个聚类以便使得所获得的的聚类满足同一聚类中的对象相似度最高,而不同聚类中的对象相似度较小。
参考:https://www.cnblogs.com/bourneli/p/3645049.html
那么,如何做到呢,算法思想是什么?
以空间中K个点为中心进行聚类,对最靠近他们的对象归类。通过迭代的方法,逐次更新各聚类中心的值,直到得到最好的聚类结果。
具体过程如下:
假定有4个二维特征数据,表示在平面直角坐标系上,使用K=2进行聚合。
测试数据.png
步骤一:初始化指定两个中心点,比如图中红色的点,把其他所有点分别算出距离两个中心点的距离,距离更近划分在该中心点的聚合空间内。【省略计算过程】,划分之后的2个聚合空间中,第一个红色点为一组,其他点为第二组。
重新计算中心点.png
步骤二:利用点的均值,重新计算每一组聚合空间的中心点,再次计算每个点到两个新的中心点的距离,距离更近的划分在该中心点所在聚合空间内。调整之后,左边两个点聚合到左边中心点区域,右边两个点聚合再右边中心点区域。
重新划分聚合区域.png
步骤三:利用点的均值,再次重新计算每一组聚合空间的中心点,再次划分聚合区域,得到结果和上一步一致,则停止算法,得到最终结果。
1.代码实现
import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
def kmeans():
#假定6个3特征数据
data=np.array([[15,23,35],[123,213,123],[12,321,321],[876,6,678],[93,56,37],[213,3,5]])
print(data.shape)
print(data)
#使用K-means聚合这6个数据为3类
km=KMeans(n_clusters=3)
km.fit(data)
predict=km.predict(data)
print(predict)
#使用轮廓系数评估该模型的准确率[-1,1]
res=silhouette_score(data,predict)
print("聚类评估结果:",res)
个人理解:
给定一个没有目标值的特征数据集和分类数目K,从随机K个中心点开始,利用距离和平均值公式,不断优化中心点位置,直到耿更好的满足轮廓系数评估的结果。
层次聚类算法
0.基础介绍
假设有N个待聚类的样本,对于层次聚类来说,步骤:
a.(初始化)每个样本归为一类,计算每两个之间的距离,也就是样本与样本之间的相似度。
b.寻找各个类之间最近的两个类,把他们归为一类【这样总数就少了一个】
c.重新计算这个类和旧的各个类之间的相似度。
d.重复bc步骤直至所有样本归为一类,结束。
那么,其中有一个细节是新类的【多点聚类】如何和其他点进行距离计算。
可以按照最近的点位置为基准,也可以按照最远的点的位置为基准,同样可以按照平均中心点位置为基准。不同基准,不同结果。
和K-Means的区别在于,分层之后,可以按照任意分类数目进行树的切分。
1.代码实现
from sklearn import datasets
import numpy as np
import matplotlib.pyplot as plt
from sklearn import preprocessing
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import linkage,dendrogram
#导入数据集,进行拆分,归一化
iris = datasets.load_iris()
iris_data = iris.data
print(iris_data.shape)
print(iris_data)
data = np.array(iris_data[:50,1:-1])
print(data.shape)
min_max_scaler = preprocessing.MinMaxScaler()
data_M = min_max_scaler.fit_transform(data)
print(data_M)
#绘制树状图
plt.figure(figsize=(20,6))
Z = linkage(data_M, method='ward', metric='euclidean')
p = dendrogram(Z, 0)
plt.show()
#使用分层聚类算法,进行数据分类
ac = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward')
ac.fit(data_M)
labels = ac.fit_predict(data_M)
print(labels)
plt.scatter(data_M[:,0], data_M[:,1], c=labels)
plt.show()
七.深度学习
使用深度学习框架TensorFlow进行
TensorFlow属于计算密集型框架
涉及到大量数据计算属于计算密集型(CPU/GPU密集)
涉及到多网络,磁盘操作属于I/O密集型
1.TensorFlow基本介绍
- Graph(图)
【Tensor(TensorFlow中数据格式)+Operation(TensorFlow中函数统称)】集合体 - Session(会话)
运行图的结构,掌握资源,分配资源;默认只能运行一个图(默认图),使用run方法运行图的结构 - Tensor(张量)
TensorFlow中基本数据结构,对numpy(ndarray)的封装,包含【名字,形状,数据类型】
import tensorflow as tf
"""使用TensorFlow进行加法运算"""
def add():
a=tf.constant(3)
b=tf.constant(5)
#a,b,sum均为Tensor类型数据
print("a:%s b:%s"%(a,b))
sum=tf.add(a,b)
print("sum:",sum)
#指定不定shape
plt=tf.placeholder(dtype=tf.float32,shape=[None,3])
"""
fetches-列表参数,指定获取图中哪些Tensor
feed_dict-字典参数,结合placeholder使用
"""
with tf.Session() as session:
res=session.run(fetches=[a,sum,plt],feed_dict={plt:[[3,2,3],[1,2,3]]})
print(res)
print("a.shape:%s a.name:%s a.op:%s"%(a.shape,a.name,a.op))
print("plt.shape:%s plt.name:%s plt.op:%s"%(plt.shape, plt.name, plt.op))
"""图"""
def graph():
#默认图
print("tf-default-graph:", tf.get_default_graph())
#创建图,不创建图,默认是在默认图中执行tensor和operation
gr=tf.Graph()
with gr.as_default():
a = tf.constant(7)
b = tf.constant(10)
sum = tf.add(a, b)
#该Graph的Tensor都可以访问到该图
print("a.graph:",a.graph)
print("sum.graph:", sum.graph)
"""张量"""
def tensor():
#创建一个符合正态分布的随机Tensor mean-均值 stddev-方差 shape-数据形状
ts = tf.random_normal(mean=0.0, stddev=0.5, shape=[50, 3])
print(ts)
plt=tf.placeholder(dtype=tf.float32,shape=[None,3])
print(plt)
#对不定形状可以使用set_shape设置具体shape
plt.set_shape([4,3])
print(plt)
#设置[4,3]之后不能再次设置
#plt.set_shape([5,3])
#print(plt)
#改变数据形状,reshape()需要保证数据元素个数相同
plt_reshape=tf.reshape(plt,shape=[3,4])
print(plt_reshape)
#修改Tensor数据类型
plt=tf.cast(plt,dtype=tf.int32)
print(plt)
- 变量(tf.Variable)
def vari():
a=tf.constant(5)
#定义tensorflow变量
b=tf.Variable(tf.random_normal(shape=[3,2],mean=0.0,stddev=1.0,name="b"))
print("a:%s,b:%s"%(a,b))
#定义tf.Variables类型需要进行初始化操作
variinit=tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(variinit)
res=sess.run(fetches=[a,b])
print(res)
"""可视化操作"""
#把图写入文件,运行tensorboard命令可以通过浏览器直接访问可视图
tf.summary.FileWriter("./tmp/testgraph",graph=sess.graph)
2.TensorFlow线性回归
import tensorflow as tf
import os
"""
模拟线性回归
tf.matmul()-矩阵相乘
tf.square()-平方计算
eval()-获取Tensor中具体数值
with tf.variable_scope()-变量作用域(优化graph显示)
tf.summary-graph可视化图形统计类
tf.train.Saver-模型保存/恢复类
"""
def linner():
with tf.variable_scope("data"):
#1.假定一条y=3x+5.2b的线性回归函数,并准备数据
x=tf.random_normal(shape=[100,1],mean=0.0,stddev=1.0,name="x")
y_true=tf.matmul(x,[[3.0]])+5.2
with tf.variable_scope("model"):
#2.定义权重值w和偏移量b(需要定义为变量才能不断训练) trainable-True 可训练,不断变化
weight=tf.Variable(tf.random_normal(shape=[1,1],mean=0.0,stddev=1.0,name="w"))
b=tf.Variable(0.0,name="b")
y_predict=tf.matmul(x,weight)+b
with tf.variable_scope("loss"):
#3.计算损失值
loss=tf.reduce_mean(tf.square(y_true-y_predict))
with tf.variable_scope("gradientOptimizer"):
#4.利用梯度下降获取训练op learning_rate-学习率,太大导致梯度爆炸,太小导致学习次数激增才能更更好预测
train_op=tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(loss)
#5.初始化全局变量
init_op=tf.global_variables_initializer()
#6.统计损失值和权重值 scalar()-统计Tensor histogram()-统计变量值
tf.summary.scalar("loss",loss)
tf.summary.histogram("weight",weight)
mergeall=tf.summary.merge_all()
with tf.Session() as sess:
sess.run(init_op)
#读取模型
if os.path.exists("./tmp/model"):
print("存在该模型")
tf.train.Saver().restore(sess,"./tmp/model/linnermodel")
print("init weight:%s b:%s"%(weight.eval(),b.eval()))
fileWriter = tf.summary.FileWriter("./tmp/linnergraph", graph=sess.graph)
#7.进行100次训练并记录统计信息到graph中
for i in range(100):
sess.run(train_op)
summary=sess.run(mergeall)
fileWriter.add_summary(summary,i)
print("train %d weight:%s b:%s" % (i,weight.eval(), b.eval()))
#保存模型
tf.train.Saver().save(sess,"./tmp/model/linnermodel")
3.TensorFlow文本,图片,二进制文件子线程读取处理
import tensorflow as tf
import os
"""
实现一个简单的队列出入操作
"""
def testQueue():
# 创建队列
q=tf.FIFOQueue(capacity=3,dtypes=tf.float32)
# 初始化队列op
en_q_many=q.enqueue_many([[1,2,3],])
# +1入队列op(en_q依赖性,执行op会自动执行取出+1两步操作)
de_q=q.dequeue()
data=de_q+1
en_q=q.enqueue(data)
with tf.Session() as sess:
#执行初始化op
sess.run(en_q_many)
#执行入队列op
for i in range(100):
sess.run(en_q)
#执行出队列op
for i in range(q.size().eval()):
print(sess.run(q.dequeue()))
"""
模拟子线程入队列,主线程出队列操作
"""
def testQueueRunner():
# 创建队列
q = tf.FIFOQueue(capacity=1000, dtypes=tf.float32)
# 创建自增队列op
var = tf.Variable(0.0)
data = tf.assign_add(var,tf.constant(1.0))
en_q = q.enqueue(data)
qr = tf.train.QueueRunner(queue=q,enqueue_ops=[en_q]*2)
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init_op)
coord=tf.train.Coordinator()
threads=qr.create_threads(sess,coord=coord,start=True)
for i in range(300):
print(i,sess.run(q.dequeue()))
coord.request_stop()
coord.join(threads)
"""
子线程读取CSV文件,主线程处理
"""
def testReadCSV():
filedir = os.listdir("./csv/")
filelist = [os.path.join("./csv/", file) for file in filedir]
# 1.构建数据目录列表
filequeue = tf.train.input_producer(filelist)
# 2.构建阅读器读取数据
reader = tf.TextLineReader()
key, value = reader.read(filequeue)
# 指定每一个样本的每一列的类型,默认值
record_defaults = [["name1"], ["name2"]]
# 3.指定编码格式
text1, text2 = tf.decode_csv(value, record_defaults=record_defaults)
# 4.批处理文件数据 batch-size-批处理大小(决定每次取数据容量) num-threads-开启线程数(决定取几次) capacity-队列容量
text1s, text2s = tf.train.batch(tensors=[text1, text2], batch_size=10, num_threads=3, capacity=6)
with tf.Session() as sess:
coord = tf.train.Coordinator()
# 开启子线程读取数据
thread = tf.train.start_queue_runners(sess=sess, coord=coord)
print(sess.run(fetches=[text1s, text2s]))
coord.request_stop()
coord.join(thread)
"""
子线程读取JPEG图片文件,主线程处理
"""
def testReadImage():
filedir=os.listdir("./tmp/imagedata/")
filelist=[os.path.join("./tmp/imagedata/",file) for file in filedir]
#1.构建数据目录列表
filequeue=tf.train.input_producer(filelist)
#2.构建阅读器读取数据
reader=tf.WholeFileReader()
key,value=reader.read(filequeue)
#3.指定编码格式
image=tf.image.decode_jpeg(value)
resize_image=tf.image.resize_images(images=image,size=[200,200])
#如果进行批处理,需要指定形状
resize_image.set_shape(shape=[200,200,3])
print(resize_image)
#4.批处理文件数据 batch-size-批处理大小 num-threads-开启线程数 capacity-队列容量
image_batch=tf.train.batch(tensors=[resize_image],batch_size=10,num_threads=2,capacity=6)
with tf.Session() as sess:
coord=tf.train.Coordinator()
#开启子线程读取数据
thread=tf.train.start_queue_runners(sess=sess,coord=coord)
print(sess.run(fetches=[image_batch]))
coord.request_stop()
coord.join(thread)
"""
子线程读取二进制文件,主线程处理
"""
def readbin():
height=32
width=32
channels=3
lablebytes=1
imagebytes=height*width*channels
lable_imagebytes=imagebytes+lablebytes
filedir=os.listdir("./tmp/bindata/")
filelist=[os.path.join("./tmp/bindata/",file) for file in filedir]
#1.构建数据目录列表
filequeue=tf.train.input_producer(filelist)
#2.构建阅读器读取数据
reader=tf.FixedLengthRecordReader(lable_imagebytes)
key,value=reader.read(filequeue)
#3.指定编码格式
lable_image=tf.decode_raw(value,tf.uint8)
lable=tf.slice(lable_image,[0],[lablebytes])
image=tf.slice(lable_image,[lablebytes],[imagebytes])
image_reshape=tf.reshape(tensor=image,shape=[height,width,channels])
#4.批处理文件数据 batch-size-批处理大小 num-threads-开启线程数 capacity-队列容量
image_batch,lable_batch=tf.train.batch(tensors=[image_reshape,lable],batch_size=10,num_threads=2,capacity=6)
with tf.Session() as sess:
coord=tf.train.Coordinator()
#开启子线程读取数据
thread=tf.train.start_queue_runners(sess=sess,coord=coord)
print(sess.run(fetches=[image_batch,lable_batch]))
#存储为TFRecord
writetorecord(image_batch,lable_batch)
coord.request_stop()
coord.join(thread)
"tfrecords快速读取数据类型"
def writetorecord(image_batch,lable_batch):
# 建立TFRecordWriter存储器
writer = tf.python_io.TFRecordWriter(path="./tmp/tfrecorddata/tfrecord")
# 循环写入文件,构造example协议(包含eval()必须在session中执行)
print("开始存储")
for i in range(10):
image = image_batch[i].eval().tostring()
lable = int(lable_batch[i].eval()[0])
example = tf.train.Example(features=tf.train.Features(feature={
"image": tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])),
"lable": tf.train.Feature(int64_list=tf.train.Int64List(value=[lable])),
}))
writer.write(example.SerializeToString())
writer.close()
print("存储完成")
def readrecord():
filedir = os.listdir("./tmp/tfrecorddata/")
filelist = [os.path.join("./tmp/tfrecorddata/", file) for file in filedir]
filequeue=tf.train.input_producer(filelist)
reader=tf.TFRecordReader()
key,value=reader.read(filequeue)
features=tf.parse_single_example(value,features={
"image":tf.FixedLenFeature([],tf.string),
"lable":tf.FixedLenFeature([],tf.int64),
})
image=tf.decode_raw(bytes=features["image"],out_type=tf.uint8)
image_reshape=tf.reshape(image,shape=[32,32,3])
lable=tf.cast(features["lable"],tf.int32)
image_batch, lable_batch = tf.train.batch(tensors=[image_reshape,lable], batch_size=10, num_threads=2, capacity=6)
return image_batch,lable_batch
def testTFRecord():
# 从TFRecord中读取
image_batch, lable_batch = readrecord()
with tf.Session() as sess:
print(sess.run(fetches=[image_batch,lable_batch]))
4.简单的神经网络模型
感知机模型
感知机模型是为了解决多分类问题。
通过多个特征值x1,x2..建立超平面函数w1x1+w2x2+....+b,把目标值进行softmax分类
感知机-神经元(单个感知机)-神经网络(多神经元)
神经网络
N个特征值->M个目标值(输出)
全连接状态的权重数就是NM,偏置数是M,对输出的M个目标值进行softmax取概率,概率大的就是预测的结果。
[None,N]->[None,M]就是一个矩阵相乘的结果 [None,N][N,M]=[None,M]
eg: 3个特征值 3个预测目标值 真实目标值
x1 ---w1/w1'---> Y1(3) 0.3 [0
x2 ---w2/w2'---> (对2个隐层)---> Y2(4) ---softmax--> 0.4 -交叉熵计算损失--> 1
x3 ---w3/w3'---> Y3(3) 0.3 0]
...
对比
算法 策略 优化
线性回归 均方误差 梯度下降
逻辑回归 对数似然损失 梯度下降
神经网络 交叉熵损失 梯度下降
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
"""使用神经网络进行数字图片的预测"""
def mnist(is_train):
# 0.准备数据
mnistdata=input_data.read_data_sets("~/Desktop/PythonTest/TestTF/data/mnist/input_data/",one_hot=True)
# 1.建立占位符数据 x[None,784] y_true[None,10]
with tf.variable_scope("data"):
x=tf.placeholder(dtype=tf.float32,shape=[None,784])
y_true=tf.placeholder(dtype=tf.float32,shape=[None,10])
# 2.建立全连接神经网络 w[784,10] b[10]
with tf.variable_scope("model"):
# 随机初始化权重和偏置
weight=tf.Variable(tf.random_normal(shape=[784,10],mean=0.0,stddev=1.0),name="weight")
bias=tf.Variable(tf.constant(0.0,shape=[10]))
# 预测None个样本的输出结果 [None,784]*[784,10]+[10]=[None,10]
y_predict=tf.matmul(x,weight)+bias
# 3.求出所有样本的损失,求平均值
with tf.variable_scope("soft_cross"):
# 求平均交叉熵损失
loss=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_true,logits=y_predict))
# 4.梯度下降求出损失
with tf.variable_scope("optimizer"):
train_op=tf.train.GradientDescentOptimizer(0.1).minimize(loss)
# 5.计算准确率
with tf.variable_scope("accuracy"):
# None个样本[1,0,0,1,1,1,1,0...1,0]
#argmax函数:返回的是输入列表中最大值的位置
equal_list=tf.equal(tf.argmax(y_true,1),tf.argmax(y_predict,1))
# 求出1的占有率即准确率
accuarcy=tf.reduce_mean(tf.cast(equal_list,tf.float32))
saver=tf.train.Saver()
init_op=tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init_op)
if is_train==True:
for i in range(2000):
mnist_x,mnist_y=mnistdata.train.next_batch(50)
sess.run(train_op,feed_dict={x:mnist_x,y_true:mnist_y})
print("训练第%d步,准确率:%f"%(i,sess.run(accuarcy,feed_dict={x:mnist_x,y_true:mnist_y})))
# 保存模型
saver.save(sess=sess,save_path="./tmp/mnist_model")
else:
# 预测
saver=saver.restore(sess=sess,save_path="./tmp/mnist_model")
for i in range(100):
x_test,y_test=mnistdata.test.next_batch(1)
print("第%d张图片,目标是%d,预测结果是%d"
%(i,
tf.argmax(y_test,1).eval(),
tf.argmax(sess.run(y_predict,feed_dict={x:x_test,y_true:y_test}),1).eval()
))
5.卷积神经网络模型
卷积神经网络模型就是在神经网络模型中加入卷积层。
卷积层进行特征提取,去掉不重要的样本,减少参数数量。
第一步进行过滤器Filter的选择,相当于用N个带权重偏置一个小窗口去看数据,然后移动一定的步长,把所有的数据都看一遍。
eg:
1 4 5 7
2 4 3 8 --->用1个22Filter,step=2观察 -> (第一个点:10.1+0.44+20.3+4*0.2)--> 3.1 5.8
6 2 3 5 0.1,0.4 2.9 4.1
3 3 6 0 0.3,0.2
假如step=3,那么面临观察不全或者观察越界的问题,那么就需要填充层Padding->
0 0 0 0 0 0
0 1 4 5 7 0
0 2 4 3 8 0
0 6 2 3 5 0
0 3 3 6 0 0
0 0 0 0 0 0
计算公式:
H2=(H1-F+2P)/S+1 H1-源数据高,F-FilterH,P-Padding S-Step步长
W2=(W1-F+2P)/S+1 W1-源数据宽,F-FilterW,P-Padding S-Step步长
指定Padding="SAME" 那么H1=H2。
第二步进行激活函数过滤(eg:relu)。
第三步进行池化层,真正减少数据量。
eg:Filter 2*2 step=1
3.1 5.8 --->(3.1+5.8+2.9+4.1) 15.9
2.9 4.1
第四步进行全连接层,预测目标值。
def cnn_mnist(is_train):
# 0.准备数据
mnistdata = input_data.read_data_sets("~/Desktop/PythonTest/TestTF/data/mnist/input_data/", one_hot=True)
# 1.建立占位符数据 x[None,784] y_true[None,10]
with tf.variable_scope("data"):
x = tf.placeholder(dtype=tf.float32, shape=[None, 784])
y_true = tf.placeholder(dtype=tf.float32, shape=[None, 10])
# 2.第一层卷积层 卷积 32个Filter=5*5*32,strides(步长)=1,padding="SAME"
with tf.variable_scope("cnn1"):
# a.修改原数据结构 [None,28,28,1]
x_reshape = tf.reshape(x, [-1, 28, 28, 1])
# b.随机初始化权重和偏置
w_cnn1 = tf.Variable(tf.random_normal(shape=[5,5,1,32], mean=0.0, stddev=1.0))
b_cnn1 = tf.Variable(tf.constant(0.0, shape=[32]))
# c.卷积+relu激活
x_relu1=tf.nn.relu(tf.nn.conv2d(x_reshape,w_cnn1,strides=[1,1,1,1],padding="SAME")+b_cnn1)
# d.池化 2*2,strides=2,padding="SAME" [None,28,28,32]->[None,14,14,32]
x_pool1=tf.nn.max_pool(x_relu1,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME")
# 3.第二层卷积层 卷积 64个Filter=5*5*64,strides(步长)=1,padding="SAME"
with tf.variable_scope("cnn2"):
# 原第一层卷积后数据结构 [None,14,14,32]
# a.随机初始化权重和偏置
w_cnn2 = tf.Variable(tf.random_normal(shape=[5,5,32,64], mean=0.0, stddev=1.0))
b_cnn2 = tf.Variable(tf.constant(0.0, shape=[64]))
# b.卷积+relu激活
x_relu2 = tf.nn.relu(tf.nn.conv2d(x_pool1, w_cnn2, strides=[1, 1, 1, 1], padding="SAME") + b_cnn2)
# c.池化 2*2,strides=2,padding="SAME" [None,14,14,64]->[None,7,7,64]
x_pool2 = tf.nn.max_pool(x_relu2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
# 4.全连接层 [None,7,7,64]=[None,7*7*64]*[7*7*64,10]+[10]->[None,10]
with tf.variable_scope("connect"):
# 随机初始化权重和偏置
weight = tf.Variable(tf.random_normal(shape=[7*7*64,10], mean=0.0, stddev=1.0), name="weight")
bias = tf.Variable(tf.constant(0.0, shape=[10]))
# 修改shape
x_cnn_reshape=tf.reshape(x_pool2,[-1,7*7*64])
y_predict = tf.matmul(x_cnn_reshape, weight) + bias
# 5.求出所有样本的损失,求平均值
with tf.variable_scope("soft_cross"):
# 求平均交叉熵损失
loss=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_true,logits=y_predict))
# 6.梯度下降求出损失
with tf.variable_scope("optimizer"):
train_op=tf.train.GradientDescentOptimizer(0.0001).minimize(loss)
# 7.计算准确率
with tf.variable_scope("accuracy"):
# None个样本[1,0,0,1,1,1,1,0...1,0]
#argmax函数:返回的是输入列表中最大值的位置
equal_list=tf.equal(tf.argmax(y_true,1),tf.argmax(y_predict,1))
# 求出1的占有率即准确率
accuarcy=tf.reduce_mean(tf.cast(equal_list,tf.float32))
saver=tf.train.Saver()
init_op=tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init_op)
if is_train==True:
for i in range(1000):
mnist_x,mnist_y=mnistdata.train.next_batch(50)
sess.run(train_op,feed_dict={x:mnist_x,y_true:mnist_y})
print("训练第%d步,准确率:%f"%(i,sess.run(accuarcy,feed_dict={x:mnist_x,y_true:mnist_y})))
# 保存模型
saver.save(sess=sess,save_path="./tmp/cnn_mnist_model")
else:
# 预测
saver=saver.restore(sess=sess,save_path="./tmp/cnn_mnist_model")
for i in range(100):
x_test,y_test=mnistdata.test.next_batch(1)
print("第%d张图片,目标是%d,预测结果是%d"
%(i,
tf.argmax(y_test,1).eval(),
tf.argmax(sess.run(y_predict,feed_dict={x:x_test,y_true:y_test}),1).eval()
))
识别验证码过程分析
-
先来分析一下mnist识别数据的过程:
特征值:源数据图片格式[None,28,28,1] ,为了进行矩阵计算展成二维数据[None,28281]=[None,784]。
目标值:需要one-hot编码。 [None,10](eg:用[0,0,1,0,0,0,0,0,0,0]表示 3)
全连接过程:[None,784]*[784,10]+[10]=[None,10]
w: [784,10]
b: [10] -
那么识别4位纯字母验证码的数据过程:
特征值:源数据图片格式[None,20,80,3] ,为了进行矩阵计算展成二维数据[None,20803]=[None,4800]。
目标值:需要one-hot编码。 [None,426](eg:用[[0,0,1,0,0,0,0,0,0,0....][0,0...1,0..],[0,0...1,0..],[0,0...1,0..]]表示 CNPQ)
全连接过程:[None,4800][4800,104]+[104]=[None,104]
w: [4800,104]
b: [104]