NumPy 和它的 ndarray 对象,这个对象为 Python 多维数组提供了高效的存储和处理方法
-
数组基础
- 向量 (一维数组)、矩阵 (二维数组)
- 创建数组
-
从Python列表创建
np.array(range(10),dtype='float32') np.array([range(i,i+3)for i in range(2,7,2)])
-
用numpy内置方法创建
np.zeros((3,5)) #3*5的数值都是0的二维浮点数组 np.ones((3,5),dtype='int') #3*5 数值都是1的二维整数数组 np.full((3,5),'python') #3*5 数值都是'python'的二维数组 np.arange(20,0,-5) #返回一个线性序列,与range()类似,arange函数对数据类型敏感,如果将整数作为参数,生成整数数组;如果输入浮点数(例如arange(3.)),则生成浮点数组 np.arange(3.0) >>> array([ 0., 1., 2.]) np.linsapce(1,10,5) #返回长度为5的数组,数值线性均匀分布在1~10之间的浮点数,不受舍入错误的影响 np.random.random((3,5)) #返回3*5 二维数组,随机分布在0~1之间的浮点数 np.random.randint(0,10,(3,5))#创建3*5二维整数数组,随机分布在[0,10)之间的整数 np.random.normal(0,1,(3,5)) #创建3*5二维浮点数组,平均值为0,方差(每个数与平均数的差的平均数)为1 np.eye(5) #创建5*5单位矩阵,对角线为1的方阵 np.eye(5,3,k=1,dtype=int) #5行3列,值是1的对角线从第2列开始 array([[0, 1, 0], [0, 0, 1], [0, 0, 0], [0, 0, 0], [0, 0, 0]]) np.empty(3) #长度为3,数值是内存随机数 numpy的数据类型
-
numpy的数据类型
- 指定数据类型
dtype = 'float32'
- 或相关np对象
dtype = np.int32
- 指定数据类型
-
numpy的数据类型
- 指定数据类型
dtype = 'float32'
- 或相关np对象
dtype = np.int32
- 指定数据类型
-
数组的操作
-
数组的属性
na=np.randdom.randint(1,10,size=(3,5)) na.ndim # 2 数组的维度 na.shape #(3,5) 数组每个维度的大小 na.size # 15 数组的总大小 na.dtype #dtype('int32') 数组的数据类型 na.nbytes #60 数组总的字节数 na.itmesize # 4 每个元素的字节数 #设置一组种子,保证随机数相同 np.random.seed(1) x1=np.random.randint(10,size=10) #[5 8 9 5 0 0 1 7 6 9] np.random.seed(1) x2=np.random.randint(10,size=10) #[5 8 9 5 0 0 1 7 6 9] np.random.seed(1) x3=np.random.randint(10,size=10) #[5 8 9 5 0 0 1 7 6 9] # randint(low,high=none,size=none);省略high 则返回[0,low)的区域随机数
-
数组的索引
数组的索引与列表相似,可以通过索引查询或修改,不过数组的类型是固定的,会被自动修改
na=np.array([[1,2],[3,4],[5,6]]) na[2][0]=50
-
- 数组的切片
-
关于数组切片有一点很重要也非常有用,那就是数组切片返回的是数组数据的视图,而不是数值数据的副本,如果修改这个子数组,原始数组也被修改!!!!
-
arr [ 行范围:列范围 ] 行范围:垂直方向 axis=0;列范围:水平方向axis=1
-
na[:,1] #获取第二列 array([2, 4, 6]) na[1,:] #获取第二行 array([3, 4])
-
创建数组的副本
-
-
x=na.cpoy()
-
-
数组的变形
-
reshape()方法可以实现维度转换,但大小要一致
na=np.array([[1,2],[3,4],[5,6]]) na.size #6 na.reshape(6) #array([ 1, 2, 3, 4, 5, 6])
-
另外一个常见的变形模式是将一个一维数组转变为二维的行或列的矩阵。你也可以通过 reshape 方法来实现,或者更简单地在一个切片操作中利用 newaxis 关键字
x = np.array([1, 2, 3]) # 通过变形获得的行向量 x.reshape((1, 3)) Out[39]: array([[1, 2, 3]]) In[40]: # 通过newaxis获得的行向量 x[np.newaxis, :] Out[40]: array([[1, 2, 3]]) In[41]: # 通过变形获得的列向量 x.reshape((3, 1)) Out[41]: array([[1],[2],[3]]) In[42]: # 通过newaxis获得的列向量 x[:, np.newaxis] Out[42]: array([[1],[2],[3]])
-
-
数组的拼接和切割
axis 0:通常指行,第0轴沿着行的垂直往下
axis 1:通常指列,第1轴沿着列的方向水平延伸
reshape((3,4)):3表示0轴长度(有多少行),4表示1轴长度(有多少列)
-
np.concatenate( [ n1,n2....] ) : 将数组元组或数组列表作为参数
-
-
na=np.array([[ 1, 2, 3], [4, 5, 6],[ 7, 8, 9]]) # 默认沿着第一个轴 (x轴折叠)拼接 n1=np.concatenate([na,na,na]) # # 沿着第二个轴(y轴折叠)拼接 n1=np.concatenate([na,na,na],axis=1)
-
固定维度,使用vstack(垂直栈)与hstack(水平栈) 进行拼接,np.dstack 将沿着第三个维度.
na=array([[1, 2, 3],[4, 5, 6],[7, 8, 9]]) n1=np.array([9,9,9]) np.vstack([n1,na]) '''array([[9, 9, 9], [1, 2, 3], [4, 5, 6], [7, 8, 9]]) ''' n1=np.array([[9],[9],[9]]) np.hstack([na,n1]) ''' array([[1, 2, 3, 9], [4, 5, 6, 9], [7, 8, 9, 9]]) '''
-
切割
-
分裂可以通过 np.split()、np.hsplit()和 np.vsplit() 函数来实现。可以向函数传递一个索引列表作为参数,索引列表记录的是分裂点位置。值得注意的是,N 分裂点会得到 N + 1 个子数组。相关的np.hsplit 和 np.vsplit 的用法也类似.
na=array([1, 2, 3, 4, 5, 6, 7, 8, 9]) np.split(na,(3,5)) #[array([1, 2, 3]), array([4, 5]), array([6, 7, 8, 9])] na=np.arange(16).reshape(4,4) np.vsplit(na,[2]) ''' [array([[0, 1, 2, 3], [4, 5, 6, 7]]), array([[ 8, 9, 10, 11], [12, 13, 14, 15]])] ''' np.hsplit(na,[3]) ''' [array([[ 0, 1, 2], [ 4, 5, 6], [ 8, 9, 10], [12, 13, 14]]), array([[ 3], [ 7], [11], [15]])]
-
-
数组的增删操作
增加 :np.append(array,data])
-
插入:np.insert(arr, obj, values, axis) #obj插入元素位置
a = np.array([[1,2],[3,4],[5,6]]) b=np.insert(a,1,11,axis = 1) #增加列上得元素 # 输出 array([[ 1, 11, 2], [ 3, 11, 4], [ 5, 11, 6]]) a = np.array([[1,2],[3,4],[5,6]]) b=np.insert(a,1,[2,6],axis = 0) #增加行上得元素 # 输出 array([[1, 2], [2, 6], [3, 4], [5, 6]])
numpy.delete(arr, obj, axis) 在副本上操作,返回删除了某些元素的新数组
-
数组的计算:通用函数
通用函数有两种存在形式:一元通用函数(unary ufunc)对单个输入操作,二元通用函数(binary ufunc)对两个输入操作
-
数组的加减乘除运算
运算符 对应的通用函数 描述 + np.add 加法运算(即 1 + 1 = 2) - np.subtract 减法运算(即 3 - 2 = 1) - np.negative 负数运算( 即 -2) * np.multiply 乘法运算(即 2 * 3 = 6) / np.divide 除法运算(即 3 / 2 = 1.5) // np.floor_divide 地板除法运算(floor division,即 3 // 2 = 1) ** np.power 指数运算(即 2 ** 3 = 8) % np.mod 模 / 余数( 即 9 % 4 = 1) na=np.arange(5) print(na+2) print(np.add(na,2))
-
绝对值 abs()或 absolute()
na=np.arange(-5,0) print(na) print(np.abs(na))
-
三角函数
np.pi np.sin(theta) /np.arsin(theta) np.cos(theta) /np.arcos(theta) np.tan(theta) /np.artan(theta)
-
指数与对数
#指数 e^x --->np.exp(x) 2^x --->np.exp2(x) 3^x --->np.power(3,x) #对数 ln(x) --->np.log(x) log2(x) --->np.log2(x) log10(x) --->np.log10(x)
-
通用函数特性:
-
指定输出位置:所有的通用函数都可以通过 out 参数来指定计算结果的存放位置
y=np.empty(5) np.multiply(3,na,out=y) y 输出 array([15., 12., 9., 6., 3.])
-
聚合功能:例如用任何通用函数的 reduce 方法(函数也有自己的方法)
na=array([5, 4, 3, 2, 1]) np.add.reduce(na) >>>15
-
外积 :任何通用函数都可以用 outer 方法获得两个不同输入数组所有元素对的函数运算结果
na=array([5, 4, 3, 2, 1]) np.add.outer(na,na) >>> array([[10, 9, 8, 7, 6], [ 9, 8, 7, 6, 5], [ 8, 7, 6, 5, 4], [ 7, 6, 5, 4, 3], [ 6, 5, 4, 3, 2]])
axis 关键字指定的是数组将会被折叠的维度,而不是将要返回的维度。因此指定axis=0 意味着沿着第一个轴(x轴)折叠——对于二维数组,这意味着每一列的值都将被聚合.
-
其他聚合
-
数组的计算:广播
什么是数组的广播?
数组的广播,可以理解为数组扩展,为了不同维度的数组之间的运算,将它们扩展或广播使其能够变形成同维度数组从而进行运算。参考可视化展示
a=np.arange(3)
b=a.reshape(3,1)
a+b
array([[0, 1, 2],[1, 2, 3],[2, 3, 4]])
广播规则:
-
规则 1:如果两个数组的维度数不相同,那么小维度数组的形状将会在最左边补 1。
a=np.ones((3,3)) b=np.arange(3) >>>a.shape = (3, 3) >>> b.shape=(3,) #b会扩展或广播成(1,3)
-
规则 2:如果两个数组的形状在任何一个维度上都不匹配,那么数组的形状会沿着维度为 1 的维度扩展以匹配另外一个数组的形状。需要更新这两个数组的维度来相互匹配.
a=np.ones((3,1)) b=np.arange(3) >>>a.shape = (3, 1) ---->(3,3) >>> b.shape=(3,) ----->(3,3) a+b array([[1., 2., 3.], [1., 2., 3.], [1., 2., 3.]])
-
规则 3:如果两个数组的形状在任何一个维度上都不匹配并且没有任何一个维度等于 1,那么会引发异常。
a=np.ones((3,2)) b=np.arange(3) a+b # ValueError: a+b[:,np.newaxis] #变换维度 array([[1., 1.], [2., 2.], [3., 3.]])
数组的运算:比较、掩码、布尔逻辑
-
比较运算:与通用函数相似,数组的比较运算返回相应布尔值数组
na=np.arange(10) na>3 array([False, False, False, False, False, False, True, True, True,True])
-
操作布尔数组
#统计记录个数 na=np.arange(1,10).reshape(3,3) np.count_nonzero(na>6) # 3 返回为TRUE的个数 np.sum(na>6) # 3 同理 np.sum(na>5,axis=1) # array([0, 1, 3]) 沿着列返回个数组 #类似的函数还有 any()/all(na>6,axis=1)
-
布尔运算(逻辑运算或逐位运算)
运算符 对应通用函数 & np.bitwise_and | np.bitwise_or ^ np.bitwise_xor ~ np.bitwise_not np.sum(na>5,axis=1)&na<3 array([[ True, True, False], [ True, True, True], [ True, True, True]])
-
将布尔数组作为掩码
使用布尔数组作为掩码,通过该掩码获得数据的子数据集,换句话说,所有的这些值是掩码数组对应位置为 True 的值。
n1=np.arange(1,9).reshape((4,2)) n1>5 array([[False, False], [False, False], [False, True], [ True, True]]) n1[n1>5] array([6, 7, 8])
通过将布尔操作、掩码操作和聚合结合,可以快速回答对数据集提出的这类问题
-
关键字 and 和 or,以及逻辑操作运算符 & 和 | 的区别是什么,什么时候该选择哪一种?
-
当你使用 and 或 or 时,就等于将这个对象当作整个布尔实体。在 Python 中,所有非零的整数都会被当作是 True:
>>> bool(42),bool(59) (True, True) >>> 42 and 0 0 >>> 42 or 0 42 >>> bool(42 and 0) False >>> bool(42 or 0) True
-
当你对整数使用 & 和 | 时,表达式操作的是元素的比特,将 and或 or 应用于组成该数字的每个比特, & 和 | 运算时,对应的二进制比特位进行比较以得到最终结果
>>> bin(42),bin(59) ('0b101010', '0b111011') >>> bin(42 &59) '0b101010' >>> bin(42 | 59) '0b111011' >>> 59&42 42 >>> 42 |59 59
-
当 NumPy 中有一个布尔数组时,该数组可以被当作是由比特字符组成的,其中 1 = True、0 = False。这样的数组可以用上
面介绍的方式进行 & 和 | 的操作;而用 or 来计算这两个数组时,Python 会计算整个数组对象的真或假,这会导致程序出错;同样,对给定数组进行逻辑运算时,你也应该使用 | 或 &,而不是or 或 and
A = np.array([1, 0, 1, 0, 1, 0], dtype=bool) B = np.array([1, 1, 1, 0, 1, 1], dtype=bool) A | B Out[37]: array([ True, True, True, False, True, True], dtype=bool) x = np.arange(10) (x > 4) & (x < 8) Out[39]: array([False, False, ..., True, True, False, False], dtype=bool)
-
花哨的索引
花哨的索引和前面那些简单的索引非常类似,但是传递的是索引数组,而不是单个标量。花哨的索引让我们能够快速获得并修改复杂的数组值的子数据集。
-
传递一个索引数组来一次性获得多个数组元素
n1=np.arange(12) >>> n1 array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) >>> ind=[0,5,7] >>> n1[ind] array([0, 5, 7])
-
结果的形状与索引数组的形状一致,而不是与被索引数组的形状一致
ind=np.array([[3,4,5],[7,8,9]]) >>> n1[ind] array([[3, 4, 5],[7, 8, 9]])
-
多维度
n1=np.arange(12).reshape(3,4) row=np.array([0,1,2]) col=np.array([1,3,3]) n1[row,col] array([ 1, 7, 11]) #n1[0,1]=1;n1[1,3]=7;n1[2,3]=11
-
组合索引
-
将花哨的索引和简单的索引组合使用
-
将花哨的索引和切片组合使用
-
将花哨的索引和掩码组合使用
-
索引选项的组合可以实现非常灵活的获取和修改数组元素的操作
-
花哨的索引可以被用于获取部分数组,它也可以被用于修改部分数组。
-
数组的排序
-
默认情况下,np.sort 的排序算法是 快速排序,其算法复杂度为[N log N],另外也可以选择归并排序和堆排序
-
np.sort(x) :返回一个排好序的数组
-
x.sort() : in place 就地置换;在原始数组就地排序
-
np.argsort(x) :返回的是原始数组排好序的索引值
x=np.array([2, 1, 4, 3, 5]) >>> np.argsort(x) array([1, 0, 3, 2, 4], dtype=int64)
-
部分排序:分隔
# np.partition 函数的输入是数组和数字 K,输出结果是一个新数组,最左边是第 K 小的值,往右是任意顺序的其他值,在这两个分隔区间中,元素都是任意排列的,同样支持axis x=np.array([6,5,4,7,1,8,2,9,4,2,0]) >>> np.partition(x,3) array([0, 2, 1, 2, 4, 5, 4, 6, 9, 7, 8]) np.partition(x,2,axis=1)
数组的结构化:numPy 的结构化数组和记录数组,它们为复合的、异构的数据提供了非常有效的存储,其实pandas更实用
data = np.zeros(4, dtype={'names':('name', 'age', 'weight'),'formats':('U10', 'i4', 'f8')})