在上节课中,你看到了numpy的一些基础知识。在这节课中,我将展示numpy赢博体育的一系列扩展示例。其中一些示例打算作为程序运行,而其他示例将采用Jupyter笔记本的形式。
可以用numpy数组类型表示的一种东西是向量。我们今天的第一个赢博体育包括对向量集合的操作。
向量空间的一组基是n个相互垂直的向量的集合。向量v在一组基{x1, x2,…,xn}下的坐标是一列数{c1, c2,…,cn},满足
V = c1 x1 + c2 x2 +⋯+ cn xn
在下一个例子中,我们要构造一个基,然后用这个基来计算目标向量的坐标。
这个例子来自计算机图形学。在计算机图形赢博体育程序中,我们通常使用两种不同的坐标系。世界坐标系使用位于原点的标准基底。基由三个标准坐标向量组成
在计算机图形学中,我们还使用第二种坐标系统,称为眼坐标。这代表了观察者所使用的坐标系统,他坐在空间中的某个位置观察世界中的物体。
眼睛坐标系统通常以观察者的一些信息的形式指定。
下面是计算眼睛坐标框架的三个坐标向量所需的数学步骤的总结。
look = look - peye
T = up - (up·z) z
X = y × z
这里的符号|| v ||代表向量v的范数。一旦我们构造了构成眼睛坐标系的向量,我们可以通过以下数学步骤将世界坐标中的任意点p表示为眼睛坐标:
V = p - peye
解出c的A c = v
下面是完成赢博体育这些步骤的Python程序。在大多数情况下,上面的数学可以直接转化为代码。
导入numpy作为np #作为计算输入数据的点和向量# p_eye = np.array([2,2,4]) #观看者的位置p_look = np.array([-1,0,0]) #他们正在看的点= np.array([0,1,0]) #他们的向上方向pt = np.array([-2,1,1]) #场景中点的位置#计算组成眼睛坐标框架的三个向量。v_look = p_look - p_eye z = -v_look/np.linalg.norm(v_look) t = up - np.dot(up,z)*z y = t/np.linalg.norm(t) x = np.cross(y,z) #计算pt相对于这个新坐标系的坐标。A = np.转置(np.array([x,y,z])) print(A) c = np.linalg.solve(A,pt-p_eye) print(c)
代码中的一个语句需要一些额外的解释。在上面的数学公式中,我们有一个步骤,我们将新坐标系的基向量聚集在一起,形成一个矩阵。
如果我们把它转换成代码
A = np.array([x,y,z])
结果将不正确,因为numpy将把每个向量x, y和z解释为矩阵a中的行。解决这个问题的方法是对矩阵进行转置,使矩阵的行变成列。
A = np.转置(np.array([x,y,z]))
给定两个向量u和v,我们可以通过下面的算法计算出v在u方向上的部分我们首先通过将u除以它自身的长度来标准化u
然后计算点积u·v v中不与u方向一致的部分是
W = v - (u·v) u
W就保证垂直于u。
这一基本步骤构成了一种称为Gram-Schmidt算法的算法的基础。在这个算法中,我们从一个向量集合开始
V1 v2, vk
在ℝn。然后求出一个新的向量集
U1 u2…uk
使得u向量的长度都是1并且彼此垂直。u向量都是通过v向量的适当线性组合来构造的。
下面是该算法的前几个步骤。
第一个u向量是第一个v向量的归一化版本。
第二个u向量是通过首先计算v2中不在u1方向上的部分来计算的。
W2 = v2 - (v2·u1) u1
然后对这个向量进行标准化。
同样,下面是计算u3的过程:
W3 = v3 - (v3·u1) u1 - (v3·u2) u2
这是一个包含一组向量的文本文件。编写一个Python程序,从文件中读取六个向量,并使用上面概述的算法从它们构造一个由六个相互垂直的向量组成的集合。您应该使用numpy向量操作来执行算法中的每一步。
就像我们在绘图课上看到的,numpy能做的一个很好的技巧就是向量函数计算。在这种技术中,我们构造一个普通的函数,然后将numpy数组作为参数传递给该函数。该函数将自动返回一个新数组,其条目是该函数计算的原始数组的条目。当与聚合函数结合使用时,这种技术可以在完全没有循环的情况下进行复杂的计算。
下面是一个使用向量函数求值和聚合函数的示例。
在微积分1的最后,我们介绍了函数f(x)的定积分。
这个量可以在几何上定义为面积:函数f(x)和x轴在x值a≤x≤b范围内的面积。正如你在微积分1中看到的,你可以使用几何技术来估计这个面积。最简单的几何技巧是将从a到b的区间划分为N + 1个等距点xi = a + h i,其中步长h等于(b-a)/N。
这个点的网格将区间[a,b]划分为子区间[xi, xi+1],对于i = 0到n,我们可以在每个子区间上放置一个矩形,该矩形近似于子区间[xi, xi+1]上f(x)下面的面积。得到一个近似矩形的一种方法是给区间[xi, xi+1]上的矩形一个高度f(xi)。下图说明了这种设置。
把赢博体育这些近似矩形的面积加起来,我们就能得到我们想要的面积的粗略近似。
由于矩形不能很好地近似曲线下的面积,我们需要一种更好的方法。一个明显的改进是用梯形代替矩形。在每个子区间[xi, xi+1]上,我们放置一个梯形,其左高由f(xi)给出,右高由f(xi+1)给出。下面的图片说明了梯形比矩形在匹配曲线下的面积方面做得更好。
一个这样的梯形的面积是h (f(xi) + f(xi+1))/2。如果我们把曲线下赢博体育梯形的面积加起来,我们就得到了积分的梯形法则估计:
下面的Python程序为函数计算这个和
在a = 0到b = 2的范围内。曲线下的面积是半径为2的四分之一圆,所以我们提前知道正确的面积是(π 22)/4 = π。这将使我们看到梯形规则估计的实际答案有多接近。
这是我们将在这个例子中使用的函数def (x):返回np.sqrt(4.0 - x*x) #通过使用步长为(b-a)/N的梯形#计算f(x)从a到b的积分#的近似值def梯形area (a,b,N): h = (b-a)/N;x = np.arange (a + h、b、h)返回h * (f (x) .sum ()) + h * (a) / 2 + h * f (b) / 2打印(“N错误”);for j in range(3,20,2): estimate = trapapezoidarea (0.0,2.0,2**j) error = math.fabs(math. fabs)π-估计)打印(“{:> 7 d} {: g}”.format (2 * * j、错误))
下面是这个程序生成的输出:
N错误8 0.0517735 32 0.00649023 128 0.000811861 512 0.000101501 2048 1.26882e-05 8192 1.58604e-06 32768 1.98256e-07 131072 2.4782e-08 524288 3.09775e-09
该方法不仅产生了很好的估计,而且使用numpy向量函数计算还具有使代码非常快的附加副作用。使用更传统的Python代码技术编写的相同代码会明显变慢。
对于我们最后一个愚蠢的例子,我将重新审视机器学习钞票的问题。在钞票的例子中,我们从k近邻方法中得到了一个奇怪的结果,即该算法能够得到赢博体育的测试样本。这在机器学习赢博体育中是不寻常的,所以这个案例需要进一步的调查。
我们已经看到numpy和pyplot可以很好地互补。在这个例子中,我将利用这个方便的链接。我想用pyplot将数据集中的点可视化。希望可视化能解释为什么k近邻算法这么好。
将我们的数据可视化的一个困难是,我们的数据点生活在一个四维空间。数据集中的每个点是一个由四个数字组成的列表。Pyplot只包含用于在二维或三维中绘制点的工具,因此为了绘制数据的图,我们必须减少数据集中涉及的维数。一种相当粗糙的方法是简单地忽略每个数据点中的第四个数字,并在三维空间中绘制数据点的图。这是相当容易做到的,我将把它作为一个简单的练习,让您在看完这个例子之后尝试。
用四维数据集制作三维图的一种更有效、更复杂的方法是赢博体育标准的机器学习降维算法。我们将在这个例子中使用的算法是主成分分析,或PCA算法。该算法通过为数据点所在的四维空间构建一个替代基来工作。这个备选基中的轴被选择沿数据集的最大可变性方向对齐。第一个轴是数据集具有最高可变性的方向,连续的轴被选择为垂直于已经选择的轴的最大可变性方向。在此方法中选择的最终轴是具有最小可变性的方向:因为这是四个轴中最不有趣的,当我们将点从四维减少到三维时,我们可以放弃这个最终坐标。我将使用的代码来做PCA方法来自这个页面上的towardsdatascience.com网站:
def pca(X): #数据矩阵X,假设以0为中心的n, m = X。形状断言np.allclose(X.mean(axis=0), np.zeros(m)) #计算协方差矩阵C = np.dot(X。T, X) / (n-1) #特征分解eigen_vals, eigen_vecs = np. linalge .eig(C) #将X投影到PC空间X_pca = np。dot(X, eigen_vecs)返回X_pca
这段代码假设您已经将数据集存储到numpy数组中,数组中的每一行代表一个数据点。这个函数返回一个新的numpy数组,其中包含每个数据点相对于PCA算法计算的新基的坐标。该函数的另一个要求是原始数据为零中心,这意味着我们必须计算数据集中每列的平均值,然后从数据集中每列的平均值中减去该平均值。
下面是从文本文件中读取训练集和测试集的代码。这段代码将完整的数据集组织为数据点列表,将该列表转换为numpy数组X,通过从每列中减去平均值,将0个中心X转换为numpy数组,然后调用pca()函数。
点= =[][]类张开(“training.txt”)f:线在f.readlines():部分= line.split () points.append(((部分[0])浮动,浮动(部分[1]),浮动(部分[2]),浮动(部分[3])])classes.append (int[4](部分)与开放(“用法”)f:线在f.readlines():部分= line.split () points.append(((部分[0])浮动,浮动(部分[1]),浮动(部分[2]),浮动(部分[3])])classes.append (int[4](部分)+ 2)X = np.array(点)X - = np.mean (X轴= 0)D = pca (X)
赢博体育PCA算法的结果是一个新的数据点数组D,在新的PCA基中给出每个原始数据点的坐标。这就是我们从四维降维到三维的地方。我们使用一些简单的numpy切片操作来切割数组的前三列,以生成要绘制的三维数据点列表。
xs = D[:,0] ys = D[:,1] zs = D[:,2]
下一步是根据原始点的分类将这些数据点分离到子列表中。您可能已经注意到,在我用来读取数据点的原始代码中,我也收集了分类信息。训练集中的真钞分类为0,训练集中的假钞分类为1,测试集中的真钞分类为2,测试集中的假钞分类为3。下一段代码将分类重新附加到转换后的数据点上,然后根据四种分类再次拆分列表:
赢博体育=列表(zip (x, y, z,类))红色=[]#点的训练集分类1绿色=[]#点的训练集分类0黄色=[]#点的测试集分类1蓝色=[]#点的测试集分类0 x, y, z, c:如果c = = 0: green.append ((x, y, z)) elif c = = 1: red.append ((x, y, z)) elif c = = 2: blue.append ((x, y, z)):yellow.append redX ((x, y, z)) =(用红色x, x, y, z] redY = [y为x, y, z红色]redZ = [z为x, y, z红色]greenX = [x, x, y, z在绿色)呈绿色的= [y为x, y, z在绿色]greenZ = [z为x, y, z在绿色]yellowX = [x, x, y, z的黄色]淡黄的=(用黄色y为x, y, z] yellowZ =(用黄色z为x, y, z] blueX =(用蓝色x, x, y, z]旅行包=(蓝色y为x, y, z] blueZ = [z为x, y, z在蓝色)
我们现在有四个独立的数据点列表要绘制。
最后一步是使用pyplot绘制一些三维图。由于我将制作几个以不同方式查看数据集的图,因此我将使用pyplot图,这是一个可以容纳多个子图的容器。pyplot调用子plot轴,因此我将使用add_subplot()函数创建四个不同的轴。
我们将为每个子图使用的图类型是pyplot散点图,它用于绘制数据点云。
FIG = plt.figure() ax = FIG .add_subplot(221, projection='3d') ax。(redX, redY, redZ, c='r', marker='.')scatter(greenX, greenY, greenZ, c='g', marker='.') ax = fig.add_subplot(222, projection='3d') ax。scatter(blueX, blueY, blueZ, c='b', marker='.') ax。scatter(yellowX, yellowY, yellowZ, c='y', marker='.') ax = fig.add_subplot(223, projection='3d') ax。(redX, redY, redZ, c='r', marker='.')scatter(yellowX, yellowY, yellowZ, c='y', marker='.') ax = fig.add_subplot(224, projection='3d') ax。scatter(greenX, greenY, greenZ, c='g', marker='.') ax。scatter(blueX, blueY, blueZ, c='b', marker='.') plt.savefig("pca3.png")
下面是结果的情节。
第一行的两个图表示训练集和测试集。我们在这两张图中看到的是,真钞和假钞形成了不同的碗状区域,碗状的假数据点嵌套在里面,而碗状的真数据点略高于碗状的真数据点。正是这两个区域的分离说明了k近邻方法的成功。
第二排的两张图只显示了左边的假钞和右边的真钞。在这些图中,我们可以看到来自测试集的数据点合并到来自训练集的数据点。