#AI

前端与机器学习

前端与机器学习,很多时候不会有交集。但是当一个前端要去开发一个机器学习平台的UI时,交集就产生了。对一个前端来说,这是一个挑战,同时也是一个机遇。

从最开始接触到机器学习平台,面对各种组件、算法不知所措时,然后就疯狂地去看博客了解如何入门机器学习。一般博客会推荐你先学习线性代数、高数、概率论,然后再开始开免费的机器学习视频,推荐的入门书籍。你会发现这是一个门槛很高技术领域。如果从线性代数、高数、概率论学习完,再来了解机器学习,估计得耗费非常大的精力。

随着几个月的学习,发现有些机器学习的算法只需要简单的数学知识,就能开始入门了。从这些地方作为切入点,显得再好不过。

kNN算法

kNN,英文全名 为k-NearestNeighbor,中文叫k-近邻算法。它的工作原理是:存在一个样本数据集合(训练样本集),并且样本集中每个数据都存在标签;输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行对比,然后提取出样本集中特征最相似数据的分类标签。一般来说,只选取前k个数据,这就是k-邻近算法的由来。

假设有这样一组数据:

data = [
  [1, 1.1],
  [1, 1],
  [0, 0],
  [0, 0.1]
]
// data中每个数据对应的标签
lables = ['A', 'A', 'B', 'B']

当我输入数据 [0.2, 0.1]的时候,kNN算法就会判断这个点与哪个点最相近,进而得出输入数据属于哪个标签。
那这里涉及到了什么数学知识点呢?这就要提及欧式公式,计算两个向量点xA和xB之间的距离:

d = √((xA0-xB0)^2+(xA1-xB1)^2) 

例如,点(0,0)和(1,2)之间的距离计算为:

√((1-0)^2+(2-0)^2) // =>√5

当遇到三个或三个以上特征的时候,该公式也适用。

kNN是一个非常简单的机器学习算法,我们用python实现一下。

import numpy
def classify0(inX, dataSet, labels, k):
    # 获取训练样本的大小
    dataSetSize = dataSet.shape[0]
    # 用样本数据构建和训练数据集一样的数组,再减去训练数据集
    diffMat = numpy.tile(inX, (dataSetSize, 1)) - dataSet
    # 下面是应用欧式公式,先平方,再求和,最后开方
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances  = sqDistances**0.5
    # 下面是从欧式公式计算的结果中选取k个最相似的标签
    sortedDistIndicies = distances.argsort()
    classCount={}
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]

kNN是一个非常简单的机器学习算法,对于入门机器学习再合适不过,只需要了解欧式公式即可。然后通过这里还可以补补向量的概念。

那它在实际应用中,可以应用在相亲网站的条件匹配上,同时也可以识别简单的手写数字等等。反正可以统一输出为数据,然后标签化的数据,都可以应用上它。

decisionTree算法

decisionTree,决策树算法。决策树算法,我们举邮件分类的例子来说明最好不过了。假如我们有一堆邮件,那如何将他们自动分类呢?假如邮件中包含”王者荣耀”的关键字自动分类为”无聊时需要阅读的邮件”;如果没有包含,进一步判断邮件中是否包含”工作”的关键字,如果有,自动分类为”需要及时处理的邮件”,否则分类为”无聊时需要阅读的邮件”。以此类推。

决策树算法里面涉及到的数学概念是”熵”。熵定义为信息的期望值。如果待分类的事务可能分类在多个分类中,则符号Xi的信息定义为:

# P(Xi)为选择该分类的概率
l(Xi)=-log2P(Xi)

为了计算熵,我们需要计算所有类别所有可能值包含的信息期望值,公式如下:

H=- SUM1-n (P(Xi) * log2P(Xi))

应用这个公式,我们用python来实现计算熵的。

def caclShannonEnt (dataSet):
    numEntries = len(dataSet)
    # 计算类别
    labelCounts = {}
    for featVec in dataSet:
      currentLabel = featVec[-1]
      if currentLabel not in labelCounts.keys():
        labelCounts[currentLabel] = 0
      labelCounts[currentLabel] += 1
    # 计算熵
    shannonEnt = 0.0
    for key in labelCounts:
      prob = float(labelCounts[key])/numEntries
      shannonEnt -= prob * log(prob, 2)
    return shannonEnt

然后对于给定的一个数据集(训练数据集,最后一个列为标签),就可以根据特征划分数据,度量划分数据集的熵,以便判断当前是否正确划分了数据集。

  def splitDataSet(dataSet, axis, value):
    retDataSet = []
    for featVec in dataSet:
      if featVec[axis] == value:
        reducedFeatVec = featVec[:axis]
        reducedFeatVec.extend(featVec[axis+1:])
        retDataSet.append(reducedFeatVec)
    return retDataSet

  def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0]) - 1
    baseEntropy = caclShannonEnt(dataSet)
    bestInfoGain = 0.0
    bestFeature = -1
    for i in range(numFeatures):
      featList = [example[i] for example in dataSet]
      uniqueVals = set(featList)
      newEntropy = 0.0
      for value in uniqueVals:
        subDataSet = splitDataSet(dataSet, i, value)
        prob = len(subDataSet)/float(len(dataSet))
        newEntropy += prob * caclShannonEnt(subDataSet)
      infoGain = baseEntropy - newEntropy
      if (infoGain > bestInfoGain):
        bestInfoGain = infoGain
        bestFeature = i
    return bestFeature

  # 多数表决 ----------------------------------------------------------
  def majorityCnt(classList):
    classCount = {}
    for vote in classList:
      if vote not in classCount.keys():
        classCount[vote] = 0
      classCount[vote] += 1
    sortedClassCount = sorted(classCount.iteritems(), key = operator.itemgetter(1), reverse = True)
    return sortedClassCount[0][0]

  # 创建树 ---
  def createTree(dataSet, labels):
    classList = [example[-1] for example in dataSet]
    if classList.count(classList[0]) == len(classList):
      return classList[0]
    if len(dataSet[0]) == 1:
      return majorityCnt(classList)
    bestFeat = chooseBestFeatureToSplit(dataSet)
    bestFeatLabel = labels[bestFeat]
    myTree = {bestFeatLabel:{}}
    del(labels[bestFeat])
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)
    for value in uniqueVals:
      subLabels = labels[:]
      myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
    return myTree

以上,就是决策树构建的代码。对于决策树,比较难以理解的是熵的概念。在了解了熵的基础上,决策树的算法逻辑也就比较简单地就写出来了。

总结

从这些简单的算法去入门机器学习,每个阶段让自己有一些产出,既能不断地学习,也能不断激励自己。然后不断补充自己的遗漏的数学知识,再去深入了解更多的机器学习算法。这样一个渐进的过程,对于了解机器学习这样高门槛的技术领域,也不妨是一条可行的道路。

当然上面使用到了python,对于前端来说,还要学习一下python的基础语法。不过python来说,花一个星期左右的时间去看看文档,基本上也就入门了。

#AI