您的位置:首页 > 其它

数据分析部分基础算法理论解答

2020-06-23 04:49 190 查看

K-近邻算法(KNN)

**适用数据范围:数值型和标称型 **

原理

简单地说,K-近邻算法采用测量不同特征值之间的距离方法进行分类。

  • 优点:精度高、对异常值不敏感、无数据输入假定。
  • 缺点:时间复杂度高、空间复杂度高。
  • 适用数据范围:数值型和标称型。

工作原理

存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输人没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。

一般来说,我们只选择样本数据集中前K个最相似的数据,这就是K-近邻算法中K的出处,通常K是不大于20的整数

最后 ,选择K个最相似数据中出现次数最多的分类,作为新数据的分类。

knn = KNeighborsClassifier()   #将knn算法实例化
knn.fit(X_train,y_train)       #将数据训练,返回的是算法的模型
y_ = knn.predict(X_test)       #进行数据的预测
knn.score(X_train,y_train)     #模型的评估,对于分类算法来说,就是给模型打分
knn.score(X_test,y_test)       #给测评结果打分

KNN的优缺点

  • 优点: 简单有效
  • 重新训练的代价低
  • 对于异常值不太敏感(基于邻域分类)
  • 缺点:
      时间复杂度高、空间复杂度高
    • 惰性学习,效率低下
    • 输出的结果可解释性不强
    • 适⽤数据范围:数值型和标称型
    • 可解释性不强

    近似误差:

    对现有训练集的训练误差,关注训练集,如果近似误差过小可能会出现过拟合的现象,对现有的训练集 能有很好的预测,但是对未知的测试样本将会出现较⼤偏差的预测。模型本⾝不是最接近最佳模型。

    估计误差:

    可以理解为对测试集的测试误差,关注测试集,估计误差小说明对未知数据的预测能⼒好,模型本⾝最 接近最佳模型。

    欠拟合和过拟合

    (1)定义

    • 过拟合:⼀个假设在训练数据上能够获得比其他假设更好的拟合, 但是在测试数据集上却不能很好地拟合数据,此时认为这个假设出现了过拟合的现象。(模型过于复杂)

    • 欠拟合:⼀个假设在训练数据上不能获得更好的拟合,并且在测试数据集上也不能很好地拟合数据,此时认 为这个假设出现了欠拟合的现象。(模型过于简单)

    (2)原因以及解决办法

    • 过拟合原因以及解决办法

      原因:原始特征过多,存在⼀些嘈杂特征, 模型过于复杂是因为模型尝试去兼顾各个测试数据点,解决办法: 1)重新清洗数据,导致过拟合的⼀个原因也有可能是数据不纯导致的,如果出现了过拟合就需要 我们重新清洗数据。
    • 2)增大数据的训练量,还有⼀个原因就是我们用于训练的数据量太小导致的,训练数据占总数据 的比例过小。
    • 3)减少特征维度,防止维灾难
      1. 对于Knn来说,近邻的数量非常的重要
  • 欠拟合原因以及解决办法

      原因:学习到数据的特征过少,解决办法: 1)添加其他特征项,有时候我们模型出现⽋拟合的时候是因为特征项不够导致的,可以添加其他 特征项来很好地解决。例如,“组合”、“泛化”、“相关性”三类特征是特征添加的重要⼿段,无论在什 么场景,都可以照葫芦画瓢,总会得到意想不到的效果。除上面的特征之外,“上下⽂特征”、“平台 特征”等等,都可以作为特征添加的⾸选项。
    • 2)添加多项式特征,这个在机器学习算法里面用的很普遍,例如将线性模型通过添加⼆次项或者 三次项使模型泛化能力更强。

    使用sklearn的knn模块进行分类

    #1.模型实例
    #n_neighbors=5 默认找周围的5个离自己最近的数据
    knn=KNeighborsClassifier(n_neighbors=5)
    #2.将数据进⾏训练(把数据保存到内存中)
    #X是特征数据
    #y是⽬标数据(标签)
    knn.fit(X_train,y_train)
    #3.评估 1.0代表100%的准确
    knn.score(X_train,y_train)
    #准确率 被预测正确的数据数量 / 总数据数量
    #4.对测试数据进⾏评估
    knn.score(X_test,y_test)
    #5.如果模型的分值高,那么模型可以上线,可以进⾏预测了
    knn.predict(X_test)

    K-means

    岭回归

    是一种专用于共线性数据分析的有偏估计回归方法,实质上是一种改良的最小二乘估计法,通过放弃最小二乘法的无偏性,以损失部分信息、降低精度为代价获得回归系数更为符合实际、更可靠的回归方法,对病态数据的拟合要强于最小二乘法。

    岭回归,又称脊回归、吉洪诺夫正则化(Tikhonov regularization),是对不适定问题(ill-posed problem)进行回归分析时最经常使用的一种正则化方法。

    原理

    回归分析中常用的最小二乘法是一种无偏估计。

    对于有些矩阵,矩阵中某个元素的一个很小的变动,会引起最后计算结果误差很大,这种矩阵称为“病态矩阵”。有些时候不正确的计算方法也会使一个正常的矩阵在运算中表现出病态。对于高斯消去法来说,如果主元(即对角线上的元素)上的元素很小,在计算时就会表现出病态的特征。

    岭回归是对最小二乘回归的一种补充,它损失了无偏性,来换取高的数值稳定性,从而得到较高的计算精度。

    特点

    通常岭回归方程的R平方值会稍低于普通回归分析,但回归系数的显著性往往明显高于普通回归,在存在共线性问题和病态数据偏多的研究中有较大的实用价值。

    Lasso(回归模型)

    该方法是一种压缩估计。它通过构造一个惩罚函数得到一个较为精炼的模型,使得它压缩一些回归系数,即强制系数绝对值之和小于某个固定值;同时设定一些回归系数为零。因此保留了子集收缩的优点,是一种处理具有复共线性数据的有偏估计。

    Lasso回归于岭回归非常相似,它们的差别在于使用了不同的正则化项。最终都实现了约束参数从而防止过拟合的效果。但是Lasso之所以重要,还有另一个原因是:Lasso能够将一些作用比较小的特征的参数训练为0,从而获得稀疏解。也就是说用这种方法,在训练模型的过程中实现了降维(特征筛选)的目的。

    优点

    LASSO算法在模型系数绝对值之和小于某常数的条件下,谋求残差平方和最小,在变量选取方面的效果优于逐步回归、主成分回归、岭回归、偏最小二乘等,能较好的克服传统方法在模型选取上的不足。

    特征工程

    征工程的目的,是通过一系列的工程活动,将这些信息使用更高效的编码方式(特征)表示。使用特征表示的信息,信息损失较少,原始数据中包含的规律依然保留。此外,新的编码方式还需要尽量减少原始数据中的不确定因素(白噪声、异常数据、数据缺失…等等)的影响。特征工程的目的是最大限度地从原始数据中提取特征以供算法和模型使用。

    朴素贝叶斯

    朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。

    最为广泛的两种分类模型是决策树模型(Decision Tree Model)和朴素贝叶斯模型(Naive Bayesian Model,NBM)。

    贝叶斯方法是以贝叶斯原理为基础,使用概率统计的知识对样本数据集进行分类。由于其有着坚实的数学基础,贝叶斯分类算法的误判率是很低的。贝叶斯方法的特点是结合先验概率和后验概率,即避免了只使用先验概率的主观偏见,也避免了单独使用样本信息的过拟合现象。贝叶斯分类算法在数据集较大的情况下表现出较高的准确率,同时算法本身也比较简单。

    朴素贝叶斯算法(Naive Bayesian algorithm) 是应用最为广泛的分类算法之一

    朴素贝叶斯方法是在贝叶斯算法的基础上进行了相应的简化,即假定给定目标值时属性之间相互条件独立。也就是说没有哪个属性变量对于决策结果来说占有着较大的比重,也没有哪个属性变量对于决策结果占有着较小的比重。虽然这个简化方式在一定程度上降低了贝叶斯分类算法的分类效果,但是在实际的应用场景中,极大地简化了贝叶斯方法的复杂性。

    优点

    朴素贝叶斯算法假设了数据集属性之间是相互独立的,因此算法的逻辑性十分简单,并且算法较为稳定,当数据呈现不同的特点时,朴素贝叶斯的分类性能不会有太大的差异。换句话说就是朴素贝叶斯算法的健壮性比较好,对于不同类型的数据集不会呈现出太大的差异性。当数据集属性之间的关系相对比较独立时,朴素贝叶斯分类算法会有较好的效果。

    缺点

    属性独立性的条件同时也是朴素贝叶斯分类器的不足之处。数据集属性的独立性在很多情况下是很难满足的,因为数据集的属性之间往往都存在着相互关联,如果在分类过程中出现这种问题,会导致分类的效果大大降低。

    应用

    文本分类

    分类是数据分析和机器学习领域的一个基本问题。文本分类已广泛应用于网络信息过滤、信息检索和信息推荐等多个方面。数据驱动分类器学习一直是近年来的热点,方法很多,比如神经网络、决策树、支持向量机、朴素贝叶斯等。相对于其他精心设计的更复杂的分类算法,朴素贝叶斯分类算法是学习效率和分类效果较好的分类器之一。直观的文本分类算法,也是最简单的贝叶斯分类器,具有很好的可解释性,朴素贝叶斯算法特点是假设所有特征的出现相互独立互不影响,每一特征同等重要。但事实上这个假设在现实世界中并不成立:首先,相邻的两个词之间的必然联系,不能独立;其次,对一篇文章来说,其中的某一些代表词就确定它的主题,不需要通读整篇文章、查看所有词。所以需要采用合适的方法进行特征选择,这样朴素贝叶斯分类器才能达到更高的分类效率。

    其他

    朴素贝叶斯算法在文字识别, 图像识别方向有着较为重要的作用。 可以将未知的一种文字或图像,根据其已有的分类规则来进行分类,最终达到分类的目的。

    现实生活中朴素贝叶斯算法应用广泛,如文本分类,垃圾邮件的分类,信用评估,钓鱼网站检测等等。

    决策树

    决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。在机器学习中,决策树是一个预测模型,他代表的是对象属性与对象值之间的一种映射关系。Entropy = 系统的凌乱程度,使用算法ID3, C4.5和C5.0生成树算法使用熵。这一度量是基于信息学理论中熵的概念。

    决策树是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶节点代表一种类别。

    分类树(决策树)是一种十分常用的分类方法。他是一种监管学习,所谓监管学习就是给定一堆样本,每个样本都有一组属性和一个类别,这些类别是事先确定的,那么通过学习得到一个分类器,这个分类器能够对新出现的对象给出正确的分类。这样的机器学习就被称之为监督学习。

    组成

    决策点,是对几种可能方案的选择,即最后选择的最佳方案。如果决策属于多级决策,则决策树的中间可以有多个决策点,以决策树根部的决策点为最终决策方案。

    状态节点,代表备选方案的经济效果(期望值),通过各状态节点的经济效果的对比,按照一定的决策标准就可以选出最佳方案。由状态节点引出的分支称为概率枝,概率枝的数目表示可能出现的自然状态数目每个分枝上要注明该状态出现的概率。

    结果节点,将每个方案在各种自然状态下取得的损益值标注于结果节点的右端。

    决策树是一个预测模型;他代表的是对象属性与对象值之间的一种映射关系。树中每个节点表示某个对象,而每个分叉路径则代表的某个可能的属性值,而每个叶结点则对应从根节点到该叶节点所经历的路径所表示的对象的值。决策树仅有单一输出,若欲有复数输出,可以建立独立的决策树以处理不同输出。数据挖掘中决策树是一种经常要用到的技术,可以用于分析数据,同样也可以用来作预测。

    优点

    • 决策树易于理解和实现,人们在在学习过程中不需要使用者了解很多的背景知识,这同时是它的能够直接体现数据的特点,只要通过解释后都有能力去理解决策树所表达的意义。

    • 对于决策树,数据的准备往往是简单或者是不必要的,而且能够同时处理数据型和常规型属性,在相对短的时间内能够对大型数据源做出可行且效果良好的结果。

    • 易于通过静态测试来对模型进行评测,可以测定模型可信度;如果给定一个观察的模型,那么根据所产生的决策树很容易推出相应的逻辑表达式。

    缺点

    • 对连续性的字段比较难预测。

    • 对有时间顺序的数据,需要很多预处理的工作。

    • 当类别太多时,错误可能就会增加的比较快。

    • 一般的算法分类的时候,只是根据一个字段来分类。

    ID3

    ID3算法是一种贪心算法,用来构造决策树。ID3算法起源于概念学习系统(CLS),以信息熵的下降速度为选取测试属性的标准,即在每个节点选取还尚未被用来划分的具有最高信息增益的属性作为划分标准,然后继续这个过程,直到生成的决策树能完美分类训练样例。

    该算法是以信息论为基础,以信息熵和信息增益度为衡量标准,从而实现对数据的归纳分类。以下是一些信息论的基本概念:

    定义1:若存在n个相同概率的消息,则每个消息的概率p是1/n,一个消息传递的信息量为-Log2(1/n)

    定义2:若有n个消息,其给定概率分布为P=(p1,p2…pn),则由该分布传递的信息量称为P的熵,记为

    定义3:若一个记录集合T根据类别属性的值被分成互相独立的类C1C2…Ck,则识别T的一个元素所属哪个类所需要的信息量为Info(T)=I§,其中P为C1C2…Ck的概率分布,即P=(|C1|/|T|,……|Ck|/|T|)

    定义4:若我们先根据非类别属性X的值将T分成集合T1,T2…Tn,则确定T中一个元素类的信息量可通过确定Ti的加权平均值来得到,即Info(Ti)的加权平均值为:

    Info(X, T)=(i=1 to n 求和)((|Ti|/|T|)Info(Ti))

    定义5:信息增益度是两个信息量之间的差值,其中一个信息量是需确定T的一个元素的信息量,另一个信息量是在已得到的属性X的值后需确定的T一个元素的信息量,信息增益度公式为:

    Gain(X, T)=Info(T)-Info(X, T)

    ID3算法计算每个属性的信息增益,并选取具有最高增益的属性作为给定集合的测试属性。对被选取的测试属性创建一个节点,并以该节点的属性标记,对该属性的每个值创建一个分支据此划分样本。

    C4.5

    C4.5算法继承了ID3算法的优点,并在以下几方面对ID3算法进行了改进:

    • 用信息增益率来选择属性,克服了用信息增益选择属性时偏向选择取值多的属性的不足;

    • 在树构造过程中进行剪枝;

    • 能够完成对连续属性的离散化处理;

    • 能够对不完整数据进行处理。

    优点

    产生的分类规则易于理解,准确率较高。其缺点是:在构造树的过程中,需要对数据集进行多次的顺序扫描和排序,因而导致算法的低效。此外,C4.5只适合于能够驻留于内存的数据集,当训练集大得无法在内存容纳时程序无法运行。

    具体算法步骤如下:

    1.创建节点N

    2.如果训练集为空,在返回节点N标记为Failure

    3.如果训练集中的所有记录都属于同一个类别,则以该类别标记节点N

    4.如果候选属性为空,则返回N作为叶节点,标记为训练集中最普通的类;

    5.for each 候选属性 attribute_list

    6.if 候选属性是连续的then

    7.对该属性进行离散化

    8.选择候选属性attribute_list中具有最高信息增益率的属性D

    9.标记节点N为属性D

    10.for each 属性D的一致值d

    11.由节点N长出一个条件为D=d的分支

    12.设s是训练集中D=d的训练样本的集合

    13.if s为空

    14.加上一个树叶,标记为训练集中最普通的类

    15.else加上一个有C4.5(R - {D},C,s)返回的点

    C5.0

    随机森林

    概念

    1.分裂

    在决策树的训练过程中,需要一次次的将训练数据集分裂成两个子数据集,这个过程就叫做分裂。

    2.特征

    在分类问题中,输入到分类器中的数据叫做特征。以上面的股票涨跌预测问题为例,特征就是前一天的交易量和收盘价。

    3.待选特征

    在决策树的构建过程中,需要按照一定的次序从全部的特征中选取特征。待选特征就是在目前的步骤之前还没有被选择的特征的集合。例如,全部的特征是 ABCDE,第一步的时候,待选特征就是ABCDE,第一步选择了C,那么第二步的时候,待选特征就是ABDE。

    4.分裂特征

    接待选特征的定义,每一次选取的特征就是分裂特征,例如,在上面的例子中,第一步的分裂特征就是C。因为选出的这些特征将数据集分成了一个个不相交的部分,所以叫它们分裂特征。

    优点

    1)对于很多种资料,它可以产生高准确度的分类器;

    2)它可以处理大量的输入变数;

    3)它可以在决定类别时,评估变数的重要性;

    4)在建造森林时,它可以在内部对于一般化后的误差产生不偏差的估计;

    5)它包含一个好方法可以估计遗失的资料,并且,如果有很大一部分的资料遗失,仍可以维持准确度;

    6)它提供一个实验方法,可以去侦测variable interactions;

    7)对于不平衡的分类资料集来说,它可以平衡误差;

    8)它计算各例中的亲近度,对于数据挖掘、侦测离群点(outlier)和将资料视觉化非常有用;

    9)它可被延伸应用在未标记的资料上,这类资料通常是使用非监督式聚类。也可侦测偏离者和观看资料;

    10)学习过程是很快速的。

    支持向量机(SVM)

    支持向量机(Support Vector Machine, SVM)是一类按监督学习(supervised learning)方式对数据进行二元分类的广义线性分类器(generalized linear classifier),其决策边界是对学习样本求解的最大边距超平面(maximum-margin hyperplane) 。

    SVM使用铰链损失函数(hinge loss)计算经验风险(empirical risk)并在求解系统中加入了正则化项以优化结构风险(structural risk),是一个具有稀疏性和稳健性的分类器 。SVM可以通过核方法(kernel method)进行非线性分类,是常见的核学习(kernel learning)方法之一。

    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn import svm, datasets
    % matplotlib inline
    # 鸢尾花数据
    iris = datasets.load_iris()
    X = iris.data[:, :2] # 为便于绘图仅选择2个特征
    y = iris.target
    # 测试样本(绘制分类区域)
    xlist1 = np.linspace(X[:, 0].min(), X[:, 0].max(), 200)
    xlist2 = np.linspace(X[:, 1].min(), X[:, 1].max(), 200)
    XGrid1, XGrid2 = np.meshgrid(xlist1, xlist2)
    # 非线性SVM:RBF核,超参数为0.5,正则化系数为1,SMO迭代精度1e-5, 内存占用1000MB
    svc = svm.SVC(kernel='rbf', C=1, gamma=0.5, tol=1e-5, cache_size=1000).fit(X, y)
    # 预测并绘制结果
    Z = svc.predict(np.vstack([XGrid1.ravel(), XGrid2.ravel()]).T)
    Z = Z.reshape(XGrid1.shape)
    plt.contourf(XGrid1, XGrid2, Z, cmap=plt.cm.hsv)
    plt.contour(XGrid1, XGrid2, Z, colors=('k',))
    plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k', linewidth=1.5, cmap=plt.cm.hsv)

    AUC

    **ROC曲线下方的面积大小 **

    被定义为ROC曲线下与坐标轴围成的面积,显然这个面积的数值不会大于1。又由于ROC曲线一般都处于y=x这条直线的上方,所以AUC的取值范围在0.5和1之间。AUC越接近1.0,检测方法真实性越高;等于0.5时,则真实性最低,无应用价值。

    • AUC = 1,是完美分类器。
    • AUC = [0.85, 0.95], 效果很好
    • AUC = [0.7, 0.85], 效果一般
    • AUC = [0.5, 0.7],效果较低,但用于预测股票已经很不错了
    • AUC = 0.5,跟随机猜测一样(例:丢铜板),模型没有预测价值。
    • AUC < 0.5,比随机猜测还差;但只要总是反预测而行,就优于随机猜测。

    ROC

    ROC曲线的横坐标是伪阳性率(也叫假正类率,False Positive Rate),纵坐标是真阳性率(真正类率,True Positive Rate),相应的还有真阴性率(真负类率,True Negative Rate)和伪阴性率(假负类率,False Negative Rate)。

    作用

    • ROC曲线能很容易的查出任意阈值对学习器的泛化性能影响。

    • 有助于选择最佳的阈值。ROC曲线越靠近左上角,模型的准确性就越高。最靠近左上角的ROC曲线上的点是分类错误最少的最好阈值,其假正例和假反例总数最少。

    • 可以对不同的学习器比较性能。将各个学习器的ROC曲线绘制到同一坐标中,直观地鉴别优劣,靠近左上角的ROC曲所代表的学习器准确性最高。

    优点

    • 该方法简单、直观、通过图示可观察分析学习器的准确性,并可用肉眼作出判断。ROC曲线将真正例率和假正例率以图示方法结合在一起,可准确反映某种学习器真正例率和假正例率的关系,是检测准确性的综合代表。

    • ROC曲线不固定阈值,允许中间状态的存在,利于使用者结合专业知识,权衡漏诊与误诊的影响,选择一个更加的阈值作为诊断参考值。

    梯度下降算法

    import numpy as np
    import matplotlib.pyplot as plt
    
    # 构造数据
    def get_data(sample_num=1000):
    """
    拟合函数为
    y = 5*x1 + 7*x2
    :return:
    构造1000组数据集(x1,x2,y)
    """
    '''生成具有sample_num=1000个等间隔元素的范围是[0,9]的一个数列'''
    x1 = np.linspace(0, 9, sample_num)
    x2 = np.linspace(4, 13, sample_num)
    '''将x1,x2合并成2*sample_num的矩阵并转置,最终是sample_num*2的矩阵'''
    x = np.concatenate(([x1], [x2]), axis=0).T
    '''x.dot(y) 等价于 np.dot(x,y)  两个矩阵相乘'''
    y = np.dot(x, np.array([5, 7]).T)
    return x, y
    
    # 梯度下降法
    def SGD(samples, y, step_size=0.1, max_iter_count=2000):
    """
    :param samples: 样本
    :param y: 结果value
    :param step_size: 每一接迭代的步长
    :param max_iter_count: 最大的迭代次数
    :param batch_size: 随机选取的相对于总样本的大小
    :return:
    """
    # 确定样本数量以及变量的个数初始化theta值
    
    m, var = samples.shape  # m=1000是行,var=2是列
    theta = np.zeros(2)
    '''flatten,把y降到一维,默认是按横的方向降。y.flatten('F')按竖的方向降。
    此处就是将y进行转置
    '''
    y = y.flatten()
    # 进入循环内
    loss = 1
    iter_count = 0
    
    iter_list = []
    loss_list = []
    theta1 = []
    theta2 = []
    # 当损失精度大于0.01且迭代此时小于最大迭代次数时,进行
    while loss > 0.01 and iter_count < max_iter_count:
    loss = 0
    # 梯度计算
    theta1.append(theta[0])
    theta2.append(theta[1])
    
    # 样本维数下标
    rand1 = np.random.randint(0, m, 1)  # 生成大小在范围[0,m]内的一个随机数
    h = np.dot(theta, samples[rand1].T)  # samples[rand1]第rand1行
    # 关键点,只需要一个样本点来更新权值
    for i in range(len(theta)):
    theta[i] = theta[i] - step_size * (1/m) * (h - y[rand1]) * samples[rand1, i]
    
    """
    # batch_size = np.random.randint(0, m, 1)
    batch_size = range(1, m)
    batch_size = np.array(batch_size)
    (si,) = batch_size.shape
    dev = 0
    for i in range(len(theta)):
    for j in batch_size:
    h = np.dot(theta, samples[j].T)
    dev = dev + (1 / si) * (h - y[j]) * samples[j, i]
    theta[i] = theta[i] - step_size * dev
    
    """
    # 计算总体的损失精度,等于各个样本损失精度之和
    for i in range(m):
    h = np.dot(theta.T, samples[i])
    # 每组样本点损失的精度
    every_loss = (1 / (var * m)) * np.power((h - y[i]), 2)
    loss = loss + every_loss
    
    print("iter_count: ", iter_count, "the loss:", loss)
    
    iter_list.append(iter_count)
    loss_list.append(loss)
    
    iter_count += 1
    
    plt.plot(iter_list, loss_list)
    plt.xlabel("iter")
    plt.ylabel("loss")
    plt.show()
    return theta1, theta2, theta, loss_list
    
    if __name__ == '__main__':
    samples, y = get_data()
    theta1, theta2, theta, loss_list = SGD(samples, y)
    print(theta)  # 会很接近[5, 7]

    批量梯度下降法BGD

    批量梯度下降每次更新使用了所有的训练数据,最小化损失函数,如果只有一个极小值,那么批量梯度下降是考虑了训练集所有的数据,是朝着最小值迭代运动的,但是缺点是如果样本值很大的话,更新速度会很慢。

    import numpy as np
    
    # #BGD:批量梯度下降 每次迭代使用全部的样本数据
    # #用y = Θ1*x1 + Θ2*x2来拟合下面的输入和输出
    # #input1  1   3   5   4
    # #input2  4   5   1   2
    # #output  15  21  13  14
    # #实际的式子是:y=2*x1+3*x2
    input_x=[[1,4],[3,5],[5,1],[4,2]]#输入
    input_x=np.array(input_x)
    y=[14,21,13,14]#输出
    y=np.array(y)
    theta=np.ones(input_x.shape[1])#设置Θ初值 为 1*2矩阵
    loss=1 #使损失先定义一个数,为了进入循环
    step_size=0.01 #学习率/步长
    eps=0.0001#准确率
    max_iters=10000 #最大迭代次数
    error=0 #损失值
    iter_count=0#当前的迭代数
    err1=np.zeros(input_x.shape[0])#定义Θ1求梯度的中间变量
    err2=np.zeros(input_x.shape[0])#定义Θ2求梯度的中间变量
    
    while (loss > eps and iter_count < max_iters):
    loss=0#初始化本次的实验误差
    err1Sum=0#初始化Θ1梯度的误差损失和
    err2Sum = 0  # 初始化Θ2梯度的误差损失和
    for i in range(input_x.shape[0]):
    pre_y=theta[0]*input_x[i][0]+theta[1]*input_x[i][1]#得到预测值
    err1[i]=(pre_y-y[i])*input_x[i][0] #第i步是对Θ1求导得到的
    err1Sum+=err1[i]
    err2[i] = (pre_y - y[i]) * input_x[i][1]  # 该步是对Θ2求导得到的
    err2Sum += err2[i]
    theta[0]-=step_size*err1Sum/4 #得到下一步的thea[0]
    theta[1]-=step_size*err2Sum / 4  # 得到下一步的thea[1]
    for i in range((input_x.shape[0])):
    pre_y=theta[0]*input_x[i][0]+theta[1]*input_x[i][1]#得到预测值
    error=(1/(2*(input_x.shape[0])))*(pre_y-y[i])**2 #得到损失值(2*(input_x.shape[0]))这个也可以为2
    loss+=error#该次总损失
    iter_count+=1#记录迭代次数
    print("iter_count:",iter_count)
    print("loss:",loss)
    print("theta:",theta)
    print("final loss value:",loss)
    print("total iters:",iter_count)

    优点

    • 一次迭代是对所有样本进行计算,此时利用矩阵进行操作,实现了并行。

    • 由全数据集确定的方向能够更好地代表样本总体,从而更准确地朝向极值所在的方向。当目标函数为凸函数时,BGD一定能够得到全局最优。

    缺点

    • 当样本数目 mm 很大时,每迭代一步都需要对所有样本计算,训练过程会很慢。

    • 由于这种方法是在一次更新中,就对整个数据集计算梯度,所以计算起来非常慢,遇到很大量的数据集也会非常棘手,而且不能投入新数据实时更新模型。

    随机梯度下降法SGD

    随机梯度下降在每次更新的时候,只考虑一个样本点,这样会大大加快训练数据,也恰好是批量梯度下降的缺点,但是有可能由于训练数据的噪声点较多,那么每一次利用噪声点进行更新的过程中,就不一定是朝着极小值方向更新,但是由于更新多轮,整体方向还是朝着极小值方向更新,又提高了速度。

    import numpy as np
    
    #SGD:随机梯度下降法
    input_x=[[1,4],[3,5],[5,1],[4,2]]#输入
    input_x=np.array(input_x)
    y=[14,21,13,14]#输出
    y=np.array(y)
    theta=np.ones(input_x.shape[1])#设置Θ初值 为 1*2矩阵
    loss=1 #使损失先定义一个数,为了进入循环
    step_size=0.01 #学习率/步长
    eps=0.0001#准确率
    max_iters=10000 #最大迭代次数
    error=0 #损失值
    iter_count=0#当前的迭代数
    err1=np.zeros(input_x.shape[0])#定义Θ1求梯度的中间变量
    err2=np.zeros(input_x.shape[0])#定义Θ2求梯度的中间变量
    while (loss>eps and iter_count<max_iters):
    loss=0
    i=np.random.randint(0,input_x.shape[0])#随机抽样
    pre_y=theta[0]*input_x[i][0]+theta[1]*input_x[i][1]#预测值
    theta[0]-=step_size*(pre_y-y[i])*input_x[i][0]
    theta[1] -= step_size * (pre_y - y[i]) * input_x[i][1]
    for i in np.arange(input_x.shape[0]):
    pre_y = theta[0] * input_x[i][0] + theta[1] * input_x[i][1]  # 预测
    error=0.5*(pre_y-y[i])**2
    loss+=error
    iter_count+=1
    print("iter_count:",iter_count)
    print("theta:",theta)
    print("final loss:",loss)
    print("iters:",iter_count)

    优点

    • 由于不是在全部训练数据上的损失函数,而是在每轮迭代中,随机优化某一条训练数据上的损失函数,这样每一轮参数的更新速度大大加快。

    缺点

    • 准确度下降。由于即使在目标函数为强凸函数的情况下,SGD仍旧无法做到线性收敛。

    • 可能会收敛到局部最优,由于单个样本并不能代表全体样本的趋势。
      不易于并行实现。

    • 会造成 cost function 有严重的震荡。

    解释一下为什么SGD收敛速度比BGD要快:
      答:这里我们假设有30W个样本,对于BGD而言,每次迭代需要计算30W个样本才能对参数进行一次更新,需要求得最小值可能需要多次迭s代(假设这里是10);而对于SGD,每次更新参数只需要一个样本,因此若使用这30W个样本进行参数更新,则参数会被更新(迭代)30W次,而这期间,SGD就能保证能够收敛到一个合适的最小值上了。也就是说,在收敛时,BGD计算了 10×30W10×30W 次,而SGD只计算了 1×30W1×30W 次。

    小批量梯度下降法MBGD

    小批量梯度下降法是为了解决批量梯度下降的训练速度慢,以及随机梯度下降法的准确性综合而来,但是这里注意,不同问题的batch是不一样的,要通过实验结果来进行超参数的调整。

    import numpy as np
    
    MBGD:小批量梯度下降
    从数据中抽取一小组数据测试
    input_x=[[1,4],[3,5],[5,1],[4,2]]#输入
    input_x=np.array(input_x)
    y=[14,21,13,14]#输出
    y=np.array(y)
    theta=np.ones(input_x.shape[1])#设置Θ初值 为 1*2矩阵
    loss=1 #使损失先定义一个数,为了进入循环
    step_size=0.01 #学习率/步长
    eps=0.0001#准确率
    max_iters=10000 #最大迭代次数
    error=0 #损失值
    iter_count=0#当前的迭代数
    err1=np.zeros(input_x.shape[0])#定义Θ1求梯度的中间变量(1*4:[0,0,0,0])
    err2=np.zeros(input_x.shape[0])#定义Θ2求梯度的中间变量
    while (loss>eps and iter_count<max_iters):
    loss=0
    #ij 为抽取的两个数
    i=np.random.randint(0,input_x.shape[0])
    j=(i+1)%input_x.shape[0]
    pre_y0=theta[0] * input_x[i][0] + theta[1] * input_x[i][1]
    pre_y1=theta[0] * input_x[j][0] + theta[1] * input_x[j][1]
    theta[0]-=step_size * (1/2) * ((pre_y0 - y[i]) * input_x[i][0]+(pre_y1 - y[j]) * input_x[j][0])  #对第一个参数求导
    theta[1]-=step_size * (1 / 2) * (
    (pre_y0 - y[i]) * input_x[i][1] + (pre_y1 - y[j]) * input_x[j][1])  # 对应5式
    for i in range(3):
    pre_y = theta[0] * input_x[i][0] + theta[1] * input_x[i][1]  # 总预测值
    error = (1 / (2 * 2)) * (pre_y - y[i]) ** 2  # 损失值
    loss = loss + error  # 总损失值
    iter_count += 1
    print('iters_count', iter_count)
    
    print('theta: ', theta)
    print('final loss: ', loss)
    print('iters: ', iter_count)

    优点

    • 通过矩阵运算,每次在一个batch上优化神经网络参数并不会比单个数据慢太多。

    • 每次使用一个batch可以大大减小收敛所需要的迭代次数,同时可以使收敛到的结果更加接近梯度下降的效果。(比如上例中的30W,设置batch_size=100时,需要迭代3000次,远小于SGD的30W次)

    • 可实现并行化。

    缺点

    • batch_size的不当选择可能会带来一些问题。

    归一化?作用

    归一化是一种简化计算的方式,即将有量纲的表达式,经过变换,化为无量纲的表达式,成为标量。 在多种计算中都经常用到这种方法。

    什么时候用归一化?什么时候用标准化?
     (1)如果对输出结果范围有要求,用归一化。
     (2)如果数据较为稳定,不存在极端的最大最小值,用归一化。
     (3)如果数据存在异常值和较多噪音,用标准化,可以间接通过中心化避免异常值和极端值的影响。

    PCA

  • 内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: