NumPy入门笔记

Numpy学习笔记

序:真的是想到哪里学到哪里,学东西不要管那么多,就当是“量子波动”学习知识,总有一天会成体系。

2019年10月25日 至 2019年10月28日

# define " import numpy as np "


简介

​ NumPy是Python语言的一个扩充程序库。支持高级大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。Numpy内部解除了Python的PIL(全局解释器锁),运算效率极好,是大量机器学习框架的基础库!

​ NumPy 的前身 Numeric 最早是由 Jim Hugunin 与其它协作者共同开发,2005 年,Travis Oliphant 在 Numeric 中结合了另一个同性质的程序库 Numarray 的特色,并加入了其它扩展而开发了 NumPy。NumPy 为开放源代码并且由许多协作者共同维护开发。



NumPy Ndarray对象及常用操作

基本属性

​ 这是一个N维数组对象,下标从0开始,且所有元素同类型、同内存大小,主要包含如下属性:

  • ndarray.ndim

    表示axes(axis复数)/dimensions 描述维度数字

  • ndarray.shape

    返回元组,输出各个维度的大小

    可以使用reshape函数来调整数组的形状

    import numpy as np
    a = np.array([[1,2,3],[4,5,6]])
    b = a.reshape(3,2)
    print (b)
  • ndarray.size

    返回所有元素的个数(各个维度大小的乘积)

  • ndarray.dtype

    返回数据的类型

    ​ ">" 若首先取高字节的数据存放在低地址,则是大端法;

    ​ "<" 若首先取低字节的数据存放在低地址,则是小端法;

    • 自定义数据类型
    import numpy as np
    student = np.dtype([('name','S20'), ('age', 'i1'), ('marks', 'f4')]) 
    a = np.array([('abc', 21, 50),('xyz', 18, 75)], dtype = student) 
    print(a)
  • ndarray.itemsize

    返回单个元素的大小(单位字节),等价于ndarray.dtype.itemsize

  • ndarray.data

    一般不使用,这是存放数据的区域

  • 其他参见numpy-ref文档

    NumPy数组的维数称为秩(rank),一维数组的秩为 1,二维数组的秩为2,以此类推。

​ 在 NumPy中,每一个线性的数组称为是一个轴(axis),也就是维度(dimensions)。比如说,二维数组相当于是两个一维数组,其中第一个一维数组中每个元素又是一个一维数组。所以一维数组就是 NumPy 中的轴(axis),第一个轴相当于是底层数组,第二个轴是底层数组里的数组。而轴的数量(秩),就是数组的维数。W

很多时候可以声明 axis,axis=0,表示沿着第 0 轴进行操作,即对每一列进行操作;axis=1,表示沿着第1轴进行操作,即对每一行进行操作。


创建数组

  1. 使用函数创建新数组

np.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)

对应参数解释:object数组或者嵌套数列;dtype元素类型可选;copy对象是否复制可选;order创建数组的样式(C行方向、F列方向、默认A任意方向);subok默认返回一个与基类同类型的数组;ndim指定生成数组的最小维度。

还可以使用其他函数:

array, zeros, zeros_like, ones, ones_like, empty, empty_like, arange, linspace, numpy.random.RandomState.rand, numpy.random.RandomState.randn, fromfunction, fromfile

  1. 从已有对象创建新数组

numpy.asarray(a, dtype = None, order = None)

a可以接受的参数为列表、列表的元组、元组、元组的元组、元组的列表、多为数组;数据类型可选;存放方式C/F。

numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)

numpy.frombuffer 用于实现动态数组。numpy.frombuffer 接受 buffer 输入参数,以流的形式读入转化成 ndarray 对象。

buffer可以是任意对象,会以流的形式读入;dtype返回数组的数据类型可选;count读取的数据数量,默认为-1,读取所有数据;offset读取的起始位置,默认为0。

import numpy as np
s =  'Hello World'
a = np.frombuffer(s, dtype =  'S1')
print (a)
# 输出
# ['H' 'e' 'l' 'l' 'o' ' ' 'W' 'o' 'r' 'l' 'd']

numpy.fromiter(iterable, dtype, count=-1)

numpy.fromiter 方法从可迭代对象中建立 ndarray 对象,返回一维数组。

iterable可迭代对象;dtype返回数组的数据类型;count读取的数据数量,默认为-1,读取所有数据。

import numpy as np 
# 使用 range 函数创建列表对象  
list=range(5)
it=iter(list)
# 使用迭代器创建 ndarray 
x=np.fromiter(it, dtype=float)
print(x)
#输出
# [0. 1. 2. 3. 4.]
  1. 使用数值范围创建数组

numpy.arange(start, stop, step, dtype)

numpy.arange 根据 [start,stop)指定的范围,以及 step 设定的步长,生成一个 ndarray对象。

start起始值,默认为0;stop终止值(不包含);step步长,默认为1;dtype返回ndarray的数据类型,如果没有提供,则会使用输入数据的类型。

np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)

numpy.linspace 函数用于创建一个一维数组,该数组是一个等差数列构成的。

start序列的起始值;stop序列的终止值,如果endpoint为true,该值包含于数列中;num要生成的等步长的样本数量,默认为50;endpoint该值为 ture 时,数列中中包含stop值,反之不包含,默认是True;retstep如果为 True 时,生成的数组中会显示间距,反之不显示;dtypendarray 的数据类型。

import numpy as np
a =np.linspace(1,10,10,retstep=True)
print(a)
# 拓展例子
b =np.linspace(1,10,10).reshape([10,1])
print(b)
#输出
# (array([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10.]), 1.0)

np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)

numpy.logspace 函数用于创建一个于等比数列,值得注意的是:start和stop是数列的下标值,他们的底数是base。

start序列的起始值为:base ** start;stop序列的终止值为:base ** stop,如果endpoint为true,该值包含于数列中;num 要生成的等步长的样本数量,默认为50;endpoint该值为 ture 时,数列中包含stop值,反之不包含,默认是True;base对数 log 的底数;dtypendarray 的数据类型。

import numpy as np
a = np.logspace(0,9,10,base=2)
print (a)
# [  1.   2.   4.   8.  16.  32.  64. 128. 256. 512.]

数据类型

名称 描述
bool_ 布尔型数据类型(True 或者 False)
int_ 默认的整数类型(类似于 C 语言中的 long,int32 或 int64)
intc 与 C 的 int 类型一样,一般是 int32 或 int 64
intp 用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64)
int8 字节(-128 to 127)
int16 整数(-32768 to 32767)
int32 整数(-2147483648 to 2147483647)
int64 整数(-9223372036854775808 to 9223372036854775807)
uint8 无符号整数(0 to 255)
uint16 无符号整数(0 to 65535)
uint32 无符号整数(0 to 4294967295)
uint64 无符号整数(0 to 18446744073709551615)
float_ float64 类型的简写
float16 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位
float32 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位
float64 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
complex_ complex128 类型的简写,即 128 位复数
complex64 复数,表示双 32 位浮点数(实数部分和虚数部分)
complex128 复数,表示双 64 位浮点数(实数部分和虚数部分)

类型转换

  • 浮点数据转换

    float64(默认)的数组转化为float32和float16的数组时,数组的长度会发生变化,分别变为原来的两倍和四倍。

  • 整型数据转换

    同上

  • 浮点数转整数

    numpy中的数据类型转换,不能直接改原数据的dtype,只能用函数astype()

    import numpy as np
    b=np.array([1.,2.,3.,4.]) # 默认为float64,直接改变则数组长度会变化
    c=b.astype(int)
    print(c)
    print(c.shape)
    print(c.dtype)

数组切片和索引

NumPy切片和普通索引,ndarray对象的内容可以通过索引或切片来访问和修改,与 Python 中 list 的切片操作一样。ndarray 数组可以基于 0 – n 的下标进行索引,切片对象可以通过内置的 slice() 函数,并设置 start, stop 及 step 参数进行,从原数组中切割出一个新数组。

a = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
s = slice(2,7,2)   # 从索引 2 开始到索引 7 停止,间隔为2
print (a[s])
# 或者
a = np.arange(10)
b = a[2:7:2]   # 从索引 2 开始到索引 7 停止(不包括7),间隔为 2
print(b)
# 输出 [2  4  6]

冒号 " : "的解释:如果只放置一个参数,如 [2],将返回与该索引相对应的单个元素。如果为 [2:],表示从该索引开始以后的所有项都将被提取。如果使用了两个参数,如 [2:7],那么则提取两个索引(不包括停止索引)之间的项,list[start​ : end: ​step]start:起始位置、end:结束位置、step:步长,list[::-1]用于reverse。

list[-1:]和list[:-1]的区别和联系: 这里面list[-1]是最后一个元素,所以等价于 list[len-1:len]list[0:len-1] 参考链接

切片还可以包括省略号 " … ",来使选择元组的长度与数组的维度相同。 如果在行位置使用省略号,它将返回包含行中元素的 ndarray。

a = np.array([[1,2,3],[3,4,5],[4,5,6]])  
print (a[...,1])   # 第2列元素
print (a[1,...])   # 第2行元素
print (a[...,1:])  # 第2列及剩下的所有元素
# 输出
# [2 4 5]
# [3 4 5]
# [[2 3]
#  [4 5]
#  [5 6]]
# reversed a
>>> print(a[ : :-1])     
array([[4, 5, 6], 
       [3, 4, 5], 
       [1, 2, 3]])  
>>> print(a[...,::-1])
[[3 2 1]
 [5 4 3]
 [6 5 4]]
>>> print(a[::-1,::-1])
[[6 5 4]
 [5 4 3]
 [3 2 1]]

NumPy 高级索引,NumPy 比一般的 Python 序列提供更多的索引方式。除了之前看到的用整数和切片的索引外,数组可以由整数数组索引(花式索引)、布尔索引(对应下面三段代码)。(花式索引?)

布尔索引通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。

>>> x = np.array([[1,  2],  [3,  4],  [5,  6]])
>>> x[x>3]
array([4, 5, 6])
# 以下实例使用了 ~(取补运算符)来过滤 NaN
>>> a = np.array([np.nan, 1, 2, np.nan, 3, 4, 5])
>>> print (a[~np.isnan(a)])
[1. 2. 3. 4. 5.]
# 还有a[np.iscomplex(a)]等

花式索引指的是利用整数数组进行索引。花式索引根据索引数组的值作为目标数组的某个轴的下标来取值。对于使用一维整型数组作为索引,如果目标是一维数组,那么索引的结果就是对应位置的元素;如果目标是二维数组,那么就是对应下标的行。花式索引跟切片不一样,它总是将数据复制到新数组中。

# 获取数组中(0,0),(1,1)和(2,0)位置处的元素
>>> x = np.array([[1,  2],  [3,  4],  [5,  6]])
>>> y = x[[0,1,2],  [0,1,0]] # 二维数组的索引
>>> y
array([1, 4, 5])
#
>>> x=np.arange(32).reshape((8,4))
>>> x
array([[ 0,  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]])
>>> x[[4,2,1,7]]
array([[16, 17, 18, 19],
       [ 8,  9, 10, 11],
       [ 4,  5,  6,  7],
       [28, 29, 30, 31]])
# 传入多个索引数组(要使用np.ix_)
>>> x[np.ix_([1,5,7,2],[0,3,1,2])]
array([[ 4,  7,  5,  6],
       [20, 23, 21, 22],
       [28, 31, 29, 30],
       [ 8, 11,  9, 10]])

寻找数组中的最大值和最小值索引可使用np.argmax(arr.axis = 0/1) , np.argmin(arr, axis = 0/1)不写axis则返回整个数组的最大值的索引(1个),0轴为列方向,1轴为行方向。

  • 生成随机数( 链接

数组广播

NumPy广播(Broadcast),广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行。如果两个数组 a 和 b 形状相同,即满足 a.shape == b.shape,那么 a*b 的结果就是 a 与 b 数组对应位相乘。这要求维数相同,且各维度的长度相同。

  • 让所有输入数组都向其中形状最长的数组看齐,形状中不足的部分都通过在shape前面加 1 补齐维度。(3,4)+(3,)补齐(1,3)
  • 输出数组的形状是输入数组形状的各个维度上的最大值。
  • 如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为 1 时,这个数组能够用来计算,否则出错。(x*y,y的维度与x中的子维度相同则可以运算)

迭代数组

参考链接:https://numpy.org/devdocs/reference/generated/numpy.nditer.html?highlight=nditer#numpy.nditer

NumPy 迭代数组,NumPy 迭代器对象 numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式,迭代器最基本的任务的可以完成对数组元素的访问。

np.nditer(op, flags=['multi_index'], op_flags=['readwrite'])

op ndarray 或者是序列;flags 可选项,字符串序列,用于控制迭代器行为;op_flags 可选项,字符串列表,可选值有 readonly, readwrite, or writeonly

  • 数组x和x.T的存储方式是一样的,使用迭代当时输出也是一样的。
  • 使用C(按照行输出)和F(按照列输出)迭代显式出的结果不一致。
x = np.arange(12).reshape(3,4)
>>> for i in np.nditer(x):
...     print(i,end = " ")
...
0 1 2 3 4 5 6 7 8 9 10 11

nditer 对象有另一个可选参数 op_flags。 默认情况下,nditer 将视待迭代遍历的数组为只读对象(read-only),为了在遍历数组的同时,实现对数组元素值得修改,必须指定 read-write 或者 write-only 的模式。

a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print ('原始数组是:')
print (a)
print ('\n')
for x in np.nditer(a, op_flags=['readwrite']): 
    x[...]=2*x 
print ('修改后的数组是:')
print (a)

nditer类的构造器拥有flags参数,它可以接受下列值:c_index 跟踪C顺序索引;f_index 跟踪Fortran顺序索引;external_loop输出值时具有多个值的一维数组。

如果两个数组是可广播的,nditer 组合对象能够同时迭代它们。 假设数组 a 的维度为 (3,4),数组 b 的维度为 (4,) ,则使用以下迭代器(数组 b 被广播到 a 的大小)。

>>> a = np.arange(0,60,5).reshape(3,4)
>>> b = np.array([1,2,3,4])
>>> a
array([[ 0,  5, 10, 15],
       [20, 25, 30, 35],
       [40, 45, 50, 55]])
>>> b
array([1, 2, 3, 4])
>>> for x,y in np.nditer([a,b]):
...     print ("%d:%d"  %  (x,y), end=", " )
...
0:1, 5:2, 10:3, 15:4, 20:1, 25:2, 30:3, 35:4, 40:1, 45:2, 50:3, 55:4,

数组相关操作

  • 修改数组形状 numpy.reshape numpy.ndarray.flat

    函数返回一个数组元素迭代器

    >>> x = np.arange(12).reshape(3,4)
    >>> x
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11]])
    >>> x.flat
    <numpy.flatiter object at 0x000001E7D0570910>

    numpy.ndarray.flatten

    返回一份数组拷贝,对拷贝所做的修改不会影响原始数组。

    >>> x.flatten()
    array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

    numpy.ravel

    返回一个连续的被展开的数组。等同于x.reshape(-1, order=order),修改会引起原来数组的变化。

    >>> y = np.ravel(x,order= "A")
    >>> y
    array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
    >>> y[0] = 100
    >>> y
    array([100,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11])
    >>> x
    array([[100,   1,   2,   3],
           [  4,   5,   6,   7],
           [  8,   9,  10,  11]])
  • 翻转数组 numpy.transpose

    用于对换数组的维度,numpy.transpose(arr, axes)arr:要操作的数组;axes:整数列表,对应维度,通常所有维度都会对换。功能同arr.T,转置。

    numpy.rollaxis

    函数向后滚动特定的轴到一个特定位置,numpy.rollaxis(arr, axis, start)arr:数组;axis:要向后滚动的轴,其它轴的相对位置不会改变;start默认为零,表示完整的滚动。会滚动到特定位置。

    numpy.swapaxes

    numpy.swapaxes(arr, axis1, axis2), 函数用于交换数组的两个轴 axis1和axis2。

  • 修改数组维度 numpy.broadcast

    用于模仿广播的对象,它返回一个对象,该对象封装了将一个数组广播到另一个数组的结果。该函数使用两个数组作为输入参数 。

numpy.broadcast_to

函数numpy.broadcast_to(array, shape, subok) 将数组广播到新形状。它在原始数组上返回只读视图。 它通常不连续。 如果新形状不符合 NumPy 的广播规则,该函数可能会抛出ValueError 。

numpy.expand_dims

函数通过在指定位置插入新的轴来扩展数组形状 numpy.expand_dims(arr, axis)

numpy.squeeze

函数numpy.squeeze(arr, axis) 从给定数组的形状中删除一维(该维度数值必须为1)的条目 。

  • 连接数组 numpy.concatenate

    函数 numpy.concatenate((a1, a2, ...), axis) 用于沿指定轴连接相同形状的两个或多个数组。

第一个数组:
[[1 2]
 [3 4]]
  
第二个数组:
  [[5 6]
   [7 8]]
  
沿轴 0 连接两个数组:
  [[1 2]
   [3 4]
   [5 6]
   [7 8]]
  
沿轴 1 连接两个数组:
  [[1 2 5 6]
   [3 4 7 8]]

numpy.stack

函数numpy.stack((a1,a2,...), axis) 用于沿新轴连接数组序列 。(维度会加1)

第一个数组:
[[1 2]
  [3 4]]
  
第二个数组:
[[5 6]
 [7 8]]
  
沿轴 0 堆叠两个数组:
  [[[1 2]
    [3 4]]
  
   [[5 6]
    [7 8]]]
  
  沿轴 1 堆叠两个数组:
  [[[1 2]
    [5 6]]
  
   [[3 4]
    [7 8]]]

numpy.hstack

numpy.stack 函数的变体,它通过水平堆叠来生成数组 np.hstack((a,b))

第一个数组:
[[1 2]
 [3 4]]  
第二个数组:
[[5 6]
 [7 8]]  
水平堆叠:
[[1 2 5 6]
 [3 4 7 8]]

numpy.vstack

第一个数组:
  [[1 2]
   [3 4]] 
第二个数组:
  [[5 6]
   [7 8]]
竖直堆叠:
  [[1 2]
   [3 4]
   [5 6]
   [7 8]]

  • 分割数组 numpy.split

    函数numpy.split(ary, indices_or_sections, axis) 沿特定的轴将数组分割为子数组 。ary:被分割的数组indices_or_sections:如果是一个整数,就用该数平均切分,如果是一个数组,为沿轴切分的位置(左开右闭)axis:沿着哪个维度进行切向,默认为0,横向切分。为1时,纵向切分。

    For example, [2, 3] would, for axis=0, result in ary[:2]、ary[2:3]、ary[3:]。

    numpy.hsplit

    原array:
    [[4. 7. 6. 3. 2. 6.]
     [6. 3. 6. 7. 9. 7.]]
    np.hsplit(harr, 3)拆分后:
    [array([[4., 7.],
           [6., 3.]]), array([[6., 3.],
           [6., 7.]]), array([[2., 6.],
           [9., 7.]])]

    numpy.vsplit

    第一个数组:
    [[ 0  1  2  3]
     [ 4  5  6  7]
     [ 8  9 10 11]
     [12 13 14 15]]
    np.vsplit(a,2)竖直分割:
    [array([[0, 1, 2, 3],
           [4, 5, 6, 7]]), array([[ 8,  9, 10, 11],
           [12, 13, 14, 15]])]
  • 数组元素的添加与删除 numpy.resize

    函数 numpy.resize(arr, shape) 返回指定大小的新数组。如果新数组大小大于原始大小,则包含原始数组中的元素的副本。

    numpy.append

    函数numpy.append(arr, values, axis=None) 在数组的末尾添加值。 追加操作会分配整个数组,并把原来的数组复制到新数组中。 输入数组的维度必须匹配否则将生成ValueError。

    arr:输入数组;values:要向arr添加的值,需要和arr形状相同(除了要添加的轴);axis:默认为 None。当axis无定义时,是横向加成,返回总是为一维数组!当axis有定义的时候,分别为0和1的时候。当axis有定义的时候,分别为0和1的时候(列数要相同)。当axis为1时,数组是加在右边(行数要相同)。

    append 函数返回的始终是一个一维数组。

    a = np.array([[1,2,3],[4,5,6]])
    print (np.append(a, [7,8,9]))
    print (np.append(a, [[7,8,9]],axis = 0))
    print (np.append(a, [[5,5,5],[7,8,9]],axis = 1))
    第一个数组:
    [[1 2 3]
     [4 5 6]]
    向数组添加元素:
    [1 2 3 4 5 6 7 8 9]
    沿轴 0 添加元素:
    [[1 2 3]
     [4 5 6]
     [7 8 9]]
    沿轴 1 添加元素:
    [[1 2 3 5 5 5]
     [4 5 6 7 8 9]]

    numpy.insert

    函数numpy.insert(arr, obj, values, axis) 在给定索引之前,沿给定轴在输入数组中插入值。 如果值的类型转换为要插入,则它与输入数组不同。 插入没有原地的,函数会返回一个新数组。 此外,如果未提供轴,则输入数组会被展开。

    arr:输入数组;obj:在其之前插入值的索引;values:要插入的值;axis:沿着它插入的轴,如果未提供,则输入数组会被展开。该操作会广播值数组来配输入数组。

    a = np.array([[1,2],[3,4],[5,6]])
    print (a)
    print (np.insert(a,3,[11,12]))
    print (np.insert(a,1,[11],axis = 0))
    print (np.insert(a,1,11,axis = 1))
    第一个数组:
    [[1 2]
     [3 4]
     [5 6]]
    未传递 Axis 参数。 在插入之前输入数组会被展开。
    [ 1  2  3 11 12  4  5  6]
    传递了 Axis 参数。 会广播值数组来配输入数组。
    沿轴 0 广播:
    [[ 1  2]
     [11 11]
     [ 3  4]
     [ 5  6]]
    沿轴 1 广播:
    [[ 1 11  2]
     [ 3 11  4]
     [ 5 11  6]]

    numpy.delete

    函数Numpy.delete(arr, obj, axis) 返回从输入数组中删除指定子数组的新数组。 与 insert() 函数的情况一样,如果未提供轴参数,则输入数组将展开。

    arr:输入数组;obj:可以被切片,整数或者整数数组,表明要从输入数组删除的子数组;axis:沿着它删除给定子数组的轴,如果未提供,则输入数组会被展开。

    a = np.arange(12).reshape(3,4)
    print (a)
    print (np.delete(a,5))
    print (np.delete(a,1,axis = 0))
    print (np.delete(a,1,axis = 1))
    a = np.array([1,2,3,4,5,6,7,8,9,10])
    print (np.delete(a, np.s_[::2])) # np.s_[::2] = slice(none,none,2)
    第一个数组:
    [[ 0  1  2  3]  # 第一行
     [ 4  5  6  7]  # 第二行
     [ 8  9 10 11]]
    未传递 Axis 参数。 在删除之前输入数组会被展开。
    [ 0  1  2  3  4  6  7  8  9 10 11]
    删除第二行:
    [[ 0,  1,  2,  3],
     [ 8,  9, 10, 11]]
    删除第二列:
    [[ 0  2  3]
     [ 4  6  7]
     [ 8 10 11]]
    包含从数组中删除的替代值的切片:
    [ 2  4  6  8 10]

    numpy.unique

    函数numpy.unique(arr, return_index, return_inverse, return_counts) 用于去除数组中的重复元素。

    arr:输入数组,如果不是一维数组则会展开;return_index:如果为true,返回新列表元素在旧列表中的位置(下标),并以列表形式存储;return_inverse:如果为true,返回旧列表元素在新列表中的位置(下标),并以列表形式存储;return_counts:如果为true,返回去重数组中的元素在原数组中的出现次数。

    a = np.array([5,2,6,2,7,5,6,8,2,9])
    print (a)
    第一个数组:
    [5 2 6 2 7 5 6 8 2 9]
    
    u,indices = np.unique(a, return_index = True)
    print(u)
    print (indices)
    第一个数组的去重值:
    [2 5 6 7 8 9]
    去重数组的索引数组:
    [1 0 2 4 7 9]
    
    u,indices = np.unique(a,return_inverse = True)
    print (u)
    print (indices)
    print (u[indices])
    去重数组的下标:
    [2 5 6 7 8 9]
    下标为:
    [1 0 2 0 3 1 2 4 0 5]
    使用下标重构原数组:
    [5 2 6 2 7 5 6 8 2 9]
    
    u,indices = np.unique(a,return_counts = True)
    print (u)
    print (indices)
    返回去重元素的重复数量:
    [2 5 6 7 8 9]
    [3 2 2 1 1 1]

位运算

bitwise_and 对数组元素执行位与操作 bitwise_or 对数组元素执行位或操作 invert 按位取反 left_shift 向左移动二进制表示的位 right_shift 向右移动二进制表示的位

注:也可以使用 “&”、 “~”、 “|” 和 “^” 等操作符进行计算。


字符串数组

NumPy 字符串函数,字符数组类(numpy.char)中定义了一些函数,这些函数用于对 dtype 为 numpy.string_ 或 numpy.unicode_ 的数组执行向量化字符串操作,它们基于 Python 内置库中的标准字符串函数。

numpy.char.add() 依次对两个数组的元素进行字符串连接 。

numpy.char.multiply() 对字符串执行多重连接。

np.char.multiply('geek-docs ',3) # geek-docs geek-docs geek-docs

numpy.char.center() 用于将字符串居中,并使用指定字符在左侧和右侧进行填充。

numpy.char.capitalize() 将字符串的第一个字母转换为大写 。

numpy.char.title() 将字符串的每个单词的第一个字母转换为大写 。

numpy.char.lower() 对数组的每个元素转换为小写。它对每个元素调用 str.lower 。

numpy.char.upper() 对数组的每个元素转换为大写。它对每个元素调用 str.upper 。

numpy.char.split() 指定分隔符对字符串进行分割,并返回数组。默认情况下,分隔符为空格。

numpy.char.splitlines() 以换行符作为分隔符来分割字符串,并返回数组。

numpy.char.strip() 用于移除开头或结尾处的特定字符。

numpy.char.join() 通过指定分隔符来连接数组中的元素或字符串 。

numpy.char.replace() 函数使用新字符串替换字符串中的所有子字符串。

numpy.char.encode() 对数组中的每个元素调用 str.encode 函数。 默认编码是'utf-8',可以使用标准 Python 库中的编解码器。

numpy.char.decode() 函数对编码的元素进行 str.decode() 解码。

a = np.char.encode('geek-docs', 'cp500')
print(a)  # b'\x87\x85\x85\x92`\x84\x96\x83\xa2'
print(np.char.decode(a, 'cp500')) # geek-docs

数学函数与计算

  • 三角函数

    cos cosh sin sinh tan tanh ( 一般三角函数和双曲函数

    arccos arccosh arcsin arcsinh arctan arctanh (反三角函数)

cos = np.cos(a*np.pi/180)
inv = np.arccos(cos)
np.degrees(inv)(弧度转化为度数)
  • 四舍五入函数

    numpy.around(array,decimals)

    decimals默认为0,n表示保留到小数点后n位,-n表示保留到小数点前n位置。

  • 向上、下取整

    numpy.ceil() numpy.floor()

  • 算数函数

    add() subtract() multiply() divide() 加减乘除

    numpy.reciprocal() 函数返回参数逐元素的倒数

    numpy.power() 第一个输入数组中的元素作为底数,第二个输入为幂

    numpy.mod() 求余,函数 numpy.remainder() 也产生相同的结果。

  • 统计函数

    (不使用axis参数则返回所有元素的最大、最小值)

    numpy.amin(arr, axis) 用于计算数组中的元素沿指定轴的最小值。

    numpy.amax(arr, axis) 用于计算数组中的元素沿指定轴的最大值。

    numpy.ptp(arr, axis) 计算数组中元素最大值与最小值的差(最大值 – 最小值)

    numpy.percentile(a, q, axis,keepdims=false)

    百分位数是统计中使用的度量,表示小于这个值的观察值的百分比。

    a是输入数组,q是计算的百分位数,axis为轴向,keepdims为true保持原形状。

    numpy.median() 函数用于计算数组 a 中元素的中位数(中值)

    numpy.mean()

    函数返回数组中元素的算术平均值。

    如果提供了轴,则沿其计算。算术平均值是沿轴的元素的总和除以元素的数量。

    numpy.average(arr, axis, weights, returned)

    函数根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值。 该函数可以接受一个轴参数。 如果没有指定轴,则数组会被展开。加权平均值即将各数值乘以相应的权数,然后加总求和得到总体值,再除以总的单位数。 如果 returned 参数设为 true,则返回 (average, sum_of_weights) 。

    numpy.std(a, axis=None, dtype=None)

    标准差是一组数据平均值分散程度的一种度量。标准差是方差的算术平方根。

    标准差的计算等同于 std = sqrt(mean(abs(x - x.mean())**2))

  • 排序函数

    numpy.sort(a, axis, kind, order)

    返回待排序数组的有序副本。kind 可以选择排序方法,默认quicksort,如果数组包含字段,则设置order根据字段排序。默认为升序排序降序排列( np.sort(arr)[::-1])。

    dt = np.dtype([('name',  'S10'),('age',  int)]) 
    a = np.array([("raju",21),("anil",25),("ravi",  17),  ("amar",27)], dtype = dt)  
    print (np.sort(a, order =  'name'))
    # 结果
    我们的数组是:
    [(b'raju', 21) (b'anil', 25) (b'ravi', 17) (b'amar', 27)]
    按 name 排序:
    [(b'amar', 27) (b'anil', 25) (b'raju', 21) (b'ravi', 17)]

    numpy.argsort() 函数返回的是数组值从小到大的索引值。

    x = np.array([3,  1,  2])
    y = np.argsort(x)
    x[y]
    我们的数组是:
    [3 1 2]
    对 x 调用 argsort() 函数,返回所以:
    [1 2 0]
    以排序后的索引,顺序重构原数组:
    [1 2 3]

    numpy.lexsort() 用于对多个序列进行排序,返回其索引。把它想象成对电子表格进行排序,每一列代表一个序列,排序时优先照顾靠后的列。

    小升初考试,重点班录取学生按照总成绩录取。在总成绩相同时,数学成绩高的优先录取,在总成绩和数学成绩都相同时,按照英语成绩录取…… 这里,总成绩排在电子表格的最后一列,数学成绩在倒数第二列,英语成绩在倒数第三列。

    nm =  ('raju','anil','ravi','amar') 
    dv =  ('f.y.',  's.y.',  's.y.',  'f.y.') 
    ind = np.lexsort((dv,nm))  
    print ('调用 lexsort() 函数:') 
    print (ind) 
    print ('使用这个索引来获取排序后的数据:') 
    print ([nm[i]  +  ", "  + dv[i]  for i in ind])
    
    调用 lexsort() 函数:
    [3 1 0 2]
    使用这个索引来获取排序后的数据:
    ['amar, f.y.', 'anil, s.y.', 'raju, f.y.', 'ravi, s.y.']

    msort(a)

    数组按第一个轴排序,返回排序后的数组副本,相等于 np.sort(a, axis=0)。

    >>> np.msort(result)
    array([[ 1,  1,  1,  1],
           [ 1,  2,  2,  4],
           [ 3,  8,  6,  5],
           [ 4,  9,  7,  6],
           [ 8, 12,  8,  7],
           [10, 12,  8, 12]])
    >>> result
    array([[ 1,  1,  7,  6],
           [ 8,  9,  2,  1],
           [ 4, 12,  8,  7],
           [ 1,  8,  1, 12],
           [10, 12,  6,  4],
           [ 3,  2,  8,  5]])
    >>> np.sort(result,axis = 0)
    array([[ 1,  1,  1,  1],
           [ 1,  2,  2,  4],
           [ 3,  8,  6,  5],
           [ 4,  9,  7,  6],
           [ 8, 12,  8,  7],
           [10, 12,  8, 12]])

    sort_complex(a) 对复数按照先实部后虚部的顺序进行排序。

    partition(a, kth[, axis, kind, order])

    指定一个数,对数组进行分区。

    np.partition 的工作流程可以看做是先对数组排序(升序),然后以索引是kth的元素为基准,将元素分成两部分,即大于该元素的放在其后面,小于该元素的放在其前面,这里有点类似于快排。常用于求一个数组的前k(k = kth+1求最小,k = kth求最大)个最值元素,时间复杂度很低 O(n) 。

    参考链接

    >>> result = np.random.randint(1, 13,(6,4))
    >>> result
    array([[ 1,  1,  7,  6],
           [ 8,  9,  2,  1],
           [ 4, 12,  8,  7],
           [ 1,  8,  1, 12],
           [10, 12,  6,  4],
           [ 3,  2,  8,  5]])
    >>> result1 = np.sort(result,axis=0)
    >>> result1
    array([[ 1,  1,  1,  1],
           [ 1,  2,  2,  4],
           [ 3,  8,  6,  5],
           [ 4,  9,  7,  6],
           [ 8, 12,  8,  7],
           [10, 12,  8, 12]])
    >>> result2 = np.partition(result, kth=1, axis=0)[:2]
    >>> result2  # 求每一列前k = 2小,所以参数kth = 1
    array([[1, 1, 1, 1],
           [1, 2, 2, 4]])
    >>> result3 = np.partition(result, kth=-2, axis=1)[::,-2:]
    >>> result3  # 求每一行最大k = 2个元素,
    array([[ 6,  7],
           [ 8,  9],
           [ 8, 12],
           [ 8, 12],
           [10, 12],
           [ 5,  8]])

    argpartition(a, kth[, axis, kind, order])

    类似上面的函数,常用于求一个数组的前k个最值元素的索引,可以通过关键字 kind 指定算法(默认"introselect"),沿着指定轴axis对数组进行分区。(introselect参考快排过程)

    import numpy as np
    a = np.array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
    print(np.argpartition(a, 4)) #将数组a中所有元素(包括重复元素)从小到大排列,比索引为第5的元素小的放在前面,大的放在后面(除了第五个元素,其余元素可能都是乱序的),输出新数组索引。
    >> [6 9 4 3 7 2 1 5 8 0]
    a[np.argpartition(a, 4)]     #输出新数组索引对应的数组
    >> array([0, 0, 3, 3, 4, 4, 4, 9, 6, 9])
    a[np.argpartition(a, -5)[-5:]] # 输出top5
    >> array([4, 4, 9, 6, 9])
    >>> result3 = result[np.c_[np.arange(result.shape[0]),np.arange(result.shape[0])],np.argpartition(result, kth=-2, axis=1)[:,-2:]]
    >>> result3 # 操作略复杂,直接partition可以得到一样的效果,两者相同
    array([[ 6,  7],
           [ 8,  9],
           [ 8, 12],
           [ 8, 12],
           [10, 12],
           [ 5,  8]])条件筛选函数
  • 条件筛选函数

    numpy.argmax()numpy.argmin() 返回最大值和最小值索引

    numpy.nonzero() 返回非0值索引

     # 对应两个两个维度的坐标我们的数组是:
    [[30 40  0]
     [ 0 20 10]
     [50  0 60]]
    调用 nonzero() 函数:
    (array([0, 0, 1, 1, 2, 2], dtype=int64), array([0, 1, 1, 2, 0, 2], dtype=int64)) # 对应两个两个维度的坐标

    numpy.where() 根据条件返回符合的元素的索引

    x = np.arange(9.).reshape(3,  3)  
    y = np.where(x >  3)  
    x[y] # 根据索引求原来的元素
    我们的数组是:
    [[0. 1. 2.]
     [3. 4. 5.]
     [6. 7. 8.]]
    大于 3 的元素的索引:
    (array([1, 1, 2, 2, 2]), array([1, 2, 0, 1, 2])) # y是元组
    使用这些索引来获取满足条件的元素:
    [4. 5. 6. 7. 8.]

    numpy.extract() 也是返回一定满足一定条件的元素。

    >>> arr = np.arange(12).reshape((3, 4))
    >>> arr
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11]])
    >>> condition = np.mod(arr, 3)==0
    >>> condition
    array([[ True, False, False,  True],
           [False, False,  True, False],
           [False,  True, False, False]])
    >>> np.extract(condition, arr)
    array([0, 3, 6, 9])
    # condition是布尔型的,等价于array[condition]
  • 字节交换

    numpy.ndarray.byteswap() 大小端的转化,参数为True

  • NumPy 副本和视图

    np.ndarray.view() 创建一个新的数组对象,该方法创建的新数组的维数改变不会更改原始数据的维数。修改元素会改变原始值。

    但是, 使用切片创建视图修改数据会影响到原始数组 。

    arr = np.arange(12)
    arr
    a=arr[3:]
    b=arr[3:]
    a[1]=123
    b[2]=234
    arr
    id(a),id(b),id(arr[3:])
    我们的数组:
    [ 0  1  2  3  4  5  6  7  8  9 10 11]
    创建切片:
    [  0   1   2   3 123 234   6   7   8   9  10  11]
    2142679040208 2142679040288 2142816278048
    # 变量 a,b 都是 arr 的一部分视图,对视图的修改会直接反映到原数据中。但是我们观察 a,b 的 id,他们是不同的,也就是说,视图虽然指向原数据,但是他们和赋值引用还是有区别的。

    np.ndarray.copy() 创建一个副本,对副本数据进行修改,不会影响原始数据,物理内存不在一个位置。

    无复制: 简单的赋值 不会创建数组对象的副本。 相反,它使用原始数组的相同id()来访问它。 id()返回 Python 对象的通用标识符,类似于 C 中的指针。此外,一个数组的任何变化都反映在另一个数组上。 例如,一个数组的形状改变也会改变另一个数组的形状。


矩阵

简介

NumPy 矩阵库(Matrix),NumPy 中包含了一个矩阵库 numpy.matlib,该模块中的函数返回的是一个矩阵,而不是 ndarray 对象。一个 m x n 的矩阵是一个由m行(row)n列(column)元素排列成的矩形阵列。

相关函数

  • 创建矩阵

    numpy.matlib.empty(shape, dtype, order) 创建矩阵,填充伪随机数(通常非常小)。

    numpy.matlib.zeros()

    numpy.matlib.ones()

    numpy.matlib.eye(n, M,k, dtype) 函数返回一个矩阵,对角线元素为 1,其他位置为零。创建一个n*M的矩阵,为对角线索引。

    >>> import numpy.matlib
    >>> print (np.matlib.eye(n =  3, M =  4, k =  0, dtype =  float))
    [[1. 0. 0. 0.]
     [0. 1. 0. 0.]
     [0. 0. 1. 0.]]
    >>> print (np.matlib.eye(n =  3, M =  4, k =  1, dtype =  float))
    [[0. 1. 0. 0.]
     [0. 0. 1. 0.]
     [0. 0. 0. 1.]]
    >>> print (np.matlib.eye(n =  3, M =  4, k =  -1, dtype =  float))
    [[0. 0. 0. 0.]
     [1. 0. 0. 0.]
     [0. 1. 0. 0.]]

    numpy.matlib.identity() 创建单位矩阵

    numpy.matlib.rand() 创建一个矩阵,用[0,1)之间伪随机数填充。

    可以使用 np.asmatrix()np.asarray() 互相转化。

  • 矩阵运算

    numpy.dot() 两个数组的点积,即元素对应相乘。

    对于两个一维数组,计算的是这两个数组对应下标元素的乘积和(数学上称之为内积);对于二维数组,计算的是两个数组的矩阵乘积;对于多维数组,它的通用计算公式如下,即结果数组中的每个元素都是:数组a的最后一维上的所有元素与数组b的倒数第二位上的所有元素的乘积和。

    dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])。
    numpy.dot(a, b, out=None)

    numpy.vdot() 两个向量的点积。

    函数是两个向量的点积。 如果第一个参数是复数,那么它的共轭复数会用于计算。 如果参数是多维数组,它会被展开,计算之后得到的是一个标量值。、

    a = np.array([[1,2],[3,4]])
    b = np.array([[11,12],[13,14]])
    # vdot 将数组展开计算内积
    print (np.vdot(a,b)) # 130

    numpy.inner() 两个数组的内积。对于更高的维度,它返回最后一个轴上的和的乘积。

    >>> np.inner(np.array([1,2]),np.array([5,6]))
    17  # 一维数组
    >>> np.inner(np.array([[1,2],[3,4]]),np.array([[5,6],[7,8]]))
    array([[17, 23],
           [39, 53]]) # 多维数组

    numpy.matmul() 两个数组的矩阵积。

    虽然它返回二维数组的正常乘积,但如果任一参数的维数大于2,则将其视为存在于最后两个索引的矩阵的栈,并进行相应广播。 另一方面,如果任一参数是一维数组,则通过在其维度上附加 1 来将其提升为矩阵,并在乘法之后被去除。对于二维数组,它就是矩阵乘法:

    a = [[1,0],[0,1]] 
    b = [[4,1],[2,2]] 
    print (np.matmul(a,b))
    [[4  1]
     [2  2]]
    # 二维
    a = [[1,3],[2,4]] 
    b = [1,2] 
    print (np.matmul(a,b))
    print (np.matmul(b,a))
    [7  10] 
    [5  11]
    # 三维
    a = np.arange(8).reshape(2,2,2) 
    b = np.arange(4).reshape(2,2) 
    print (np.matmul(a,b))
    [[[ 2  3]
      [ 6 11]]
     [[10 19]
      [14 27]]]

    numpy.linalg.det() 数组的行列式。

    numpy.linalg.solve() 求解线性矩阵方程。AX = B或者X = A^(-1)B

    numpy.linalg.inv() 计算矩阵的乘法逆矩阵。


其他

IO及磁盘存储

​ Numpy可以读写磁盘上的文本数据或二进制数据,NumPy 为 ndarray 对象引入了一个简单的文件格式(.npy)。npy 文件用于存储重建 ndarray 所需的数据、图形、dtype 和其他信息。

numpy.save() 和 numpy.load()

函数 numpy.save(file, arr, allow_pickle=True, fix_imports=True) 可以存储数组为".npy"格式。

numpy.savez(file, *args, **kwds)

a = np.array([[1,2,3],[4,5,6]])
b = np.arange(0, 1.0, 0.1)
c = np.sin(b)
# c 使用了关键字参数 sin_array
np.savez("geek-docs.npz", a, b, sin_array = c)
r = np.load("geek-docs.npz")
print(r.files) # 查看各个数组名称
print(r["arr_0"]) # 数组 a
print(r["arr_1"]) # 数组 b
print(r["sin_array"]) # 数组 c
# 输出
['sin_array', 'arr_0', 'arr_1']
[[1 2 3]
 [4 5 6]]
[0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
[0.         0.09983342 0.19866933 0.29552021 0.38941834 0.47942554
 0.56464247 0.64421769 0.71735609 0.78332691]

numpy.savetxt(FILENAME, a, fmt="%d", delimiter=",")

numpy.loadtxt(FILENAME, dtype=int, delimiter=' ')

以简单的文本文件格式(.txt)存储数据, 参数 delimiter 可以指定各种分隔符、针对特定列的转换器函数、需要跳过的行数等。

a=np.arange(0,10,0.5).reshape(4,-1)
np.savetxt("out.txt",a,fmt="%d",delimiter=",") # 改为保存为整数,以逗号分隔
b = np.loadtxt("out.txt",delimiter=",") # load 时也要指定为逗号分隔
print(b)
# 输出
[[0. 0. 1. 1. 2.]
 [2. 3. 3. 4. 4.]
 [5. 5. 6. 6. 7.]
 [7. 8. 8. 9. 9.]]

Matplotlib

学习链接1

  • 中文显示 参考链接

    Matplotlib 默认情况不支持中文,我们可以使用以下简单的方法来解决 :

    zhfont = matplotlib.font_manager.FontProperties(fname=r"c:\windows\fonts\simsun.ttc")

    然后可以设置参数: fontproperties=zhfont`

    或者修改全局字体: plt.rcParams['font.family']=['FontName']

  • 线形 链接

    字符 描述
    '-' 实线样式
    '--' 短横线样式
    '-.' 点划线样式
    ':' 虚线样式
    '.' 点标记
    ',' 像素标记
    'o' 圆标记
    'v' 倒三角标记
    '^' 正三角标记
    '<' 左三角标记
    '>' 右三角标记
    '1' 下箭头标记
    '2' 上箭头标记
    '3' 左箭头标记
    '4' 右箭头标记
    's' 正方形标记
    'p' 五边形标记
    '*' 星形标记
    'h' 六边形标记 1
    'H' 六边形标记 2
    '+' 加号标记
    'x' X 标记
    'D' 菱形标记
    'd' 窄菱形标记
    '|' 竖直线标记
    '_' 水平线标记
  • 颜色

    字符 颜色
    'b' 蓝色
    'g' 绿色
    'r' 红色
    'c' 青色
    'm' 品红色
    'y' 黄色
    'k' 黑色
    'w' 白色
  • 绘制子图

    import numpy as np 
    import matplotlib.pyplot as plt 
    # 计算正弦和余弦曲线上的点的 x 和 y 坐标 
    x = np.arange(0,  3  * np.pi,  0.1) 
    y_sin = np.sin(x) 
    y_cos = np.cos(x)  
    # 建立 subplot 网格,高为 2,宽为 1  
    # 激活第一个 subplot
    plt.subplot(2,  1,  1)  
    # 绘制第一个图像 
    plt.plot(x, y_sin) 
    plt.title('Sine')  
    # 将第二个 subplot 激活,并绘制第二个图像
    plt.subplot(2,  1,  2) 
    plt.plot(x, y_cos) 
    plt.title('Cosine')  
    # 展示图像
    plt.show()

结构化数组

# numpy基本类型
bytes                 b1
int                   i1,i2,i4,i8
unsigned ints         u1,u2,u4,u8
floats                f2,f4,f8
complex               c8,c16
fixed length strings a<n>
import numpy as np

structured = np.array([(1, 'First', 0.5, 1+2j), 
                       (2, 'Second', 1.3, 2-2j),
                       (3, 'Third', 0.8, 1+3j)],
                      dtype=[('id','i2'), ('position','a6'), 
                             ('value','f4'), ('complex', 'c8')])
# 或者
structured = np.array([(1, 'First', 0.5, 1+2j), 
                       (2, 'Second', 1.3, 2-2j),
                       (3, 'Third', 0.8, 1+3j)], 
                      dtype=('i2, a6, f4, c8'))
#这里再单独指定字段名称
structured.dtype.names = ('id', 'order', 'value', 'complex')

print(structured['position'])# 指定字段名,否则自动分配f0,f1,f2

  1. 单元素元组表示(num,)括号内应当加上逗号,否则按照数值处理

  2. *args, **kwargs 这两个是python中的可变参数。*args表示任何多个无名参数,它是一个tuple;**kwargs 表示关键字参数,它是一个dict。并且同时使用*args**kwargs 时,必须*args参数列要在**kwargs前。

    参考链接

  3. 参考资料:https://numpy.org/devdocs/user/quickstart.html#


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!