机器学习--k-近邻(kNN)算法案例,--k-knn


一、改进约会网站的配对效果

       想要预测的目标变量:不喜欢的人、魅力一般的人、极具魅力的人

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

       约会数据信息存放在文本文件datingTestSet.txt中,每个样本数据占据一行,共有1000行。

 

实现步骤

1、将文本文件中的数据进行解析

###################################
#功能:将文本文件中的数据解析为矩阵形式
#输入变量:filename 文件名字符串
#输出变量:return_mat, class_label_vector 文件转换后的矩阵, 类标签向量
###################################


def file2matrix(filename):
    fr = open(filename, 'r')  # 只读方式打开文件
    array_of_lines = fr.readlines()  # readlines()来读取所有数据,这样可以尽快释放文件资源
    number_of_lines = len(array_of_lines)  # 得到文件行数
    return_mat = zeros((number_of_lines, 3))  # 创建返回矩阵

    class_label_vector = []
    index = 0

    label_dict = {'largeDoses': 3, 'smallDoses': 2, 'didntLike': 1}

    # readlines()读取整个文件并以行构成一个列表,每行作为for的一个循环
    for line in array_of_lines:

        #先去除字符串两边的空格,再以tab分隔符分切字符串
        list_form_line = line.strip().split('\t')

        return_mat[index, :] = list_form_line[0:3]  # 替代每行数据

        # 使用负下标选取list_form_line最后一列
        # 即把三种类型的人数添加到class_label_vector列表中
        class_label_vector.append(label_dict[list_form_line[-1]])

        index += 1
    return return_mat, class_label_vector

 

2、归一化特征值

在处理不同取值范围的特征值时,为了避免权重失衡,通常会对数值进行归一化处理,此函数可以自动将数字特征值转化为0到1的区间。

###################################
#功能:对数值进行归一化处理
#输入变量:data_set 样本数据
#输出变量:norm_data_set, ranges, min_vals 归一化后的样本,取值范围,最小值
###################################
def auto_norm(data_set):
    min_values = data_set.min(0)  # 参数0使得函数可以从列中选取最小值,而不是选取当前行的最小值
    max_values = data_set.max(0)

    ranges = max_values - min_values

    m = data_set.shape[0]  # 获得数组的行数
    diff_data_set = data_set - tile(min_values, (m, 1))
    norm_data_set = diff_data_set/tile(ranges, (m, 1))  # 对应数值进行相除

    return norm_data_set, ranges, min_values

 

3、利用约会网站数据测试分类器效果

机器学习算法一个很重要的工作就是评估算法的正确率,通常用已有数据的90%作为训练样本,其余的10%数据去测试分类器。需要注意的是,10%的数据应该是随机选择的。对于分类器来说,错误率是检测性能的指标。错误率是错误结果的次数除以测试数据的总数,完美分类器错误率为0,而错误率为1.0的分类器不会给出任何正确的分类结果。

 

###################################
#功能:测试分类器的效果
###################################
def dating_class_test():
    ho_ratio = 0.10  # 测试数据占的百分比

    dating_data_mat, dating_labels = file2matrix('datingTestSet.txt')
    norm_mat, ranges, min_values = auto_norm(dating_data_mat)

    m = norm_mat.shape[0]
    num_test_vectors = int(m*ho_ratio)  # 10%的数据作为测试

    error_count = 0.0
    for i in xrange(num_test_vectors):
        classifier_result = classify0(norm_mat[i, :], norm_mat[num_test_vectors:m, :],
                                      dating_labels[num_test_vectors:m], 3)
        print "the classifier came back with: %d, the real answer is: %d" % \
              (classifier_result, dating_labels[i])

        if classifier_result != dating_labels[i]:
            error_count += 1.0
    print "the total error rate is: %f" % (error_count/num_test_vectors)

 

4、从错误率来看,分类器的性能还不错,接下来将利用该分类器来预测喜欢程度

 

###################################
#功能:输入某人的信息,得出对对方喜欢程度的预测值
###################################
def classify_person():
    result_list = ['not at all', 'in small doses', 'in large doses']

    # 飞行常客里程数
    ff_miles = float(raw_input("frequent flier miles earned per year:"))
    # 玩视频游戏所耗时间百分比
    percent_tats = float(raw_input("percentage of time spent playing video games:"))
    # 每周消费的冰淇淋公升数
    ice_cream = float(raw_input("liters of ice cream consumed per week:"))

    dating_data_mat, dating_labels = file2matrix('datingTestSet.txt')
    norm_mat, ranges, min_values = auto_norm(dating_data_mat)

    in_arr = array([ff_miles, percent_tats, ice_cream])
    classifier_result = classify0((in_arr-min_values)/ranges, norm_mat, dating_labels, 3)

    print "you will probably like this person: ", result_list[classifier_result - 1]

 

二、手写识别系统

        将手写字符看成由0、1组成的32行32列的一个二进制图像文件,手写字符是数字0到9。由此可知,

        想要预测的目标变量:0到9的数字

        样本特征:无

        手写文本数据有两个子目录:目录trainingDigits中包含了大约2000个例子,每个例子的内容是0到9的数字图像,每个数字有大约200个样本;目录testDigits中包含了大约900个测试数据。使用trainingDigits中的数据训练分类器,使用testDigits中的数据测试分类器效果。

 

实现步骤:

1、将图像文件的数据转为向量,把32*32的二进制图像矩阵转为1*1024的向量,这样分类器就可以处理数字图像信息了。

 

###################################
#功能:将图像转换成向量,将一个32*32的二进制图像转换成1*1024的向量
#输入变量:filename 文件名字符串
#输出变量:return_vector 转换后的向量
###################################
def img2vector(filename):
    return_vector = zeros((1, 1024))
    fr = open(filename, 'r')  # 只读方式打开文件
    for i in xrange(32):
        line_str = fr.readline()  # readline()一次读取一行数据
        for j in xrange(32):
            return_vector[0, 32*i+j] = int(line_str[j])  # 32*32个数据写入一行内

    return return_vector

 

2、使用kNN算法识别手写数字

 

###################################
#功能:测试手写识别系统
###################################
def hand_writing_class_test():
    hw_labels = []
    training_file_list = listdir('trainingDigits')  # 将目录中的文件名(例如'0_0.txt')存储在列表中
    m = len(training_file_list)  # 计算文件数
    training_mat = zeros((m, 1024))

    for i in xrange(m):
        file_name_str = training_file_list[i]
        file_str = file_name_str.split('.')[0]  # 得到文件名如[0_12.txt],[0]是第一个数据0_12
        class_num_str = int(file_str.split('_')[0])  # 得到数组如[0_12]获得第一个数[0]
        hw_labels.append(class_num_str)  # 将获得的数字添加到标签数组中

        training_mat[i, :] = img2vector('trainingDigits/%s' % file_name_str)  # 数据格式转换

    test_file_list = listdir('testDigits')
    error_count = 0.0
    m_test = len(test_file_list)

    for i in xrange(m_test):
        file_name_str = test_file_list[i]
        file_str = file_name_str.split('.')[0]
        class_num_str = int(file_str.split('_')[0])

        vector_under_test = img2vector('testDigits/%s' % file_name_str)

        classifier_result = classify0(vector_under_test, training_mat, hw_labels, 3)
        print "the classifier came back with: %d, the real answer is: %d" % (classifier_result, class_num_str)

        if classifier_result != class_num_str:
            error_count += 1.0

    print "the total number of errors is: %d" % error_count
    print "the total error rate is: %f" % (error_count/float(m_test))

 

 

def main():

   dating_data_mat, dating_labels = file2matrix('datingTestSet.txt')
   print 'dating_data_mat=', dating_data_mat
   print 'dating_labels=', dating_labels

   norm_mat, ranges, min_values = auto_norm(dating_data_mat)
   print 'norm_mat=', norm_mat
   print 'ranges=', ranges
   print 'min_values=', min_values

   dating_class_test()

   classify_person()

 

   test_vector = img2vector('testDigits/0_13.txt')
   print 'test_vector=', test_vector[0, 0:31]
   print 'test_vector=', test_vector[0, 32:63]

   hand_writing_class_test()

 

if __name__ == '__main__':
    main()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关内容