• 新的数据集,新的挑战!
    • 更多数据,更好的算法,还有抛锚的巴士

    新的数据集,新的挑战!

    是时候使用新的数据集了——比马印第安人糖尿病数据集,由美国国家糖尿病、消化和肾脏疾病研究所提供。

    新的数据集,新的挑战 - 图1

    令人惊讶的是,超过30%的比马人患有糖尿病,而全美的糖尿病患者比例是8.3%,中国只有4.2%。

    数据集中的一条记录代表一名21岁以上的比马女性,她们分类两类:五年内查出患有糖尿病,以及没有得病。

    共选取了8个特征:

    1. 怀孕次数;
    2. 口服葡萄糖耐量实验两小时后的血浆葡萄糖浓度;
    3. 舒张压(mm Hg);
    4. 三头肌皮褶厚度(mm);
    5. 血清胰岛素(mu U/ml);
    6. 身体质量指数(BMI):体重(公斤)除以身高(米)的平方;
    7. 糖尿病家谱;
    8. 年龄(岁)。

    以下是示例数据,最后一列的0表示没有糖尿病,1表示患有糖尿病:

    新的数据集,新的挑战 - 图2

    比如说,第一条记录表示一名生过两次小孩的女性,她的血糖浓度是99,舒张压是52,等等。

    新的数据集,新的挑战 - 图3

    实践[1]

    本书提供了两份数据集:pimaSmall.zip和pima.zip。前者包含100条记录,后者包含393条记录,都已经等分成了10个文件(10个桶)。我用前面实现的近邻算法计算了pimaSmall数据集,得到的结果如下:

    新的数据集,新的挑战 - 图4

    提示:代码中的 heapq.nsmallest(n, list) 会返回n个最小的项。heapq 是Python内置的优先队列类库。

    你的任务是实现kNN算法。

    首先在类的init函数中添加参数k:

    1. def __init__(self, bucketPrefix, testBucketNumber, dataFormat, k):

    knn函数的签名应该是:

    1. def knn(self, itemVector):

    它会使用到self.k(记得在init函数中保存这个值),它的返回值是0或1。

    此外,在进行十折交叉验证(tenFold函数)时也要传入k参数。

    解答

    init函数的修改很简单:

    1. def __init__(self, bucketPrefix, testBucketNumber, dataFormat, k):
    2. self.k = k
    3. ...

    knn函数的实现是:

    1. def knn(self, itemVector):
    2. """使用kNN算法判断itemVector所属类别"""
    3. # 使用heapq.nsmallest来获得k个近邻
    4. neighbors = heapq.nsmallest(self.k,
    5. [(self.manhattan(itemVector, item[1]), item)
    6. for item in self.data])
    7. # 每个近邻都有投票权
    8. results = {}
    9. for neighbor in neighbors:
    10. theClass = neighbor[1][0]
    11. results.setdefault(theClass, 0)
    12. results[theClass] += 1
    13. resultList = sorted([(i[1], i[0]) for i in results.items()], reverse=True)
    14. # 获取得票最高的分类
    15. maxVotes = resultList[0][0]
    16. possibleAnswers = [i[1] for i in resultList if i[0] == maxVotes]
    17. # 若得票相等则随机选取一个
    18. answer = random.choice(possibleAnswers)
    19. return(answer)

    对tenFold函数的改动如下:

    1. def tenfold(bucketPrefix, dataFormat, k):
    2. results = {}
    3. for i in range(1, 11):
    4. c = Classifier(bucketPrefix, i, dataFormat, k)
    5. ...

    你可以从网站上下载这些代码,不过我的代码并不一定是最优的,仅供参考。

    实践[2]

    在分类效果上,究竟是数据量的多少比较重要(即使用pimaSmall和pima数据集的效果),还是更好的算法比较重要(k=1和k=3)?

    解答

    以下是比较结果:

    新的数据集,新的挑战 - 图5

    看来增加数据量要比使用更好的算法带来的效果好。

    新的数据集,新的挑战 - 图6

    实践[3]

    72.519%的准确率看起来不错,但还是用Kappa指数来检验一下吧:

    新的数据集,新的挑战 - 图7

    解答

    计算合计和比例:

    新的数据集,新的挑战 - 图8

    随机分类器的混淆矩阵:

    新的数据集,新的挑战 - 图9

    随机分类器的正确率:

    新的数据集,新的挑战 - 图10

    Kappa指标:

    新的数据集,新的挑战 - 图11

    效果一般

    更多数据,更好的算法,还有抛锚的巴士

    新的数据集,新的挑战 - 图12

    几年前我去参加一个墨西哥城的研讨会,比较特别的是会议的第二天是坐观光巴士旅游,观看黑脉金斑蝶等。这辆巴士比较破旧,中途抛锚了好几次,所以我们一群有着博士学位的人就站在路边一边谈笑,一边等着司机修理巴士。而事实证明这段经历是这次会议最大的收获。

    其间,我有幸与Eric Brill做了交流,他在词性分类方面有着很高的成就,他的算法比前人要优秀很多,从而使他成为自然语言处理界的名人。我和他谈论了分类器的效果问题,他说实验证明增加数据所带来的效果要比改进算法来得大。

    事实上,如果仍沿用老的词性分类算法,而仅仅增加训练集的数据量,效果很有可能比他现有的算法更好。当然,他不可能通过收集更多的数据来获得一个博士学位,但如果如果你的算法能够取得哪怕一点点改进,也足够了。

    新的数据集,新的挑战 - 图13

    当然,这并不是说你就不需要挑选出更好的算法了,我们之前也看到了好的算法所带来的效果也是惊人的。

    但是如果你只是想解决一个问题,而非发表一篇论文,那增加数据量会更经济一些。

    所以,在认同数据量多寡的重要影响后,我们仍将继续学习各种算法。

    人们使用kNN算法来做以下事情:

    • 在亚马逊上推荐商品
    • 评估用户的信用
    • 通过图像分析来分类路虎车型
    • 人像识别
    • 分析照片中人物的性别
    • 推荐网页
    • 推荐旅游套餐