在人工智能的研发中,其本质就是把一切问题转化为数学问题,因此数学运算很是重要。不少数学运算采用的都是numpy这个库,由于它提供了很是多的科学计算的方法,能让咱们的工做变得很是便利,这一章我将从numpy的基本使用开始,逐渐解决掉那些数学问题,让Python与数学可以更紧密的结合在一块儿。python
numpy的本质其实仍是一个多维数组,虽然咱们以前学习过数组对象(Python中的list或者tuple)和numpy的数据看似同样,可是数组是没法直接参与数值运算的,而numpy对象却能够。算法
import numpy as np arr1 = np.array([1, 2, 3, 4, 5, 6]) arr2 = np.array([[1, 2, 3, 4, ], [5, 6, 7, 8, ]]) print(arr1, arr1.shape, arr1.dtype) print(arr2, arr2.shape, arr1.dtype) # shape获取数组形状2行4列,dtype获取数组中元素类型
若是咱们建立数组时,元素类型不同,numpy会给咱们自动处理成同样的。数组
arr3 = np.array([1, 2.5, 3]) # 只要数组元素中出现float类型,就会所有处理成float print(arr3, arr3.dtype) arr4 = np.array(['4', 5, 5.6]) # 只要数组元素中出现str,就会所有处理成str print(arr4, arr4.dtype)
numpy的访问与Python中list或者tuple访问原理同样,方法也很是相似,只不过是加了一个纬度的概念。less
# 首先咱们定义了一个二维数组 arr5 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) print(arr5[1]) # 第一行 [4 5 6] print(arr5[1][0]) # 第一行第0个 4 print(arr5[:, 2]) # 全部行第2个 [ 3 6 9 12] print(arr5[:2]) # 前2行 [[1 2 3] [4 5 6]] print(arr5[1, :]) # 第1行全部列 [4 5 6] print(arr5[:, 1:2]) # 全部行第2到第3列 [[ 2] [ 5] [ 8] [11]]
对于二维来讲,若是有逗号,逗号前是行筛选,逗号后是列筛选。对于n维来讲,第一个逗号前是第一维,后面依次是二维三维等。ide
numpy对象有一个shape属性,在Python基础中,对于形状并不敏感,而在科学计算中,形状却很重要,在后面的算法模型计算中,咱们会使用地很频繁。函数
# 定义一个6行3列的numpy数组对象 arr6 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15], [16, 17, 18]]) print(arr6.shape) # 注意看每次打印的结果 print(arr6.reshape(2, 9)) # 获得一个新的形状,原来的对象不变 print(arr6.shape, arr6) print(arr6.resize(2, 9)) # 无返回值,真正修改 print(arr6.shape, arr6)
咱们在这段代码中,分别使用了reshape和resize两种方法来对数组进行形状上的改变。其中reshape只是返回改变形状后的预览状态,或者说若是咱们要使用这个结果只能把结果赋值给一个单独的变量,而后再进行使用。resize方法的返回结果为空,可是它却真正的改变了组数的形状,仔细看打印结果你就可以发现这两种形状操做方法的区别了。学习
降维是人工智能算法中很是经常使用且重要的一个操做,缘由是有时咱们去描述一个事物的特征时,会有很是多的维度,但过多的维度会给咱们的计算带来麻烦,这个时候咱们就须要去下降它的维度,而后再进行计算。人工智能
arr7 = np.array([[1, 10, 100], [2, 20, 200], [3, 30, 300]]) # 按照数组的行顺序降至一维 print(arr7) print(arr7.ravel()) print(arr7.reshape(-1)) print(arr7.flatten()) # 按照大小顺序降至一维 print(arr7.ravel(order="F")) print(arr7.reshape(-1, order="F")) print(arr7.flatten(order="F"))
降维后再进行修改code
print('ravel:{}'.format(arr7.ravel())) arr7.ravel()[1] = 1000 print(arr7) print('reshape: {}'.format(arr7.reshape(-1))) arr7.reshape(-1)[2] = 3000 print(arr7) print('flatten: {}'.format(arr7.flatten())) arr7.flatten()[0] = 2000 print(arr7)
从结果中,咱们看到经过flatten方法实现的降维返回的是复制的操做,若是要用,那么只能把结果赋值给另外的变量了。它并无影响原来数组的结果。经过ravel和reshape两个方法,返回的则是视图,也就是经过对视图的修改,是会直接影响到原数组中的值的。orm
arr8 = np.array([[1, 10, 100], [2, 20, 200], [3, 30, 300]]) arr9 = np.array([1, 2, 3]) arr10 = np.array([[5], [6], [7]]) # 纵向堆叠 print(np.vstack([arr8, arr9])) print(np.row_stack([arr8, arr9])) # 横向合并 print(np.hstack([arr8, arr10])) print(np.column_stack([arr8, arr10]))
须要注意的是:多个数组横向堆叠时,要保证行数相同,纵向合并,则要保证列数相同。
在之前,咱们若是要对两个同形状的数组进行对应位置的四则运算时,咱们必需要对两个数组进行循环处理,代码量上来讲并很多,而且容易出错。有了NumPy以后,这些运算将会变的很是的简单。
import numpy as np arr1 = np.array([11, 12, 13]) arr2 = np.array([21, 22, 23]) arr3 = np.array([31, 32, 33]) print(arr1 + arr2) print(arr1 + arr2 + arr3) print(arr1 - arr2) print(arr1 - arr2 - arr3) print(arr1 * arr2) print(arr1 * arr2 * arr3) print(arr1 / arr2) print(arr1 / arr2 / arr3) print(arr1 // arr2) print(arr1 % arr2) print(arr1 ** arr2) print(np.add(arr1, arr2)) print(np.add(np.add(arr1, arr2), arr3)) print(np.subtract(arr1, arr2)) print(np.multiply(arr1, arr2)) print(np.divide(arr1, arr2))
从代码的运行结果中咱们能够看到,当咱们使用符号进行四则运算的时候,是能够连续进行操做的。当咱们使用对象的方法进行四则运算的时候,不能够连续进行操做,由于这个方法只接收两个参数。若是咱们想要对多个数组对象进行操做的时候,咱们必须使用方法嵌套的方式来进行操做。除了四则运算,在学习Python基础时,所学习的取余数、整除、幂运算等都是支持的。
print(arr1 <= arr2) print(arr1 == arr2) print(arr1 != arr2) print(np.greater(arr1, arr2)) print(np.greater_equal(arr1, arr2)) print(np.less(arr1, arr2)) print(np.less_equal(arr1, arr2)) print(np.equal(arr1, arr2)) print(np.not_equal(arr1, arr2))
从结果上看,运用比较运算符能够返回布尔类型的值,也就是True和False。那咱们何时会用到这样的运算呢?第一种状况是从数组中查询知足条件的元素,第二种状况是根据判断的结果执行不一样的操做,示例代码以下:
arr3 = np.array([23, 12, 25]) arr4 = np.array([21, 15, 23]) print(arr3[arr3 > arr4]) # 取出arr3中元素大于arr4的 print(arr3[arr3 > 24]) # 取出arr3中元素大于24的 print(np.where(arr3 > 24, 0, arr3)) # 相似三元表达式,把大于24的修改为0,其余不变 print(list(0 if x > 24 else x for x in arr3)) print(np.where(arr4 > 16, 0, arr4))
上面咱们全部的运算都是基于相同形状的数组,那么当数组形状不一样时,可以让它们之间进行运算吗?答案是确定的,可是有相应的规则,不能随意计算,这种计算就叫作广播运算。
# 1 广播运算,末尾的纬度值加上去 arr3 = np.arange(60).reshape(5, 4, 3) arr4 = np.arange(12).reshape(4, 3) print(arr3) print(arr4) print(arr3 + arr4) # 2 纬度值有一个为1 arr5 = np.arange(60).reshape(5, 4, 3) arr6 = np.arange(4).reshape(4, 1) print(arr5) print(arr6) print(arr5 + arr6) # 3 arr7会自动补齐,相似上面纬度值有一个为1 arr7 = np.arange(12).reshape(4, 3) arr8 = np.array([1, 2, 3]) print(arr7) print(arr8) print(arr7 + arr8) arr9 = np.arange(60).reshape(5, 4, 3) arr10 = np.arange(8).reshape(4, 2) print(arr9) print(arr10) # print(arr9 + arr10) # 不在上述三种讨论范围内,没法运算
其实,广播运算中的广播就是一对多,它的规律就是二者有类似的地方能够对应的上就能运算,缺乏的部分,会自动用相同的部分补齐。
numpy提供给咱们一些常见的函数,除了np.pi或者np.e这样的常量函数,numpy也提供给咱们不少数学函数供咱们直接调用。
import numpy as np arr1 = np.array([1.3, 1.5, -1.8, 2.4, 3.2]) arr2 = np.array([1, 2, 3, 4, 5]) print(np.fabs(arr1)) # 绝对值 print(np.ceil(arr1)) # 向上取整 print(np.floor(arr1)) # 向下取整 print(np.round(arr1)) # 四舍五入 print(np.fmod(arr2, arr1)) # 余数 print(np.modf(arr1)) # 取小数部分和整数部分 print(np.sqrt(arr2)) # 算法平方根 print(np.square(arr2)) # 平方 print(np.exp(arr2)) # 以e为底的指数 print(np.power(arr2, 3)) # 各元素的3次方 print(np.log2(arr2)) # 以2为底的对数 print(np.log10(arr2)) # 以10为底的对数 print(np.log(arr2)) # 以e为底的对数
数组对象有几个维度就有几个轴,对于咱们常见的二维数组来讲,轴0是竖直方向,轴1是水平方向。
import numpy as np arr1 = np.array([[3, 7, 25, 8, 15, 20], [4, 5, 6, 9, 14, 21]]) print(arr1) print(np.max(arr1)) # 全部数组元素最大值 print(np.max(arr1, axis=1)) # 轴1最大值 print(np.max(arr1, axis=0)) # 轴0最大值
numpy提供了不少能够按照轴方向来计算的函数。
print(np.min(arr1, axis=0)) # 最小值 print(np.min(arr1, axis=1)) print(np.mean(arr1, axis=0)) # 平均值 print(np.median(arr1, axis=0)) # 中位数 print(np.sum(arr1, axis=1)) # 求和