机器学习 Day 10 | KNN算法的简单实现(3)

机器学习第十天 KNN算法的简单实现(3)

七夕来啦啦啦,用KNN实现一个优化约会网站的配对效果的案例

用markdown写起来效果好多了

数据集下载地址
https://www.xiehaoo.com/media/record/pinke/2018/08/datingTestSet2.txt

项目概述

海伦使用约会网站寻找约会对象。经过一段时间之后,她发现曾交往过三种类型的人:
1、不喜欢的人
2、魅力一般的人
3、极具魅力的人

她希望:

1、工作日与魅力一般的人约会
2、周末与极具魅力的人约会
3、不喜欢的人则直接排除掉

现在她收集到了一些约会网站未曾记录的数据信息,这更有助于匹配对象的归类。

开发流程

收集数据:提供文本文件
准备数据:使用python解析文本文件
分析数据:使用Matplotlib画二维散点图
训练算法:此步骤不适用于 KNN算法
测试算法:使用海伦提供的部分数据作为测试样本。
使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否为自己喜欢的类型。

收集数据:提供文本文件

海伦把这些约会对象的数据存放在文本文件中,总共有 1000 行。海伦约会的对象主要包含以下 3 种特征:

  • 每年获得的飞行常客里程数
  • 玩视频游戏所耗时间百分比
  • 每周消费的冰淇淋公升数

文本文件数据格式如下:

40920   8.326976    0.953952    3
14488   7.153469    1.673904    2
26052   1.441871    0.805124    1
75136   13.147394   0.428964    1
38344   1.669788    0.134296    1

准备数据:使用python解析文本文件

将文本记录转换为Numpy的解析程序

def file2matrix(filename):
   """
   Desc:
       导入训练数据
   parameters:
       filename: 数据文件路径
   return: 
       数据矩阵 returnMat 和对应的类别 classLabelVector
   """
   fr = open(filename)
   # 获得文件中的数据行的行数
   numberOfLines = len(fr.readlines())
   # 生成对应的空矩阵
   # 例如:zeros(2,3)就是生成一个 2*3的矩阵,各个位置上全是 0 
   returnMat = zeros((numberOfLines, 3))  # prepare matrix to return
   classLabelVector = []  # prepare labels return
   fr = open(filename)
   index = 0
   for line in fr.readlines():
       # str.strip([chars]) --返回已移除字符串头尾指定字符所生成的新字符串
       line = line.strip()
       # 以 '\t' 切割字符串
       listFromLine = line.split('\t')
       # 每列的属性数据
       returnMat[index, :] = listFromLine[0:3]
       # 每列的类别数据,就是 label 标签数据
       classLabelVector.append(int(listFromLine[-1]))
       index += 1
   # 返回数据矩阵returnMat和对应的类别classLabelVector
   return returnMat, classLabelVector

分析数据:使用 Matplotlib 画二维散点图

import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:, 0], datingDataMat[:, 1], 15.0*array(datingLabels), 15.0*array(datingLabels))
plt.show()

下图中采用矩阵的第一和第二列属性得到很好的展示效果,清晰地标识了三个不同的样本分类区域,具有不同爱好的人其类别区域也不同。

《机器学习 Day 10 | KNN算法的简单实现(3)》

也就是常用的欧式距离

序号玩视频游戏所耗时间百分比每年获得的飞行常客里程数每周消费的冰淇淋公升数样本分类
10.84000.51
212134 0000.93
3020 0001.12
46732 0000.12

样本3和样本4的距离: 《机器学习 Day 10 | KNN算法的简单实现(3)》

归一化特征值,消除特征之间量级不同导致的影响

归一化定义: 我是这样认为的,归一化就是要把你需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内。首先归一化是为了后面数据处理的方便,其次是保正程序运行时收敛加快。 方法有如下:

1.线性函数转换,表达式如下:

y=(x-MinValue)/(MaxValue-MinValue)

说明:x、y分别为转换前、后的值,MaxValue、MinValue分别为样本的最大值和最小值。

2.对数函数转换,表达式如下:

y=log10(x)

说明:以10为底的对数函数转换。

3.反余切函数转换,表达式如下:

y=arctan(x)*2/PI

4.式(1)将输入值换算为[-1,1]区间的值,在输出层用式(2)换算回初始值,其中和分别表示训练样本集中负荷的最大值和最小值。

在统计学中,归一化的具体作用是归纳统一样本的统计分布性。归一化在0-1之间是统计的概率分布,归一化在-1–+1之间是统计的坐标分布。

def autoNorm(dataSet):
    """
    Desc:
        归一化特征值,消除特征之间量级不同导致的影响
    parameter:
        dataSet: 数据集
    return:
        归一化后的数据集 normDataSet. ranges和minVals即最小值与范围,并没有用到

    归一化公式:
        Y = (X-Xmin)/(Xmax-Xmin)
        其中的 min 和 max 分别是数据集中的最小特征值和最大特征值。该函数可以自动将数字特征值转化为0到1的区间。
    """
    # 计算每种属性的最大值、最小值、范围
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    # 极差
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0]
    # 生成与最小值之差组成的矩阵
    normDataSet = dataSet - tile(minVals, (m, 1))
    # 将最小值之差除以范围组成矩阵
    normDataSet = normDataSet / tile(ranges, (m, 1))  # element wise divide
    return normDataSet, ranges, minVals

训练算法:此步骤不适用于 k-近邻算法

因为测试数据每一次都要与全量的训练数据进行比较,所以这个过程是没有必要的。

KNN算法在第8天以及逐步解析过了,本案例类似,点击查看机器学习 Day 8 | K-NN算法的简单实现(2)

测试算法:使用海伦提供的部分数据作为测试样本。如果预测分类与实际类别不同,则标记为一个错误。

kNN 分类器针对约会网站的测试代码

def datingClassTest():
    """
    Desc:
        对约会网站的测试方法
    parameters:
        none
    return:
        错误数
    """
    # 设置测试数据的的一个比例(训练数据集比例=1-hoRatio)
    hoRatio = 0.1  # 测试范围,一部分测试一部分作为样本
    # 从文件中加载数据
    datingDataMat, datingLabels = file2matrix('input/2.KNN/datingTestSet2.txt')  # load data setfrom file
    # 归一化数据
    normMat, ranges, minVals = autoNorm(datingDataMat)
    # m 表示数据的行数,即矩阵的第一维
    m = normMat.shape[0]
    # 设置测试的样本数量, numTestVecs:m表示训练样本的数量
    numTestVecs = int(m * hoRatio)
    print 'numTestVecs=', numTestVecs
    errorCount = 0.0
    for i in range(numTestVecs):
        # 对数据测试
        classifierResult = classify0(normMat[i, :], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m], 3)
        print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i])
        if (classifierResult != datingLabels[i]): errorCount += 1.0
    print "the total error rate is: %f" % (errorCount / float(numTestVecs))
    print errorCount

使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否为自己喜欢的类型

约会网站预测函数

def classifyPerson():
    resultList = ['not at all', 'in small doses', 'in large doses']
    percentTats = float(raw_input("percentage of time spent playing video games ?"))
    ffMiles = float(raw_input("frequent filer miles earned per year?"))
    iceCream = float(raw_input("liters of ice cream consumed per year?"))
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    normMat, ranges, minVals = autoNorm(datingDataMat)
    inArr = array([ffMiles, percentTats, iceCream])
    classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels, 3)
    print "You will probably like this person: ", resultList[classifierResult - 1]

实际运行如下

>>> classifyPerson()

percentage of time spent playing video games ?1
frequent filer miles earned per year?1
liters of ice cream consumed per year?1

[670 955 410 450 717 184 965 790 457 893 928 517 411 430 541 782 630 120


Ran 0 tests in 0.000s

OK
 889 721 803 405 733 556 428 858  81 270 857 269 657 621 195 384 177 719 778 150  87  20 688 742 942 560 451 747 469 835  49 278 321 253 964 671
 956 616 111  67 529 309 980 940 929 313 510 283 986 353 202 925 836  28
 378  70 757 255 132  18 968 987 779 901 874 212 399 447 552 171 750 115
 224 735  98  12 801 527 379 403  37 743  61 576 632 417 982 612 247 256
 656 157 995 306 308 293 896 774 845 763 643 804 421 144 361 711 387 169
 644 862  72 181 335 625 640 685 533 131 985 740 105 935 236   2 550 945
 791 330 369 185 615 974 548  65 161 431 730 299 479 989 249 201 495 600
 532 658 266 345 230 816 496 771  48 512 694 526 191 710 218 564 904 318
 960 856 118 281 860 991 427 199 436  64 820 938 744 737 182 488 637 765
 907 848 473 841 346 963  93 134  47 811 678 651 371  54 687 300 953 455
  22 978 638 470 618 930 505 983 149 572 675 574 661 265 994  26 530 867
 903 853 524 200 501 536 662  62 503 665 305 244 357  56 514 333 689 275
  86 555 540 452 739 466 151 847 205 231 755  63 613 788 490 842 642 850
 696 623 628  73  45 812  53 499  21 697 396 110  91 458 285 764 259 189
  32 891 362  34 780 578 762 723 140 456 449 352 328 966 459 605  50 949
 707 535 338 840 992 547 208 301  29  24 731 583 777 604 950 295 913  96
 180 543 734 876 187 609 972 598 706 634 142 234 163 304 196 878 103 280
 194 446 141 808 229 988 453 404 504 923 673 210 865 544 593 571 407 154
 445 626 772   6 101 786 468 584 377 190 439  40 315 125 268 401 137 864
 467 894 738 349 879 516 102 319 381 880   1 136  79 838  31 712 787 112
 260 611 830 167 222 341 969 702 145  74 156 424 979  66 179 441 127 307
 373 648 414 292 745 515  41 148 245 692 197 507 408 500 311 641 720 814
  60 997 437 363 668 767 954 433  27 296 267 365 877 287 130 655 320 239
 852 406 939 168 117 870 471 238 175 926 553 291 888 704 415 915 539 192
  59   0 614 884 727  10 931 761 825 203 243 432 759 124 206 708 751 809
 568  19 186 993 682 834 705  99 337 807 126 924 728 394 551 793 589 843
 581  55 768 531 800 122 766 585 883 981 871 946 143 741 587 580 484 165
 601 520 732 486 660 826 193 570 967 680 409 897 162 679 534 700 984 109
 176 393 478 810 322 677 334 492 286 219 254 831 999 324 674 918  68 577
 339 257 921  84 900 385 795 666 919 948 932  13 558 652 823 155 619 113
 781 631 775 288 882 922 736 875 794 383  23 489 916 895 659 366 348  83
 390 213 715  46 248 139 215 518 789 799 594 898 153 502 866 133 282 359
 650 290 119  78 701 952 538 475 805 160 690 262 340  97 413 709  71 358
 289  57 402 188 263  30  82 477   4 418 909  42 329 559 241 686 590 575
 158 691 422 797 769 351 620 627 272 725 998 277  15 316 513 886 443 633
 104 756 519 802 724 395 785 472 629 554 849 695 649 753  39 442 961  38
 839 147 310 579 298 264  43 183 209 588 990 146 934  95 885 902 327 416
 368 683 107 854 653 303 152 326  75  25 624 426 703 608 549 595 370 461
 376 235 204 591 462 914 460 566   9 412 217 250 420 868 821 521 603 121
 347 829 367 890 123 859 464 172 226 312 819 343 562  52 128 832 817 663
 545 542  16 474 698 487 975 364 174  85 672 178 639 485 242 448 899 622
 173 302 233 569 332 752 284 386 784 511 586 493 933 796 917 602 646  77
 454 350 973   7 271 582 958 135 716 927 693 699 822 425 977 354 237 881
 523 498 170 279 506 749 971 645  44 214 207 824 198 106 423 873  80 509
 100 344 522 970  89 654 760 391 606 323  69 869   8  36 389 669 937 746
 317 681 482 827  90 228 419 491 770 116 537 776 465 684 773 647 872 138
 374  11 855 714 223 372 676 325 959  35 429 211 494  33 481 941 996 957
 480 216 908 276 798 910 920 388  94 815 497 596 392 400 912 851 220 463
   5 951 331 273 227 476  88 718 355 617 114 844 567 846 754 911 164 221
 906 382 861 375 129 713 546 563 667 792 274 936 440 758 232 565 726 435
  58 258 748 635 252 607 356 783 297 483 525 597  51 159 336 166 573 828
 664 599 261 438 944 636 444 225 108 557 892 398 528 342 561 294 943 976
 380 905   3 806  76 813  17 246 610 729 240 314 508 251 592 863 833 397
 887 947  14  92 434 962 818 722 837 360]
{2: 3}
You will probably like this person:  in small doses

    原文作者:raphah
    原文地址: https://www.jianshu.com/p/a985611e303b
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞