人工智能必备数学知识学习笔记5:向量的高级话题
- 规范化和单位向量
单位向量:表示向量长度(向量模的最小组成单元)的单位
代码实现:
1.在 _global.py中编写代码:
2.在Vector.py编写代码
1 #向量类 2 #__values() 与 _values()区别更多体现在继承上,如果是在类的内部使用时官方建议使用_values()发方法 3 from ._global import EPSILON 4 import math 5 6 7 class Vector: 8 9 def __init__(self,lst): 10 self._values = list(lst)#将数组赋值给向量类中(注:使用list方法将列表lst复制一份保证他的不被外界调用时修改) 11 12 #零向量类方法:参数1:为当前的类(cls) 参数2:维度(dim) 返回dim维的零向量 13 @classmethod 14 def zero(cls,dim): 15 return cls([0] * dim) 16 17 #返回向量的模(向量长度): 18 def norm(self): 19 return math.sqrt(sum(e**2 for e in self))#sqrt()方法为开平方根,sum()求和方法,e**2 e的平方 20 21 #返回向量的单位向量 22 def normalize(self): 23 if self.norm() < EPSILON: #此处判断一个精度范围(该精度范围调用内部自定义全局变量文件 _global.py)(由于浮点数计算机含有误差所以无法使用 == 0 的操作) 24 raise ZeroDivisionError("Normalize error! norm is zero.") #考虑零向量时报此处异常即可 25 #方案一:return Vector(1/self.norm() * [e for e in self])#循环遍历向量中的每个元素分别除以该向量的模即为单位向量 26 #方案二:return 1/self.norm() * Vector(self._values)#当前向量除以模即为单位向量 27 return Vector(self._values) / self.norm() 28 29 #向量加法,返回结果向量 30 def __add__(self, another): 31 # assert判断传入的向量维度是否相等 32 assert len(self) == len(another),\ 33 "Error in adding. Length of vectors must be same." 34 return Vector([a+b for a,b in zip(self,another)])#使用zip()方法将两个向量取出来 35 36 # 向量减法 37 def __sub__(self, another): 38 assert len(self) == len(another), \ 39 "Error in adding. Length of vectors must be same." 40 return Vector([a - b for a, b in zip(self, another)]) 41 42 # 向量乘法(数乘数组),返回数量乘法的结果向量:self * k 43 def __mul__(self, k): 44 return Vector([k * e for e in self]) 45 46 # 向量乘法(数组乘数),返回数量乘法的结果向量:k * self 47 def __rmul__(k, self): 48 return k * self #此处直接调用的是上方的乘法函数 49 50 # 向量除法:返回数量除法的结果向量 self / k 51 def __truediv__(self, k): 52 return (1 / k) * self 53 54 #返回向量取正的结果向量 55 def __pos__(self): 56 return 1 * self 57 58 # 返回向量取负的结果向量 59 def __neg__(self): 60 return -1 * self 61 62 #返回向量迭代器(当有迭代器时,zip()方法中就不用再次传入两个向量数组,直接传入向量对象即可<zip(self._values,another._values)>) 63 def __iter__(self): 64 return self._values.__iter__() 65 66 #取向量的index个元素 67 def __getitem__(self, index): 68 return self._values[index] 69 70 #返回向量的长度(有多少个元素) 71 def __len__(self): 72 return len(self._values) 73 74 # 向量展示(系统调用) 75 def __repr__(self): 76 return "Vector({})".format(self._values) 77 78 # 向量展示(用户调用) 79 def __str__(self): 80 return "({})".format(", ".join(str(e) for e in self._values))#通过遍历 self.__values 将e转成字符串通过逗号加空格来链接放入大括号中 81 82 # u = Vector([5,2]) 83 # print(u)
3.在main_vector.py展示中编写:
1 from playLA.Vector import Vector 2 3 if __name__ == "__main__": 4 5 vec = Vector([5,2]) 6 print(vec) 7 print(len(vec))#打印向量的维度 8 print("vec[0] = {}, vec[1] = {}".format(vec[0],vec[1])) 9 10 #向量加法 11 vec2 = Vector([3,1]) 12 print("{} + {} = {}".format(vec,vec2,vec+vec2)) 13 #向量减法 14 print("{} - {} = {}".format(vec, vec2, vec - vec2)) 15 #向量乘法(向量乘以数) 16 print("{} * {} = {}".format(vec,3,vec * 3)) 17 # 向量乘法(数乘以向量) 18 print("{} * {} = {}".format(3, vec, 3 * vec)) 19 # 向量取正 20 print("+{} = {}".format(vec, +vec)) 21 # 向量取负 22 print("-{} = {}".format(vec, -vec)) 23 24 #零向量 25 zero2 = Vector.zero(2) 26 print(zero2) 27 #向量加上零向量 28 print("{} + {} = {}".format(vec, zero2, vec + zero2)) 29 30 #向量的模 31 print("norm({}) = {}".format(vec,vec.norm())) 32 print("norm({}) = {}".format(vec2,vec2.norm())) 33 print("norm({}) = {}".format(zero2, zero2.norm())) 34 35 #单位向量 36 print("normalize({}) is {}".format(vec,vec.normalize())) 37 print(vec.normalize().norm())#单位向量的模(长度)基本为数字1 38 print("normalize({}) is {}".format(vec2, vec2.normalize())) 39 print(vec2.normalize().norm()) # 单位向量的模(长度)基本为数字1(计算机中会有误差0.9999...) 40 #print(zero2.normalize()) 41 #捕捉异常 ZeroDivisionError 42 try: 43 zero2.normalize() 44 except ZeroDivisionError: 45 print("Cannot normalize zero vector {}".format(zero2))
4.运行main_vector.py结果为:
1 /Users/liuxiaoming/PycharmProjects/LinearAlgebra/venv/bin/python /Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/pydevconsole.py --mode=client --port=57619 2 import sys; print('Python %s on %s' % (sys.version, sys.platform)) 3 sys.path.extend(['/Users/liuxiaoming/PycharmProjects/LinearAlgebra']) 4 PyDev console: starting. 5 Python 3.8.2 (v3.8.2:7b3ab5921f, Feb 24 2020, 17:52:18) 6 [Clang 6.0 (clang-600.0.57)] on darwin 7 runfile('/Users/liuxiaoming/PycharmProjects/LinearAlgebra/main_vector.py', wdir='/Users/liuxiaoming/PycharmProjects/LinearAlgebra') 8 (5, 2) 9 2 10 vec[0] = 5, vec[1] = 2 11 (5, 2) + (3, 1) = (8, 3) 12 (5, 2) - (3, 1) = (2, 1) 13 (5, 2) * 3 = (15, 6) 14 3 * (5, 2) = (15, 6) 15 +(5, 2) = (5, 2) 16 -(5, 2) = (-5, -2) 17 (0, 0) 18 (5, 2) + (0, 0) = (5, 2) 19 norm((5, 2)) = 5.385164807134504 20 norm((3, 1)) = 3.1622776601683795 21 norm((0, 0)) = 0.0 22 normalize((5, 2)) is (0.9284766908852593, 0.3713906763541037) 23 1.0 24 normalize((3, 1)) is (0.9486832980505138, 0.31622776601683794) 25 0.9999999999999999 26 Cannot normalize zero vector (0, 0)
- 向量的点乘
余弦定理:
多维两个向量点乘:
向量点乘的直观理解:将向量V投影到u向量上长度:将两个向量的指向相同后再相乘
代码实现:
1.在Vector.py编写代码
1 #向量类 2 #__values() 与 _values()区别更多体现在继承上,如果是在类的内部使用时官方建议使用_values()发方法 3 from ._global import EPSILON 4 import math 5 6 7 class Vector: 8 9 def __init__(self,lst): 10 self._values = list(lst)#将数组赋值给向量类中(注:使用list方法将列表lst复制一份保证他的不被外界调用时修改) 11 12 #零向量类方法:参数1:为当前的类(cls) 参数2:维度(dim) 返回dim维的零向量 13 @classmethod 14 def zero(cls,dim): 15 return cls([0] * dim) 16 17 #返回向量的模(向量长度): 18 def norm(self): 19 return math.sqrt(sum(e**2 for e in self))#sqrt()方法为开平方根,sum()求和方法,e**2 e的平方 20 21 #返回向量的单位向量 22 def normalize(self): 23 if self.norm() < EPSILON: #此处判断一个精度范围(该精度范围调用内部自定义全局变量文件 _global.py)(由于浮点数计算机含有误差所以无法使用 == 0 的操作) 24 raise ZeroDivisionError("Normalize error! norm is zero.") #考虑零向量时报此处异常即可 25 #方案一:return Vector(1/self.norm() * [e for e in self])#循环遍历向量中的每个元素分别除以该向量的模即为单位向量 26 #方案二:return 1/self.norm() * Vector(self._values)#当前向量除以模即为单位向量 27 return Vector(self._values) / self.norm() 28 29 #向量加法,返回结果向量 30 def __add__(self, another): 31 # assert判断传入的向量维度是否相等 32 assert len(self) == len(another),\ 33 "Error in adding. Length of vectors must be same." 34 return Vector([a+b for a,b in zip(self,another)])#使用zip()方法将两个向量取出来 35 36 # 向量减法 37 def __sub__(self, another): 38 #判断维度相等 39 assert len(self) == len(another), \ 40 "Error in adding. Length of vectors must be same." 41 return Vector([a - b for a, b in zip(self, another)]) 42 43 #向量点乘(向量之间相乘):返回结果标量 44 def dot(self,another): 45 #判断维度相等 46 assert len(self) == len(another), \ 47 "Error in dot product. Length of vectors must be same." 48 return sum(a * b for a,b in zip(self,another))# 方法zip()将两组向量配成对应位置的数据对 49 50 # 向量数量乘法(数乘数组),返回数量乘法的结果向量:self * k 51 def __mul__(self, k): 52 return Vector([k * e for e in self]) 53 54 # 向量数量乘法(数组乘数),返回数量乘法的结果向量:k * self 55 def __rmul__(k, self): 56 return k * self #此处直接调用的是上方的乘法函数 57 58 # 向量除法:返回数量除法的结果向量 self / k 59 def __truediv__(self, k): 60 return (1 / k) * self 61 62 #返回向量取正的结果向量 63 def __pos__(self): 64 return 1 * self 65 66 # 返回向量取负的结果向量 67 def __neg__(self): 68 return -1 * self 69 70 #返回向量迭代器(当有迭代器时,zip()方法中就不用再次传入两个向量数组,直接传入向量对象即可<zip(self._values,another._values)>) 71 def __iter__(self): 72 return self._values.__iter__() 73 74 #取向量的index个元素 75 def __getitem__(self, index): 76 return self._values[index] 77 78 #返回向量的长度(有多少个元素) 79 def __len__(self): 80 return len(self._values) 81 82 # 向量展示(系统调用) 83 def __repr__(self): 84 return "Vector({})".format(self._values) 85 86 # 向量展示(用户调用) 87 def __str__(self): 88 return "({})".format(", ".join(str(e) for e in self._values))#通过遍历 self.__values 将e转成字符串通过逗号加空格来链接放入大括号中 89 90 # u = Vector([5,2]) 91 # print(u)
2.在main_vector.py展示中编写:
1 from playLA.Vector import Vector 2 3 if __name__ == "__main__": 4 5 vec = Vector([5,2]) 6 print(vec) 7 print(len(vec))#打印向量的维度 8 print("vec[0] = {}, vec[1] = {}".format(vec[0],vec[1])) 9 10 #向量加法 11 vec2 = Vector([3,1]) 12 print("{} + {} = {}".format(vec,vec2,vec+vec2)) 13 #向量减法 14 print("{} - {} = {}".format(vec, vec2, vec - vec2)) 15 #向量乘法(向量乘以数) 16 print("{} * {} = {}".format(vec,3,vec * 3)) 17 # 向量乘法(数乘以向量) 18 print("{} * {} = {}".format(3, vec, 3 * vec)) 19 # 向量取正 20 print("+{} = {}".format(vec, +vec)) 21 # 向量取负 22 print("-{} = {}".format(vec, -vec)) 23 24 #零向量 25 zero2 = Vector.zero(2) 26 print(zero2) 27 #向量加上零向量 28 print("{} + {} = {}".format(vec, zero2, vec + zero2)) 29 30 #向量的模 31 print("norm({}) = {}".format(vec,vec.norm())) 32 print("norm({}) = {}".format(vec2,vec2.norm())) 33 print("norm({}) = {}".format(zero2, zero2.norm())) 34 35 #单位向量 36 print("normalize({}) is {}".format(vec,vec.normalize())) 37 print(vec.normalize().norm())#单位向量的模(长度)基本为数字1 38 print("normalize({}) is {}".format(vec2, vec2.normalize())) 39 print(vec2.normalize().norm()) # 单位向量的模(长度)基本为数字1(计算机中会有误差0.9999...) 40 #print(zero2.normalize()) 41 #捕捉异常 ZeroDivisionError 42 try: 43 zero2.normalize() 44 except ZeroDivisionError: 45 print("Cannot normalize zero vector {}".format(zero2)) 46 47 #向量点乘(向量乘以向量) 48 print(vec.dot(vec2))
3.运行main_vector.py结果为:
1 /Users/liuxiaoming/PycharmProjects/LinearAlgebra/venv/bin/python /Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/pydevconsole.py --mode=client --port=58247 2 import sys; print('Python %s on %s' % (sys.version, sys.platform)) 3 sys.path.extend(['/Users/liuxiaoming/PycharmProjects/LinearAlgebra']) 4 PyDev console: starting. 5 Python 3.8.2 (v3.8.2:7b3ab5921f, Feb 24 2020, 17:52:18) 6 [Clang 6.0 (clang-600.0.57)] on darwin 7 >>> runfile('/Users/liuxiaoming/PycharmProjects/LinearAlgebra/main_vector.py', wdir='/Users/liuxiaoming/PycharmProjects/LinearAlgebra') 8 (5, 2) 9 2 10 vec[0] = 5, vec[1] = 2 11 (5, 2) + (3, 1) = (8, 3) 12 (5, 2) - (3, 1) = (2, 1) 13 (5, 2) * 3 = (15, 6) 14 3 * (5, 2) = (15, 6) 15 +(5, 2) = (5, 2) 16 -(5, 2) = (-5, -2) 17 (0, 0) 18 (5, 2) + (0, 0) = (5, 2) 19 norm((5, 2)) = 5.385164807134504 20 norm((3, 1)) = 3.1622776601683795 21 norm((0, 0)) = 0.0 22 normalize((5, 2)) is (0.9284766908852593, 0.3713906763541037) 23 1.0 24 normalize((3, 1)) is (0.9486832980505138, 0.31622776601683794) 25 0.9999999999999999 26 Cannot normalize zero vector (0, 0) 27 17
- 向量点乘的意义
引申:推荐系统算法基础
几何应用:投影点的方向可以表示为单位向量,所以投影点坐标为单位向量乘以一个投影点的距离
- numpy的使用(numpy是线性代数库)
1.创建main_numpy_vector.py文件
2. 文件 main_numpy_vector.py 编写代码
1 import numpy as np 2 if __name__ == "__main__": 3 #查看 数学库 numpy 的版本号 4 print(np.__version__) 5 6 lst = [1,2,3] 7 lst[0] = "Linear Algebra"#线性代数的英文 8 print(lst) 9 10 #使用numpy中的向量 11 vec = np.array([1,2,3]) 12 print(vec) 13 # vec[0] = 666 14 # print(vec) 15 16 #np.array的创建 (参数1:维度数 参数2:每个维度的元素值) 17 print(np.zeros(5)) 18 print(np.ones(5)) 19 print(np.full(5,666)) 20 21 #np.array的基本属性 22 print(vec) 23 print("size=",vec.size)#向量有多少元素(维度数) 24 print("size=",len(vec)) 25 print(vec[0])#第一个元素值 26 print(vec[-1])#最后一个元素值 27 print(vec[0:2])#切片语法,参数1:从哪开始,参数2:步长 28 print(type(vec[0:2]))#该切片的向量的类 29 30 #np.array的基本运算 31 vec2 = np.array([4,5,6]) 32 print("{} + {} = {}".format(vec,vec2,vec + vec2))#向量加法 33 print("{} - {} = {}".format(vec, vec2, vec - vec2)) # 向量减法 34 print("{} * {} = {}".format(2, vec, 2 * vec)) # 向量乘法(数乘以向量) 35 print("{} * {} = {}".format(vec, 2, vec * 2)) # 向量乘法(向量乘以数) 36 print("{} * {} = {}".format(vec, vec2, vec * vec2)) # 向量乘法(向量与向量对应元素相乘-但无数学意义) 37 print("{}.dot({}) = {}".format(vec, vec2, vec.dot(vec2))) # 向量点乘(向量与向量点乘) 38 39 #np.linalg 为numpy中线性代数模块("Linear Algebra"的缩写) 40 print(np.linalg.norm(vec))# 向量的模(向量的长度) 41 print(vec / np.linalg.norm(vec))# 单位向量 42 print(np.linalg.norm(vec / np.linalg.norm(vec)))# 单位向量的模 43 44 #numpy涉及零向量的单位向量时会报错,需要自行处理 45 # zero3 = np.zeros(3) 46 # zero3 / np.linalg.norm(zero3)
3. 运行文件 main_numpy_vector.py 结果为:
1 /Users/liuxiaoming/PycharmProjects/LinearAlgebra/venv/bin/python /Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/pydevconsole.py --mode=client --port=58662 2 import sys; print('Python %s on %s' % (sys.version, sys.platform)) 3 sys.path.extend(['/Users/liuxiaoming/PycharmProjects/LinearAlgebra']) 4 PyDev console: starting. 5 Python 3.8.2 (v3.8.2:7b3ab5921f, Feb 24 2020, 17:52:18) 6 [Clang 6.0 (clang-600.0.57)] on darwin 7 runfile('/Users/liuxiaoming/PycharmProjects/LinearAlgebra/playLA/main_numpy_vector.py', wdir='/Users/liuxiaoming/PycharmProjects/LinearAlgebra/playLA') 8 1.19.1 9 ['Linear Algebra', 2, 3] 10 [1 2 3] 11 [0. 0. 0. 0. 0.] 12 [1. 1. 1. 1. 1.] 13 [666 666 666 666 666] 14 [1 2 3] 15 size= 3 16 size= 3 17 1 18 3 19 [1 2] 20 <class 'numpy.ndarray'> 21 [1 2 3] + [4 5 6] = [5 7 9] 22 [1 2 3] - [4 5 6] = [-3 -3 -3] 23 2 * [1 2 3] = [2 4 6] 24 [1 2 3] * 2 = [2 4 6] 25 [1 2 3] * [4 5 6] = [ 4 10 18] 26 [1 2 3].dot([4 5 6]) = 32 27 3.7416573867739413 28 [0.26726124 0.53452248 0.80178373] 29 1.0