呆板学习knnlearn2

打印 上一主题 下一主题

主题 930|帖子 930|积分 2790

  1. # 导入必要的库
  2. import matplotlib.lines as mlines
  3. import matplotlib.pyplot as plt
  4. import numpy as np
  5. from matplotlib.font_manager import FontProperties
  6. # 函数说明:打开并解析文件,对数据进行分类:1代表不喜欢,2代表魅力一般,3代表极具魅力
  7. def file2matrix(filename):
  8.     try:
  9.         # 以只读模式打开指定文件
  10.         with open(filename, 'r') as fr:
  11.             # 读取文件的所有行,存储为一个列表,列表中的每个元素是文件的一行
  12.             arrayOLines = fr.readlines()
  13.             # 计算文件的行数
  14.             numberOfLines = len(arrayOLines)
  15.             # 创建一个全零的NumPy矩阵,行数为文件的行数,列数为3,用于存储解析后的数据
  16.             returnMat = np.zeros((numberOfLines, 3))
  17.             # 初始化一个空列表,用于存储分类标签
  18.             classLabelVector = []
  19.             # 初始化行索引为0,用于遍历文件的每一行
  20.             index = 0
  21.             # 遍历文件的每一行
  22.             for line in arrayOLines:
  23.                 # 去除每行首尾的空白字符(如换行符、制表符、空格等)
  24.                 line = line.strip()
  25.                 # 使用制表符 '\t' 作为分隔符,将每行字符串分割成一个列表
  26.                 listFromLine = line.split('\t')
  27.                 # 将分割后列表的前三个元素赋值给 returnMat 矩阵的当前行,即存储特征数据
  28.                 returnMat[index, :] = listFromLine[0:3]
  29.                 # 根据分割后列表的最后一个元素进行分类
  30.                 if listFromLine[-1] == 'didntLike':
  31.                     # 如果最后一个元素是 'didntLike',则将标签 1 添加到分类标签列表中,表示不喜欢
  32.                     classLabelVector.append(1)
  33.                 elif listFromLine[-1] == 'smallDoses':
  34.                     # 如果最后一个元素是 'smallDoses',则将标签 2 添加到分类标签列表中,表示魅力一般
  35.                     classLabelVector.append(2)
  36.                 elif listFromLine[-1] == 'largeDoses':
  37.                     # 如果最后一个元素是 'largeDoses',则将标签 3 添加到分类标签列表中,表示极具魅力
  38.                     classLabelVector.append(3)
  39.                 # 行索引加1,处理下一行
  40.                 index += 1
  41.         # 返回特征矩阵和分类标签列表
  42.         return returnMat, classLabelVector
  43.     except FileNotFoundError:
  44.         # 如果文件未找到,打印错误信息
  45.         print(f"文件 {filename} 未找到,请检查文件路径。")
  46.         # 返回 None 表示读取失败
  47.         return None, None
  48.     except Exception as e:
  49.         # 如果发生其他异常,打印异常信息
  50.         print(f"读取文件时发生错误: {e}")
  51.         # 返回 None 表示读取失败
  52.         return None, None
  53. # 函数说明:可视化数据
  54. def showdatas(datingDataMat, datingLabels):
  55.     # 如果特征矩阵或分类标签列表为 None,说明文件读取失败,直接返回
  56.     if datingDataMat is None or datingLabels is None:
  57.         return
  58.     # 设置字体属性,使用宋体,字号为 14,用于显示中文
  59.     font = FontProperties(family='SimSun', size=14)
  60.     # 创建一个 2 行 2 列的子图布局,不共享 x 轴和 y 轴,画布大小为 13x8 英寸
  61.     fig, axs = plt.subplots(nrows=2, ncols=2, sharex=False, sharey=False, figsize=(13, 8))
  62.     # 获取分类标签的数量
  63.     numberOfLabels = len(datingLabels)
  64.     # 初始化一个空列表,用于存储每个数据点的颜色
  65.     LabelsColors = []
  66.     # 遍历分类标签列表
  67.     for i in datingLabels:
  68.         if i == 1:
  69.             # 如果标签为 1,将颜色 'black' 添加到颜色列表中,表示不喜欢的点用黑色表示
  70.             LabelsColors.append('black')
  71.         elif i == 2:
  72.             # 如果标签为 2,将颜色 'orange' 添加到颜色列表中,表示魅力一般的点用橙色表示
  73.             LabelsColors.append('orange')
  74.         elif i == 3:
  75.             # 如果标签为 3,将颜色 'red' 添加到颜色列表中,表示极具魅力的点用红色表示
  76.             LabelsColors.append('red')
  77.     # 定义一个内部函数,用于绘制散点图
  78.     def plot_scatter(ax, x_index, y_index, title, x_label, y_label):
  79.         # 在指定的子图上绘制散点图,x 轴数据为特征矩阵的第 x_index 列,y 轴数据为特征矩阵的第 y_index 列
  80.         # 每个点的颜色根据分类标签从 LabelsColors 列表中获取,点的大小为 15,透明度为 0.5
  81.         # ax 是一个 matplotlib 的 Axes 对象,代表一个子图。通过 ax.scatter 方法,可以在这个特定的子图上进行绘图操作。
  82.         # x=datingDataMat[:, x_index]
  83.         # datingDataMat 是一个 NumPy 数组,一般是从文件中读取并处理后得到的特征矩阵,每一行代表一个样本,每一列代表一个特征。
  84.         # datingDataMat[:, x_index] 运用了 NumPy 的切片操作,选取 datingDataMat 矩阵中所有行的第 x_index 列数据,这些数据将作为散点图中所有散点的横坐标。
  85.         # y=datingDataMat[:, y_index]
  86.         # 同理,datingDataMat[:, y_index] 选取 datingDataMat 矩阵中所有行的第 y_index 列数据,这些数据将作为散点图中所有散点的纵坐标。
  87.         # color=LabelsColors
  88.         # LabelsColors 是一个包含颜色信息的列表,其长度和 datingDataMat 的行数相同。
  89.         # 列表中的每个元素对应一个散点的颜色,也就是说,LabelsColors 中的第 i 个元素决定了 datingDataMat 中第 i 行样本所对应的散点的颜色。
  90.         # s=15
  91.         # s 参数用于设置散点的大小。这里将散点的大小设置为 15,单位通常是点(points)。
  92.         # alpha=.5
  93.         # alpha 参数用于设置散点的透明度。取值范围是 0 到 1,其中 0 表示完全透明,1 表示完全不透明。这里将散点的透明度设置为 0.5,意味着散点具有一定的半透明效果。
  94.         ax.scatter(x=datingDataMat[:, x_index], y=datingDataMat[:, y_index], color=LabelsColors, s=15, alpha=.5)
  95.         # 设置子图的标题,使用之前设置的字体属性
  96.         ax.set_title(title, fontproperties=font)
  97.         # 设置子图的 x 轴标签,使用之前设置的字体属性
  98.         ax.set_xlabel(x_label, fontproperties=font)
  99.         # 设置子图的 y 轴标签,使用之前设置的字体属性
  100.         ax.set_ylabel(y_label, fontproperties=font)
  101.         # 设置子图坐标轴刻度的字体大小为 7
  102.         ax.tick_params(axis='both', labelsize=7)
  103.         # 返回绘制好的子图
  104.         return ax
  105.     # 调用 plot_scatter 函数,绘制第一个子图,x 轴为每年获得的飞行常客里程数,y 轴为玩视频游戏所消耗时间占比
  106.     axs[0][0] = plot_scatter(axs[0][0], 0, 1, '每年获得的飞行常客里程数与玩视频游戏所消耗时间占比',
  107.                              '每年获得的飞行常客里程数', '玩视频游戏所消耗时间占')
  108.     # 调用 plot_scatter 函数,绘制第二个子图,x 轴为每年获得的飞行常客里程数,y 轴为每周消费的冰激淋公升数
  109.     axs[0][1] = plot_scatter(axs[0][1], 0, 2, '每年获得的飞行常客里程数与每周消费的冰激淋公升数',
  110.                              '每年获得的飞行常客里程数', '每周消费的冰激淋公升数')
  111.     # 调用 plot_scatter 函数,绘制第三个子图,x 轴为玩视频游戏所消耗时间占比,y 轴为每周消费的冰激淋公升数
  112.     axs[1][0] = plot_scatter(axs[1][0], 1, 2, '玩视频游戏所消耗时间占比与每周消费的冰激淋公升数',
  113.                              '玩视频游戏所消耗时间占比', '每周消费的冰激淋公升数')
  114.     # 创建一个 Line2D 对象,用于表示不喜欢的点的图例,颜色为黑色,标记为点,标记大小为 6
  115.     didntLike = mlines.Line2D([], [], color='black', marker='.',
  116.                               markersize=6, label='didntLike')
  117.     # 创建一个 Line2D 对象,用于表示魅力一般的点的图例,颜色为橙色,标记为点,标记大小为 6
  118.     smallDoses = mlines.Line2D([], [], color='orange', marker='.',
  119.                                markersize=6, label='smallDoses')
  120.     # 创建一个 Line2D 对象,用于表示极具魅力的点的图例,颜色为红色,标记为点,标记大小为 6
  121.     largeDoses = mlines.Line2D([], [], color='red', marker='.',
  122.                                markersize=6, label='largeDoses')
  123. # axs 是之前通过 plt.subplots 函数创建的子图数组。这里的 axs 是一个二维数组,因为使用 nrows=2, ncols=2 创建了一个 2x2 的子图布局。
  124. # [axs[0][0], axs[0][1], axs[1][0]] 是一个包含三个子图对象的列表。axs[0][0] 代表第一行第一列的子图,axs[0][1] 代表第一行第二列的子图,
  125. # axs[1][0] 代表第二行第一列的子图。
  126. # for ax in ... 这个循环会依次取出列表中的子图对象,并将其赋值给变量 ax。在每次循环中,ax 都会代表当前正在处理的子图。
  127.     # 遍历前三个子图
  128.     for ax in [axs[0][0], axs[0][1], axs[1][0]]:
  129.         # 在每个子图上添加图例,包含不喜欢、魅力一般和极具魅力三种情况的标记
  130.         # 2. ax.legend(handles=[didntLike, smallDoses, largeDoses])
  131.         # ax.legend() 是 matplotlib 中用于在子图上添加图例的方法。
  132.         # handles 参数接收一个包含 Line2D 对象的列表。didntLike、smallDoses 和 largeDoses 是之前创建的 Line2D 对象,
  133.         # 分别代表不同类别的数据点(不喜欢、魅力一般、极具魅力)。
  134.         # 通过传入这个列表,legend 方法会在当前子图上添加一个图例,图例中会显示这三种情况的标记和对应的标签。
  135.         ax.legend(handles=[didntLike, smallDoses, largeDoses])
  136.     # 隐藏第四个子图,因为只需要绘制三个子图
  137.     axs[1][1].axis('off')
  138.     # 自动调整子图的布局,使它们之间的间距和大小更加合理
  139.     plt.tight_layout()
  140.     # 显示绘制好的图形
  141.     plt.show()
  142. if __name__ == '__main__':
  143.     # 定义要打开的文件名
  144.     filename = "datingTestSet.txt"
  145.     # 调用 file2matrix 函数,打开并处理文件,获取特征矩阵和分类标签列表
  146.     datingDataMat, datingLabels = file2matrix(filename)
  147.     # 调用 showdatas 函数,将特征矩阵和分类标签列表作为参数传入,进行数据可视化
  148.     showdatas(datingDataMat, datingLabels)
  149.    
复制代码

代码是通过以下几个步骤来确定每个点的颜色的,下面为你详细解释:
1. 数据分类阶段

在 file2matrix 函数中,代码会读取文件里的数据,并且按照最后一列的文本描述对数据举行分类,把分类标签存到 classLabelVector 列表中。
  1. def file2matrix(filename):
  2.     # ... 前面的代码省略 ...
  3.     for line in arrayOLines:
  4.         line = line.strip()
  5.         listFromLine = line.split('\t')
  6.         returnMat[index, :] = listFromLine[0:3]
  7.         if listFromLine[-1] == 'didntLike':
  8.             classLabelVector.append(1)
  9.         elif listFromLine[-1] == 'smallDoses':
  10.             classLabelVector.append(2)
  11.         elif listFromLine[-1] == 'largeDoses':
  12.             classLabelVector.append(3)
  13.         index += 1
  14.     return returnMat, classLabelVector
复制代码
这里,'didntLike' 对应标签 1,'smallDoses' 对应标签 2,'largeDoses' 对应标签 3。
2. 颜色映射阶段

在 showdatas 函数中,代码会依据 datingLabels(也就是 classLabelVector)里的分类标签,为每个数据点分配对应的颜色,把这些颜色存到 LabelsColors 列表中。
  1. def showdatas(datingDataMat, datingLabels):
  2.     # ... 前面的代码省略 ...
  3.     LabelsColors = []
  4.     for i in datingLabels:
  5.         if i == 1:
  6.             LabelsColors.append('black')
  7.         elif i == 2:
  8.             LabelsColors.append('orange')
  9.         elif i == 3:
  10.             LabelsColors.append('red')
复制代码


  • 要是分类标签是 1,就把颜色 'black' 添加到 LabelsColors 列表里。
  • 要是分类标签是 2,就把颜色 'orange' 添加到 LabelsColors 列表里。
  • 要是分类标签是 3,就把颜色 'red' 添加到 LabelsColors 列表里。
3. 绘制散点图阶段

在 showdatas 函数里界说的 plot_scatter 函数中,代码会用 LabelsColors 列表为每个数据点设置颜色。
  1. def plot_scatter(ax, x_index, y_index, title, x_label, y_label):
  2.     ax.scatter(x=datingDataMat[:, x_index], y=datingDataMat[:, y_index], color=LabelsColors, s=15, alpha=.5)
  3.     # ... 后面的代码省略 ...
复制代码
ax.scatter 方法的 color 参数接收 LabelsColors 列表,这个列表里的每个元素都和 datingDataMat 中的一行数据对应。也就是说,LabelsColors 列表里的第 i 个元素决定了 datingDataMat 中第 i 行数据对应的点的颜色。
总结

代码先对数据举行分类,为每个数据点赋予一个分类标签,接着依据这些标签把颜色映射到每个数据点上,最后在绘制散点图时,按照映射好的颜色来体现每个点。这样一来,就能确保每个点依据其分类标签体现为对应的颜色(黑色、橙色大概红色)。
  1. import numpy as np
  2. """
  3. Parameters:
  4.     filename - 文件名
  5. Returns:
  6.     returnMat - 特征矩阵
  7.     classLabelVector - 分类Label向量
  8. """
  9. # 函数说明:打开并解析文件,对数据进行分类:1代表不喜欢,2代表魅力一般,3代表极具魅力
  10. def file2matrix(filename):
  11.     #打开文件
  12.     fr = open(filename)
  13.     #读取文件所有内容
  14.     arrayOLines = fr.readlines()
  15.     #得到文件行数
  16.     numberOfLines = len(arrayOLines)
  17.     #返回的NumPy矩阵,解析完成的数据:numberOfLines行,3列
  18.     returnMat = np.zeros((numberOfLines,3))
  19.     #返回的分类标签向量
  20.     classLabelVector = []
  21.     #行的索引值
  22.     index = 0
  23.     for line in arrayOLines:
  24.         #s.strip(rm),当rm空时,默认删除空白符(包括'\n','\r','\t',' ')
  25.         line = line.strip()
  26.         #使用s.split(str="",num=string,cout(str))将字符串根据'\t'分隔符进行切片。
  27.         listFromLine = line.split('\t')
  28.         #将数据前三列提取出来,存放到returnMat的NumPy矩阵中,也就是特征矩阵
  29.         returnMat[index,:] = listFromLine[0:3]
  30.         #根据文本中标记的喜欢的程度进行分类,1代表不喜欢,2代表魅力一般,3代表极具魅力
  31.         if listFromLine[-1] == 'didntLike':
  32.             classLabelVector.append(1)
  33.         elif listFromLine[-1] == 'smallDoses':
  34.             classLabelVector.append(2)
  35.         elif listFromLine[-1] == 'largeDoses':
  36.             classLabelVector.append(3)
  37.         index += 1
  38.     return returnMat, classLabelVector
  39. """
  40. Parameters:
  41.     dataSet - 特征矩阵
  42. Returns:
  43.     normDataSet - 归一化后的特征矩阵
  44.     ranges - 数据范围
  45.     minVals - 数据最小值
  46. """
  47. # 函数说明:对数据进行归一化
  48. def autoNorm(dataSet):
  49.     #获得数据的最小值
  50.     minVals = dataSet.min(0)
  51.     maxVals = dataSet.max(0)
  52.     #最大值和最小值的范围
  53.     ranges = maxVals - minVals
  54.     #shape(dataSet)返回dataSet的矩阵行列数
  55.     normDataSet = np.zeros(np.shape(dataSet))
  56.     #返回dataSet的行数
  57.     m = dataSet.shape[0]
  58.     #原始值减去最小值
  59.     normDataSet = dataSet - np.tile(minVals, (m, 1))
  60.     #除以最大和最小值的差,得到归一化数据
  61.     normDataSet = normDataSet / np.tile(ranges, (m, 1))
  62.     #返回归一化数据结果,数据范围,最小值
  63.     return normDataSet, ranges, minVals
  64. if __name__ == '__main__':
  65.     #打开的文件名
  66.     filename = "datingTestSet.txt"
  67.     #打开并处理数据
  68.     datingDataMat, datingLabels = file2matrix(filename)
  69.     normDataSet, ranges, minVals = autoNorm(datingDataMat)
  70.     print(normDataSet)
  71.     print(ranges)
  72.     print(minVals)
复制代码
  1. [[0.44832535 0.39805139 0.56233353]
  2. [0.15873259 0.34195467 0.98724416]
  3. [0.28542943 0.06892523 0.47449629]
  4. ...
  5. [0.29115949 0.50910294 0.51079493]
  6. [0.52711097 0.43665451 0.4290048 ]
  7. [0.47940793 0.3768091  0.78571804]]
  8. [9.1273000e+04 2.0919349e+01 1.6943610e+00]
  9. [0.       0.       0.001156]
复制代码
  1. [/code] 233353]
  2. [0.15873259 0.34195467 0.98724416]
  3. [0.28542943 0.06892523 0.47449629]
  4. [0.29115949 0.50910294 0.51079493]
  5. [0.52711097 0.43665451 0.4290048 ]
  6. [0.47940793 0.3768091 0.78571804]]
  7. [9.1273000e+04 2.0919349e+01 1.6943610e+00]
  8. [0. 0. 0.001156]
  9. [code]
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

温锦文欧普厨电及净水器总代理

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表