【文本处理】
本次实验的不同:
1. 属性列是已知的,所以不需要进行关键词筛选;
2. 输入文件是csv,一样用到ifstream读取,但是分割符不是空格,而是逗号,这里需要用到find函数找到string中逗号的位置,再用substr函数进行子字符串分割,然后用atof函数将string转为double类型保存下来,这样就得到所有样本的属性值和share值,将所有样本的share值单独保存到map里(方便查询)
【算法分析】
本次实验,我选择分类任务,实现了KNN和NB分类算法,还未实现决策树ID3算法,下面总结我对三种算法的理解和实现。
【KNN】
k-近邻算法是一种基于实例的分类方法,找出与未知样本x距离最近的k个训练样本,若在特征空间中k个最相似的样本中大多数属于某类别,则该样本也属于该类别。本实验固定k值为1,即找出距离最近的1个训练样本,将该样本的share值预测为本测试样本的share值。
k-近邻是懒惰学习算法(存放样本,分类时才计算),若样本量大复杂,就会导致很大的计算开销,无法用到实时性很强的场合。KNN算法较合适样本容量较大的类域自动分类,因为KNN主要靠周围有限的临近的样本,而不是靠判别类域的方法来确定所属类别,对类域交叉or重叠较多的待分样本集来说更合适,避免样本的不平衡问题。
本次实验样本量超过3万个,为减少计算量,我采用曼哈顿距离(欧式距离要计算平方,计算量大且会溢出,可以选择去掉过大过小值,或者取对数运算)
【NB】
贝叶斯算法是在已知先验概率与类条件概率的情况下的模式分类方法(也可以回归),待分样本的分类结果取决于各类域中样本的全体。本实验用的是朴素贝叶斯算法,其思想基础是对于给出的待分类项,求解在此项出现的条件下各个类别的出现概率,哪个大就认为此待分类项属于哪个类别。
如果特征属性为离散的,那就统计出现概率来估计条件概率,但是本数据集的属性列值是连续的,这就需要假定其值服从高斯分布(正态分布)来求概率值。先算出各个类别中此特征项划分的各均值和标准差,利用公式计算每个值的概率。
得到概率值后,为了避免出现P(a|y)=0的情况(当某类别下某特征项划分没出现时就会这样,这会大大降低分类器质量),引入Laplace校准,对所有划分计数加一,当训练样本集数量充分大时,不会对结果产生影响。得到正态分布概率后,每行向量需要归一化,最后再将测试样本和训练样本都有的特征的概率相乘,为了避免计算溢出,我采用对数运算连加后再指数运算(这里我会加个常量,为了所有值以0.5为分界值分布,进行后面的预测值判断;后来想到,可以再做归一化,找到最大值,所有值除以最大值,再映射到0/1,不过这需要符合线性映射才行),其中我去掉概率值极小的(小与0.1的),因为概率极小就说明几乎不相关,所以舍弃不计算,最后得到的概率大于0.5,则预测share值为1,否则预测为0。
理论上朴素贝叶斯模型与其他分类相比具有最小的误差率(基于统计学理论稳定的分类效率),但实际上往往不能达到理论最大值,因为它有个前提假设是属性之间要互相独立,这个假设在实际应用中往往不成立(可以考虑聚类算法将相关性较大的属性聚类,未实现),所以只有在属性相关性较小时,NBC模型性能最为良好。
【决策树ID3】
我还没有实现决策树算法,下面说说我对ID3的理解和实现流程。
决策树是分类的主要方法之一,它从一组无次序、无规则的实例中推理出以决策树表示的分类规则,建树目的是找出属性和类别间的关系,用来预测未知记录的类别。决策树是自顶而下的递归方式,在内部节点进行属性比较,根据不同属性值判断从该节点向下得分支,在叶节点得到结论。选择属性采用的方式不同延伸得不同的决策树算法,ID3用的是子树得信息增益(熵的变化值),C4.5用的是信息增益率,克服信息增益选择属性时偏向选择取值多的属性得不足。对于非离散数据,处理时需要划分区间,方法很多(采取均值、中位数),看哪种分法更好。
决策树实现流程(假设属性值只有0,1)——
每个节点应包括(进行数据集分裂的属性号、类标、左子节点的地址、右子节点的地址),输入矩阵A(m行n列,m个样本n个属性,A(i,j)表示第i样本存在第j属性),向量b(m行1列,m个样本的类标),输出是树跟节点地址。
过程:
1.计算熵值
2.计算每个属性的条件熵:
矩阵T(2行k列),表示k个类标,2行表示该属性值为0/1,T(i,j)表示当第j属性的属性值为i时类标j的元素个数
3.选取条件熵最小的进行判断:
a)若等于第一步熵值,返回NULL;
b)若小于第一步熵值,将样本分裂两部分(按照该属性值0/1划分)
4.将节点值设为对应属性的属性值
5.将节点的类标设为b中数量最大的类标
6.设置左右子节点
改进:
可能存在某些属性下所有样本值全部一致的情况(全为0/1),这时就没必要算条件熵了,所以这里可以稍微改进,传多个参数说明可选的属性号,存放全部计算条件熵有意义的属性。
连续值:
属性是连续值,需要确定一个值作为分裂点split_point,按照
剪枝:
实际构造决策树时通常要剪枝,这是为了处理由于数据中的噪声的离群点导致的过拟合问题,剪枝分两种:
先剪枝——构造过程中,当某节点满足剪枝条件,则直接停止分支的构造
后剪枝——先构造完整的决策树,再通过某些条件遍历树进行剪枝