Logistic In MNIST
算法原理简述:
二项逻辑斯蒂回归模型是一种分类模型,有条件概率P(Y|X)表示,形式为参数化的逻辑斯蒂分布。
在本实验中,对于该模型的二项形式,因为只能做二分类,所以我们对数据集的标签进行的改变只剩下0和1;而后输入的依旧是图像的向量,主要需要掌握的是关于该模型的推导和如何迭代得到近似最优解。
代码如下:
|
|
模型的训练结果:
可以看到,逻辑斯蒂的正确率很高,但是相对的,训练的时间也较长。
二项逻辑斯蒂回归模型是一种分类模型,有条件概率P(Y|X)表示,形式为参数化的逻辑斯蒂分布。
在本实验中,对于该模型的二项形式,因为只能做二分类,所以我们对数据集的标签进行的改变只剩下0和1;而后输入的依旧是图像的向量,主要需要掌握的是关于该模型的推导和如何迭代得到近似最优解。
|
|
可以看到,逻辑斯蒂的正确率很高,但是相对的,训练的时间也较长。
决策树作为机器学习算法的基础算法之一,其优点是模型具有可读性,分类速度快。决策树的基本算法可以参考李航老师的《统计机器学习》,本文中的主要思路也是基于此。对于决策树而言,主要有三部分的工作需要实现,特征提取,决策树构造和决策树的剪枝。在特征提取部分,常用的是信息增益和信息增益比,分别对应于ID3和C4.5决策树算法;决策树的构造部分主要是利用递归的思想构建;本文中未涉及到决策树剪枝部分。
本文中实现的是利用信息增益进行特征提取的ID3决策树,主要需要提及的部分是关于树的节点构造的部分。树的节点中主要包含了节点类型,包括叶节点和内部节点,用于在预测过程中当预测到达叶节点时,返回所属类别;也包含了节点所属类别(只针对叶节点存在);包含当前节点的最优切分位置(对于非叶节点存在);以及切分位置取不同值所属的不同子树,用字典保存。
基本思路是:我们在函数中输入训练数据,训练标签,可切分维度集合和信息增益阈值。
首先判断当前训练标签的类数,如果只有一类,我们将其设置为叶节点,节点类别取当前标签,然后返回;然后判断可切分维度的数量,如果不存在切分维度,则取当前训练标签中的最多那一类作为节点的类别,设置节点为叶节点返回;
以上情况都不符合的情况下,我们遍历所有的切分点,找到信息增益最大的位置,提取出这一列的值;并根据这一列的不同取值所对应的标签得到下一步的训练数据、训练标签和切分维度集合用于构建子树,并将子树添加到当前树中。
|
|
对于本文中所实现的决策树在MNIST上的分类结果在Kaggle平台上测试结果为85.07%左右,相比于KNN,其分类效果要差不少,但是所需要的计算时间较少于KNN算法。
给定一个字符串,找到字符串中的最长回文子串。见LeetCode5
本题的常见解法有三种。第一种是中心扩展的方法。在遍历字符串的过程,以当前字符串为中心向左右两侧扩展,扩展结束后判断子串的长度。需要注意的是:这种方法中有偶回文串和奇数回文串的区别,遍历的过程需要区别对待。aba奇回文子串,abba是偶回文子串。
|
|
第二种思路是使用动态规划的方法。我们用P[i, j]表示字符串中i到j位置的子串;如果这个串是回文字符串则我们设定为1;如果这个子串不是回文字符串我们则设定为0。这样我们构建一个二维的数组用来保存是否是回文的信息;然后根据一下三种情况来进行修改数组中的信息。
需要注意的地方是,我们则判断P[i, j]的时候用的是P[i + 1, j - 1]的情况,所以我们需要先知道P[i + 1,j - 1]的情况,这样决定了我们i需要从末尾开始遍历开始,然后j从i位置遍历到字符串的末尾。
|
|
朴素贝叶斯方法是基于贝叶斯定理与特征条件独立假设的分类方法。对于给定的训练数据集,首先基于特征条件独立假设学习输入和输出的联合概率分布;然后基于此模型,对给定的输入利用贝叶斯定理求出后验概率最大的输出。模型的优点是实现简单学习和预测的效率都很高,是一种常用的方法。
在MNIST数据集中,我们的特征是输入图像每一维的数据,根据已有的输入和输出估计联合概率分布;在输出新的数据集的情况下,我们根据训练好的模型,计算最大后验概率来对数据集进行分类。
|
|
相比之下朴素贝叶斯的正确较差,但是胜在模型简单,并且训练速度快。
感知机模型是二类分类的线性分类模型,其输入为实例的特征向量,输出为实例的类别,取{+1,-1}二者。感知机对应于输入空间中将实例划分为正负两类的分离超平面,属于判别模型。感知机学习旨在求出将训练数据进行线性划分的分离超平面,为此,导入基于误分类的损失函数,利用梯度下降法对损失函数进行极小化,求得感知机模型。感知机学习算法具有简单而易实现的优点。
感知机模型选择的是误分类点到超平面的总距离为损失函数。直觉上我们选择误分类的总点数作为损失函数,但是这样的损失函数不是参数的可导函数。
感知机模型中一个实例点被误分类的时候,我们调整w和b的参数,使得分类超平面向误分类点的一侧移动以减少误分类点到分类超平面的距离。
|
|
来自leetcode的contest。具体的题目描述可以在这里找到。
本题主要的难点有:怎么找到左侧边界;怎么找到右侧边界;怎么找到下边界;以及如何将边界连接已经右侧边界的逆序。 根据代码解释一下思路;首先判断根节点是否为空决定是否返回空的vector;其次定义用于保存边界的vector并将根节点的值导入;定义用于保存遍历过程节点的集合,将根节点导入;分别定义vector用于保存左侧边界、右侧边界和下边界;根据遍历函数得到的左右下边界,遍历其中的节点找到不重复的节点连接即为整颗树的边界。
|
|
给定一个数字n,和一个关于需要生成排列的长度k。要求根据这两个数字,从[1…n]的数组中生成长度为k的排列。
例如给定数字为n=4,k=2;则根据要求生成的排列为[[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]。见LeetCode77.
这道题理解上问题不大,主要是在于用什么方法去解决。我们首先想到的是使用回溯的方法来解决。首先是使用一个标签变量来记录我们当前要确定排列中的第几个位置,然后递归的调用函数来确定下面位置的数字。主要的思路体现在代码中,可以看代码中的注释来理解。
|
|
当然这道题也可以使用递归的方法来解决。主要不同的是直接生成一个当前路径数组,然后不断的确定当前位置的数字即可。
|
|
给定一个字符串,将其转化为对应的合法的数字。其中字符串可能的输入存在多种情况,需要考虑。如果是非法的转化,返回0;如果是大于2147483647则返回INT_MAX(2147483647);如果是小于-2147483648则返回INT_MIN(-2147483648).见LeetCode8
题目的整体思路不难,主要利用’9’-‘0’来得到对应位数代表的数字,用上一位的累加和乘以10加上当前位数得到结果。需要考虑的部分有:输入的开头可能是空格,我们需要跳过这些字符;当到达第一位非空格的时候,记录下数字的符号;最后需要考虑的是超过整形数字的范围;我们的做法是用base=INT_MAX/10来作为标记;如果在还没到达最后一位的时候,当前已经大于base,则结果一定溢出,所以返回对应符号的数即可,如果是当前值等于base的情况下,判断当前为是否大于7,如果大于7也是同样的做法。当然好几种情况在返回0的情况可以全部合并,写入注释用于提醒。所以做题之前需要多考虑Corner case。
|
|
1
给定一个数组[x1,x2,x3….xn]。我们定义其为连除模式,即x1/x2/x3/x4..xn。在这个序列中我们可以在任意位置中加上括号改变其计算顺序。要求找到其中所有加入括号的结果中最大的那个加入括号的方式,并返回加入括号所形成的字符串。
[1000,100,10,2],我们可以加入括号形成(1000/100)/(10/2),或者1000/(100/(10/2))等。详细解释可以看 leetcode553
初看这个题目会觉得非常的难,因为需要考虑到所有的情况中最大的那一种;并且需要在不同的位置上加上括号形成字符串。但是其实仔细考虑后我们就会发下:即不管在任意位置上加上括号,x1永远是除数,而x2永远中是被除数中的一个。所以我们就可以写成等价的方式x1/(x2/y),其中y的方式可以是任意的。通过调整分子分母可以发现:x1/(x2/y) = x1y/(x2).所以最大值的情况在y最大的情况下出现,而y的最大化即为(x3 x4 * x5….)。所以最后的最大结果肯定是:x1/(x2/(x3/x4/x5….xn)),所以我们直接返回这样的结果即可。
|
|
给定一棵树的头节点,要求将树变成指定的链表形状。具体的描述和例子可以看leetcode网站
最直接的一种思路是将链表中的节点按照一定的顺序放入栈或者队列中,然后按照要求将其重新连接就行。可以从题目中发现是类似树的先序遍历的样纸,所以在将树中节点放入队列的时候可以根据这个规律来实现。
|
|
当然对于树的题目我们依旧可以使用递归的想法来实现。我们的想法是利用一个指针pre来保存不断移动的当前的位置,然后不断的改变指针的指向即可。
|
|
在可以利用递归的方法的情况下,我们也可以利用非递归的思路来解决这个问题。解决的思路比较难描述,可以画一棵简单树按照代码中的思路就可以知道解法。
|
|