【机器学习】

machine learning notes

tags: notes machine learning

github的上传,见链接CSDN|github上传知乎|github仓库更新git提交代码流程

本学习笔记源代码见github链接github|源代码项目仓库

1.kNN分类算法

kNN算法,是在已知各训练数据元类型下基于欧式距离计算,计算待预测点与什么类距离最近。

1.1 numpy补充

学习链接numpy学习网站1
numpy学习网站2

对shape

有例子
核心:0为行轴,shape[0]为有多少行
一维:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
x1 = np.array([1,2])
y1 = np.array([[1],[2]])

print("x1:\n",x1)
print("y1:\n",y1)

print("x1.shape:\n",x1.shape)
print("y1.shape:\n",y1.shape)
>>>
x1:
[1 2]
y1:
[[1]
[2]]
x1.shape:
(2,)
y1.shape:
(2, 1)

二维:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
y2 = np.array([[1,2,3],[4,5,6]])
print("y2:\n",y2)
print("y2.shape:\n",y2.shape)
print("y2.shape[0]:\n",y2.shape[0])
print("y2.shape[1]:\n",y2.shape[1])
>>>
y2:
[[1 2 3]
[4 5 6]]
y2.shape:
(2, 3)
y2.shape[0]:
2
y2.shape[1]:
3

三维:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 y3  = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[0,1,2]],[[3,4,5],[6,7,8]]])
print("y3:\n",y3)
print("y3.shape:\n",y3.shape)
print("y3.shape[0]:\n",y3.shape[0])
print("y3.shape[1]:\n",y3.shape[1])
print("y3.shape[2]:\n",y3.shape[2])
>>>
y3:
[[[1 2 3]
[4 5 6]]

[[7 8 9]
[0 1 2]]

[[3 4 5]
[6 7 8]]]
y3.shape:
(3, 2, 3)
y3.shape[0]:
3
y3.shape[1]:
2
y3.shape[2]:
3

其中,x.shape[0]代表包含二维数组的个数,x.shape[1]表示二维数组的行数,x.shape[2]表示二维数组的列数

对于乘法

有学习链接numpy乘法学习
所谓数组星乘,就是数组的对应元素相乘,这也是初学NumPy的同学最早接触到的数组乘法。即使两个数组的shape不一样,只要满足特定条件,同样可以用星号相乘,且满足交换律。

对于一维数组,NumPy的点乘就是向量点乘,其结果是一个标量。对于多维数组,则需要满足一定条件才能实现点乘,且其结果不再是标量,而是一个多维数组。比如,NumPy的矩阵相乘,就是二维数组的点乘,参与点乘的第一个数组的列数必须等于第二个数组的行数。

在数学上,二维平面的向量叉乘,其结果是以两个向量为边的菱形的面积,三维空间的向量叉乘,其结果是仍然是一个向量,且垂直于相乘的两个向量,也就是参与相乘的两个向量决定的平面的法向量。nunpy.cross()函数可以实现向量(一维数组)叉乘,也可以实现二维或三维数组的叉乘

1
2
3
4
5
6
7
8
9
10
 >>> a = np.array([2,0])
>>> b = np.array([2,2])
>>> np.cross(a,b) # 平面向量叉乘,其结果是以两个向量为边的菱形的面积
array(4)
>>> a = np.array([1,0,0])
>>> b = np.array([0,1,0])
>>> np.cross(a,b) # x轴叉乘y轴,得到z轴
array([0, 0, 1])
>>> np.cross(b,a) # 叉乘交换顺序,得到反向的法向量
array([ 0, 0, -1])

这里的外乘,类似于星乘,并不是通用的概念,也是我自己编造的一个说法,来源于numpy.outer()函数。从字面看,outer()函数更像是求外积,但从实际效果看,更像是笛卡尔直积,因此我这里用了“外乘”而不是“外积”。那么,outer()函数究竟能作什么呢?
数组A外乘数组B,返回一个二维数组,这个二维数组的第i行是数组A的第i个元素星乘数组B。

**乘方,如a**2=a^2

排序argsort,其返回的是各个排序的index,如b[0]上是最小元素的index,有示例

1
2
3
4
5
6
7
8
import numpy as np
a=np.array([456,11,63])
a
b=np.argsort(a)
b
output:
array([456, 11, 63])
array([1, 2, 0], dtype=int64)

列表排序函数sorted sorted(iterable[, cmp[, key[, reverse]]])
cmp是比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0
有示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
>>>a = [5,7,6,3,4,1,2]
>>> b = sorted(a) # 保留原列表
>>> a
[5, 7, 6, 3, 4, 1, 2]
>>> b
[1, 2, 3, 4, 5, 6, 7]
>>> L=[('b',2),('a',1),('c',3),('d',4)]
>>> sorted(L, cmp=lambda x,y:cmp(x[1],y[1])) # 利⽤cmp函数
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> sorted(L, key=lambda x:x[1]) # 利⽤key
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
>>> sorted(students, key=lambda s: s[2]) # 按年龄排序
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
>>> sorted(students, key=lambda s: s[2], reverse=True) # 按降序
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
>>> sorted(student_tuples, key = itemgetter(2)) # 根据年龄排序
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
>>> sorted(student_tuples, key = itemgetter(1, 2)) # 根据成绩和年龄排序
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
>>> sorted(student_tuples, key = itemgetter(1, 2), reverse=True) # 反转排序结果
[('jane', 'B', 12), ('dave', 'B', 10), ('john', 'A', 15)]

对于operator中的itemgetter函数,是返回一个函数;sorted使用的时候,相当于对于每个“行”都用itemgetter获取了他的关键元(可以是一个,也可以是多个组成的元组)

1
2
3
4
5
6
7
a = [1,2,3] 
>>> b=operator.itemgetter(1) //定义函数b,获取对象的第1个域的值
>>> b(a)
2
>>> b=operator.itemgetter(1,0) //定义函数b,获取对象的第1个域和第0个的值
>>> b(a)
(2, 1)

1.2 matplotlib补充

matplotlib绘图基础教程见知乎|Matplotlib绘图
matplotlib的绘图函数库pyplot有示例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import matplotlib.pyplot as plt

# 添加3行3列子图中的第1个子图,并将其为当前子图
plt.subplot(331)
plt.bar(range(1,4),range(1,4))
# 添加3行3列子图中的第5个子图,并将其为当前子图
plt.subplot(335)
plt.pie([4,5,6])
# 添加3行3列子图中的第9个子图,并将其为当前子图
# 返回值为Axes对象
ax=plt.subplot(339)
# 使用Axes的方法(面向对象模式)绘制点
ax.plot([1],'o')

plt.show()

散点图绘制scatter函数,相关链接CSDN|scatter matplotlib.pyplot.scatter(x, y, s=None, c=None, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, verts=None, edgecolors=None, *, data=None, **kwargs)
基本用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import matplotlib.pyplot as plt
import random

# 0.准备数据
x = range(60)
y_jiangsu = [random.uniform(15, 25) for i in x]
y_beijing = [random.uniform(5,18) for i in x]

# 1.创建画布
plt.figure(figsize=(20, 8), dpi=100)

# 2.绘制图像
plt.scatter(x,y_jiangsu, s=100, c='deeppink', marker='o', label = "江苏")
plt.scatter(x,y_beijing, s=100, c='darkblue', marker='+', label = "北京")

# 2.1 刻度显示
plt.xticks(x[::5], x_ticks_label[::5])
plt.yticks(y_ticks[::5])

# 2.2 添加网格显示
plt.grid(True, linestyle="--", alpha=0.5)

# 2.3 添加描述信息
plt.xlabel("时间", fontsize=15)
plt.ylabel("温度", fontsize=15)
plt.title("中午11点--12点某城市温度变化图", fontsize=20)

# 2.4 图像保存
plt.savefig("./test.png")

# 2.5 添加图例
plt.legend(loc="best")

# 3.图像显示
plt.show()

1.3 tile

tile(inX,(m,n))对inX,横向重复n次,竖向重复m次

2.决策树算法

本次采用ID3算法来划分数据集,具体算法可见链接wiki|ID3_algorithm

注意:决策树算法是已知各数据元是什么类型,只是给出类型划分的依据。对于每个数据元,可以有很多特征(一个数据元是一行,是一条记录),但每次划分数据集的时候,只会使用一个参考特征。

2.1 信息增益

划分数据的依据就是信息增益,即将无序的数据变有序——使用信息论度量信息。
定义1:符号$x_i$的信息$l(x_i)=-log_2p(x_i)$,其中$p(x_i)$为选择该分类的概率
定义2为所有类别选择的信息期望值,$H=-\sum_{i=1}^n{p\left( x_i \right) \log _2p\left( x_i \right)}$

对于数据集,其$p(x_i)$为probOfKey = float(numOfTheKey)/(len(dataSet))
对于每种划分方式,其信息熵为以每个值为划分值划出的数目来算概率,再乘上该划分值划出的dataSet的信息熵,即:

1
2
3
4
5
6
for value in uniqueVals:
# 对于一个特征的每个数值,都要以他为划分值算一下划分结果与信息熵
subDataSet = splitDataSet(dataSet,i,value)
# 算熵(概率就是被筛出来的概率)
prob = len(subDataSet)/float(len(dataSet))
newEntopy += prob* calcShannonEnt(subDataSet)

补充,字典.keys()可以遍历字典的所有key值,if currentLabel not in labelCounts.keys():

当熵越大,说明混合的数据越多。

划分数据集

对每个特征划分数据集的结果计算一次信息熵,比较得按照哪个特征划分数据集是最好的划分方式。

注意! 在选择用哪个特征时,每个特征对应的信息增益等于原始熵-该特征对应信息熵。而对于该特征对应的信息熵,每个概率就是在每个值下筛出去的概率,每个值对应的信息就是在该值下筛出来的数据集的信息熵

对于数组的扩充,要将一个列表的各个元素扩充进来,则用extend,而对于append,是列表扩充为被扩充列表的一个元素。如:

1
2
3
4
5
6
7
8
9
a = [1,2,'3']
a.append(b)
b = [4,5,'6']
c = [1,2,'3']
c.extend(b)
>>> a
[1, 2, '3', [4, 5, '6']]
>>> c
[1, 2, '3', 4, 5, '6']

补充:set,集合函数,是python的内置函数,接收一个list为参数,创建一个无序不重复元素集,可进行关系测试,删除重复数据,还可以计算交集、差集、并集等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
list1=[1,2,3,4]
s=set(list1)
print(s)
s.add(4)
s.add(5)
s.remove('zhang')
print(s)
#交集,使用&操作符
s3=s1&s2
#并集,使用|操作符
s4=s1|s2
输出:
set([1, 2, 3, 4])
set([1, 2, 3, 4, 5])

2.2 递归构建决策树

递归结束(即构建出叶子结点)的条件是在该结点下的分支所有实例都有相同的分类;若数据集已经处理了所有属性,但还是有分支类别标签不唯一,则使用多数表决的方法来确定该叶子结点的分类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def creatTree(dataSet,labels):
"""递归创建树

Args:
dataSet (_type_matrix): 数据集
labels (_type_list): 所有特征的标签
return:创建出的树,myTree[a][b],a是对应的结点,b是节点下对应的分支的值
"""
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 = chooseFeatureToSplit(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[a][b],a是对应的结点,b是节点下对应的分支的值
myTree[bestFeatLabel][value] = creatTree(splitDataSet(dataSet,bestFeat,value),subLabels)
# 这里就解释了,为什么上面特征数的统计用dataSet[0];每次向下一级递归函数传的是splitDataSet,
return myTree

递归思路

如果不是出口,creatTree返回的是一个树(即一个value是字典的字典),这个树挂载在上一级结点上,即挂在myTree[feat][value];因此,要访问叶子结点,就是myTree[feat1][feat1Value1][feat2][feat2Value2][feat3][feat3Value3]...[featNValueN]

如果是出口,creatTree返回的是一个列表,也就是使得上一节点依value下来的分支为一个列表,程序结束,回溯。

2.3 绘制树形图

matplotlib中的ax1是来自于子图,是通过在画布fig添加子图ax1=fig.add_subplot,进而在子图上绘制曲线。

补充:Anaconda和Pycharm的安装与配置

参考教学链接cnblogs|Anaconda和Pycharm的安装和配置


【机器学习】
http://mhjiang0408.github.io/2023/02/06/machine-learning-notes/
作者
mhjiang0408
发布于
2023年2月6日
许可协议