注:为了节约行数,默认import numpy as np已经写在每段代码前,不再重复写入,如果有新的包引入,会在代码头部import
NumPy包括几个常量: np.inf、np.NINF、np.PZERO & np.NZERO、np.nan、np.e、np.pi、np.euler_gamma、np.newaxis
numpy中正无穷大一共有五种表现形式:Inf = inf = infty = Infinity = PINF
NumPy 使用IEEE二进制浮点算法标准(IEEE 754) 正无穷大不等于负无穷大。 但无穷大相当于正无穷大。
结果:
True True True True
结果:
-inf
正负零被认为是有限数
print(np.PZERO) print(np.NZERO)结果:
0.0 -0.0
非数值有三种表现形式:nan、NaN、NAN
Not a Number不等于无穷大。
结果:
False False False
表示两个非数值是不相等的
结果:
False False False
表示不同形式的非数值常量不等
结果:
[1.2 5. nan 1. 0. ] [False False True False False] 1 1 3
这里自定义了一个countNaN函数,先调用numpy的isnan方法,返回包含布尔变量的ndarray,然后继续使用numpy的count_nonzero方法,返回不是0(即False)的数量。
综上,countNaN函数返回的即是ndarray中nan的数量。
结果:
2.718281828459045
结果:
True True
突发奇想,想看一下np.e和打印的浮点数是否相等,结果发现无论是小数点后15位和小数点后25位,均判断相等,这里先抛出一个疑问。
结果:
3.141592653589793
结果:
0.5772156649015329
numpy.newaxis从字面上来理解就是用来创建新轴的,或者说是用来对array进行维度扩展的。
结果:
True
表示None和np.newaxis实际是一个常量,axis有轴的意思,我们可以通过几个例子看看为什么在numpy中引入newaxis常数:
axis 英[ˈæksɪs] 美[ˈæksɪs] n. 轴(旋转物体假想的中心线); (尤指图表中的) 固定参考轴线,坐标轴; 对称中心线(将物体平分为二);
到这里我们可以清楚,np.newaxis的作用就是给ndarray增加维度,放在前面就是在前面添加维度(把之前的一维变量提炼成新的二维变量中),放在后面就是在后面添加维度(把之前的一维变量打散,充当二维变量中的一维变量)
numpy 支持的数据类型比 Python 内置的类型要多很多,基本上可以和 C 语言的数据类型对应上,其中部分类型对应为 Python 内置的类型。下表列举了常用 NumPy 基本类型。为了区别于 Python 原生的数据类型,bool、int、float、complex、str 等类型名称末尾都加了 “_”:
print(numpy.dtype) 所显示的都是 NumPy 中的数据类型,而非 Python原生数据类型。 实际上是 dtype 对象的实例
#dtype源码 class dtype(object): def __init__(self, obj, align=False, copy=False): pass在这里,我们新建一个函数genDtype,用来生成查看不同数据类型,然后集中测试:
def genDtype(str): a = np.dtype(str) print(a.type) # <class 'numpy.bool_'> print(a.itemsize) #集中测试 strList = ['b1','i1','i2','i4','i8','u1','u2','u4','u8','f2','f4','f8','S','S3','U3'] for x in strList: genDtype(x)<class ‘numpy.bool_’> 1 <class ‘numpy.int8’> 1 <class ‘numpy.int16’> 2 <class ‘numpy.int32’> 4 <class ‘numpy.int64’> 8 <class ‘numpy.uint8’> 1 <class ‘numpy.uint16’> 2 <class ‘numpy.uint32’> 4 <class ‘numpy.uint64’> 8 <class ‘numpy.float16’> 2 <class ‘numpy.float32’> 4 <class ‘numpy.float64’> 8 <class ‘numpy.bytes_’> 0 <class ‘numpy.bytes_’> 3 <class ‘numpy.str_’> 12
我们注意到这里itemsize的单位是字节,值得注意的是类型为’S’的dtype大小为0,而’S3’大小为3,另外’U’的单个大小为4字节,即32位。
Python 的浮点数通常是64位浮点数,几乎等同于 np.float64。
NumPy和Python整数类型的行为在整数溢出方面存在显着差异,与 NumPy 不同,Python 的int 是灵活的。这意味着Python整数可以扩展以容纳任何整数并且不会溢出,这就是说numpy是有长度显示的,那么我们来看一下不同数据类型的显示范围。
#iinfo定义源码 class iinfo(object): def __init__(self, int_type): pass def min(self): pass def max(self): pass可以看到iinfo类的初始化参数里面有一个int_type,是提供给调用者使用。
结果显示:
-32768 32767 -2147483648 2147483647
同理,浮点数在numpy中也有范围限制,先看定义:
#finfo定义源码 class finfo(object): def _init(self, dtype):16 -65500.0 65500.0 0.000977 32 -3.4028235e+38 3.4028235e+38 1.1920929e-07
其中,eps是一个很小的非负数,除法的分母不能为0的,不然会直接跳出显示错误。使用eps将可能出现的零用eps来替换,这样不会报错。
本章我们学习Numpy数据类型的时间日期(datetime64)和时间增量(timedelta64)
在 numpy 中,我们很方便的将字符串转换成时间日期类型 datetime64(datetime 已被 python 包含的日期时间库所占用)。
datatime64是带单位的日期时间类型,其单位如下:
日期单位代码含义时间单位代码含义Y年h小时M月m分钟W周s秒D天ms毫秒--us微秒--ns纳秒--ps皮秒--fs飞秒--as阿托秒秒、毫秒、微bai秒、纳秒、皮秒、飞秒、阿托秒每两级之du间的换算进率为1000。
其中1阿托秒等于光飞越3粒氢阿子的时间。
比例上,一阿托秒之于一秒,如同一秒之于 317.1 亿年,约为宇宙年龄的两倍。
在这里,只用一个例子说明:
>>>a = np.datetime64('2020-10', 'D') >>>print(a) 2020-10-01我们再来判断一下‘2020-10’和‘2020-10-01’的关系:
>>>print(np.datetime64('2020-10') == np.datetime64('2020-10-01')) True由上例可以看出,2020-10 和 2020-10-01 所表示的其实是同一个时间。 事实上,如果两个 datetime64 对象具有不同的单位,它们可能仍然代表相同的时刻。并且从较大的单位(如月份)转换为较小的单位(如天数)是安全的。
可以看到,这里如果list中单位不统一,则统一用最详尽的方式表示日期(详尽效应)。
配合arrange函数,用于生成日期范围
>>>a = np.arange('2020-10', '2020-11', dtype='datetime64[D]') >>>print(a) ['2020-10-01' '2020-10-02' '2020-10-03' '2020-10-04' '2020-10-05' '2020-10-06' '2020-10-07' '2020-10-08' '2020-10-09' '2020-10-10' '2020-10-11' '2020-10-12' '2020-10-13' '2020-10-14' '2020-10-15' '2020-10-16' '2020-10-17' '2020-10-18' '2020-10-19' '2020-10-20' '2020-10-21' '2020-10-22' '2020-10-23' '2020-10-24' '2020-10-25' '2020-10-26' '2020-10-27' '2020-10-28' '2020-10-29' '2020-10-30' '2020-10-31']同理,年-年,月-月…的用法相同,不再赘述
另外,这种方式也满足详尽效应,例如:
>>>a = np.arange('2020-10-01 20', '2020-10-03', dtype='datetime64') >>>print(a) ['2020-10-01T20' '2020-10-01T21' '2020-10-01T22' '2020-10-01T23' '2020-10-02T00' '2020-10-02T01' '2020-10-02T02' '2020-10-02T03' '2020-10-02T04' '2020-10-02T05' '2020-10-02T06' '2020-10-02T07' '2020-10-02T08' '2020-10-02T09' '2020-10-02T10' '2020-10-02T11' '2020-10-02T12' '2020-10-02T13' '2020-10-02T14' '2020-10-02T15' '2020-10-02T16' '2020-10-02T17' '2020-10-02T18' '2020-10-02T19' '2020-10-02T20' '2020-10-02T21' '2020-10-02T22' '2020-10-02T23']上述代码,h和D的datetime64变量,仍然取h进行展开
跟【例三、1-2】不同的是,当用’W’去指定D类型的datetime64变量时,有如下规定:
1)如果是星期四,返回当天; 2)否则,返回上一个星期四的日期
timedelta64 表示两个 Datetime64 之间的差。timedelta64 也是带单位的,并且和相减运算中的两个 Datetime64 中的较小的单位保持一致。(详尽效应)
>>>a = np.datetime64('2020-10-20') - np.datetime64('2020-10-19') >>>b = np.datetime64('2020-10-20') - np.datetime64('2020-10-19 09:00') >>>c = np.datetime64('2020-10-20') - np.datetime64('2020-10-18 23:00', 'D') >>>print(a, a.dtype) >>>print(b, b.dtype) >>>print(c, c.dtype) 1 days timedelta64[D] 900 minutes timedelta64[m] 2 days timedelta64[D]第三行同【例三、1-2】,'D’限制了天数之后的展示
下面是Datetime64 和 Timedelta64 运算:
>>>a = np.datetime64('2020-10') + np.timedelta64(20, 'D') >>>print(a,a.dtype) 2020-10-21 datetime64[D]年(‘Y’)和月(‘M’)这两个单位是经过特殊处理的,它们无法和其他单位进行运算,一年有几天?一个月有几天?这些都是不确定的,比如:
>>>a = np.timedelta64(1, 'M') >>>b = np.timedelta64(a, 'D') TypeError: Cannot cast NumPy timedelta64 scalar from metadata [M] to [D] according to the rule 'same_kind'datetime 模块是python中提供用于处理日期和时间的类。
在支持日期时间数学运算的同时,实现的关注点更着重于如何能够更有效地解析其属性用于格式化输出和数据操作。
>>>import datetime >>>dt = datetime.datetime(2020, 10, 20) >>>dt64 = np.datetime64(dt, 'D') >>>print(dt64, dt64.dtype) >>>dt2 = dt64.astype(datetime.datetime) >>>print(dt2,type(dt2)) 2020-10-20 datetime64[D] 2020-10-20 <class 'datetime.date'>可以看到,我们可以直接用np.datetime64(datetime,dtype)来实现从后者到前者的转换,另外,我们可以通过datetime64.astype(datetime.datetime)实现从前者到前者的转换
为了允许在只有一周中某些日子有效的上下文中使用日期时间,NumPy包含一组“busday”(工作日)功能。
将指定的偏移量(offsets)应用于工作日,单位天(‘D’),偏移量为正表示朝着日历向后的方向
可以指定偏移量为 0 来获取当前日期向前或向后最近的工作日,当然,如果当前日期本身就是工作日,则直接返回当前日期。如果当前日期为非工作日,默认报错。可以指定 forward 或 backward 规则来避免报错。 (注:forward指的是日历向后,backward指的是日历向前,如果从字面意思容易弄混)
小技巧:第一步先判断当天是否有工作日,若是则进行偏移;若不是,则需要根据
a和b的组合效果等于c,都是在计算一段日期范围的工作日天数,且前闭后开
如上,weekmask一共有三种设置方式,这里需要注意的是系统默认与真实世界的日历一一对应,即1970-01-01为星期四,是不是很有趣呢?
NumPy 中定义的最重要的对象是称为 ndarray 的 N 维数组类型,它是描述相同类型的元素集合。ndarray 中的每个元素都是数据类型对象(dtype)的对象。ndarray 中的每个元素在内存中使用相同大小的块
ndarray的含义是The N-dimensional array,意思就是N维数组
【例1-1】通过array()函数进行创建
>>>datas = [x for x in range(5)] # 创建一维数组 >>>a = np.array(datas) >>>b = np.array(tuple(datas)) >>>print(a, type(a)) >>>print(b, type(b)) >>>print(a.shape,b.shape) [0 1 2 3 4] <class 'numpy.ndarray'> [0 1 2 3 4] <class 'numpy.ndarray'> (5,) (5,) # 创建二维数组 >>>c = np.array([a]*2) >>>print(c, type(c)) [[0 1 2 3 4] [0 1 2 3 4]] <class 'numpy.ndarray'> (2, 5)我们可以看到使用array时,传入的数据类型可以是list,也可以是tuple。有一个小技巧n维数组的array()内的左括号数等于n,例如:
array()和asarray()都可以将结构数据转化为 ndarray,但是array()和asarray()主要区别就是当数据源是ndarray 时,array()仍然会 copy 出一个副本,占用新的内存,但不改变 dtype 时 asarray()不会。
如果改变dtype,例如int转成float,那么不用占用新的内存,即保持一致。
def asarray(a, dtype=None, order=None): return array(a, dtype, copy=False, order=order) #`array()`和`asarray()`都可以将结构数据转化为 ndarray >>>x = [[1, 1, 1], [1, 1, 1], [1, 1, 1]] >>>y = np.array(x) >>>z = np.asarray(x) >>>#改变x的数据 >>>x[1][2] = 2 >>>print(x,type(x)) [[1, 1, 1], [1, 1, 2], [1, 1, 1]] <class 'list'> >>>print(y,type(y)) [[1 1 1] [1 1 1] [1 1 1]] <class 'numpy.ndarray'> >>>print(z,type(z)) [[1 1 1] [1 1 1] [1 1 1]] <class 'numpy.ndarray'> #当数据源是ndarray时 >>>x = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]]) >>>y = np.array(x) >>>z = np.asarray(x) >>>w = np.asarray(x, dtype=np.int) >>>x[1][2] = 2 >>>print(x,type(x),x.dtype) [[1 1 1] [1 1 2] [1 1 1]] <class 'numpy.ndarray'> int32 >>>print(y,type(y),y.dtype) [[1 1 1] [1 1 1] [1 1 1]] <class 'numpy.ndarray'> int32 >>>print(z,type(z),z.dtype) [[1 1 1] [1 1 2] [1 1 1]] <class 'numpy.ndarray'> int32 >>>print(w,type(w),w.dtype) [[1 1 1] [1 1 2] [1 1 1]] <class 'numpy.ndarray'> int32可见w随着x的变化而变化,而不是在一个新的内存中
#更改为较大的dtype时,其大小必须是array的最后一个axis的总大小(以字节为单位)的除数 >>>x = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]]) >>>print(x, x.dtype) [[1 1 1] [1 1 1] [1 1 1]] int32 >>>x.dtype = np.float # ValueError: When changing to a larger dtype, its size must be a divisor of the total size in bytes of the last axis of the array.怎么理解上面的错误,很简单,画个图示意一下:
假设我们之前有4个int8,总共32个单位,那么新的dtype可以是int16,可以是int32,但是不能是int64,因为int64装完32之后还有空余。
给函数绘图的时候可能会用到fromfunction(),该函数可从函数中创建数组。
def fromfunction(function, shape, **kwargs): #通过在每个坐标上执行一个函数来构造数组 >>>def f(x, y): >>> return 10 * x + y >>>x = np.fromfunction(f, (5, 4), dtype=int) >>>print(x) [[ 0 1 2 3] [10 11 12 13] [20 21 22 23] [30 31 32 33] [40 41 42 43]]上述的f也可以直接替换为lambda函数, 即np.fromfunction(lambda i, j: 10*i+j, (5, 5), dtype=int)
在机器学习任务中经常做的一件事就是初始化参数,需要用常数值或者随机值来创建一个固定大小的矩阵。
1数组的用法和零数组相同,不加赘述
【例】
>>>x = np.empty(5) >>>print(x) [0. 0. 0. 0. 0.] >>>x = np.empty((3, 2)) >>>print(x) [[0. 0.] [0. 0.] [0. 0.]]注:当参数是ndarray时,表示提取对角线;参数是list时,表示构建对角数组
结构数组,首先需要定义结构,然后利用np.array()来创建数组,其参数dtype为定义的结构。
只需将
{ 'names': ['name', 'age', 'weight'],'formats': ['U30', 'i8', 'f8']}
填入dtype中即可
# 结构数组的取值方式和一般数组差不多,可以通过下标取得元素: >>>print(a[0]) ('ZhangSan', 25, 5) >>>print(a[-1]) ('WangWu', 24, 7) # 我们可以使用字段名作为下标获取对应的值 >>>print(a['name']) ['ZhangSan' 'LiSi' 'WangWu']在学过数组的创建之后,需要对数组进行进一步的了解,可以先从数组属性入手,Numpy中比较重要的数组属性如下:
属性说明ndarray.ndim秩,即轴的数量或维度的数量ndarray.shape数组的维度,对于矩阵,n 行 m 列ndarray.size数组元素的总个数,相当于 .shape 中 n*m 的值ndarray.dtypendarray 对象的元素类型ndarray.itemsizendarray 对象中每个元素的大小,以字节为单位ndarray.flagsndarray 对象的内存信息ndarray.realndarray 元素的实部(复数的实部)ndarray.imagndarray 元素的虚部(复数的虚部)ndarray.data包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。接下来让我们分别介绍。
NumPy 数组的维度(又称维数)称为秩(rank),一维数组的秩为 1,二维数组的秩为 2,以此类推。 NumPy 中,每一个线性的数组称为是一个轴(axis),也就是维度(dimensions)。
我们首先创建了一个1维Numpy数组a,数组元素有18个,通过ndarray.ndim属性可以查看数组a的维数是1。然后通过reshape方法生成数组b(注:此时数组a不被改变),然后打印数组b的维数为3。
可以看到shape属性可以返回数组的维度,在上述案例中,shape返回的是一个元组tuple。我们可以通过直接设置shape或者reshape改变一个数组的shape,请注意后者不直接改变原数组,而是生成一个新数组,如c生成了d,但是c本身没有变化,直到我们通过c.shape = (3,2)改变了它。
这里我们新建一个getSize函数,用来利用list新建ndarray数组并且返回其size。
这个在前面的数据类型里面有介绍,不加赘述。
可以看到int8型数组元素大小为1字节,float64型数组元素大小为8字节。
这里比较重要的是 flags.owndata 属性,它表示该数组是否拥有数据,会配合后面的深浅复制使用。
np.sqrt是numpy提供的求平方根的方法,运算后我们利用real和imag提取的实部和虚部
由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。
NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
NumPy 的前身 Numeric 最早是由 Jim Hugunin 与其它协作者共同开发,2005 年,Travis Oliphant 在 Numeric 中结合了另一个同性质的程序库 Numarray 的特色,并加入了其它扩展而开发了 NumPy。NumPy 为开放源代码并且由许多协作者共同维护开发。
NumPy 是一个运行速度非常快的数学库,主要用于数组计算,包含:
一个强大的N维数组对象 ndarray广播功能函数整合 C/C++/Fortran 代码的工具线性代数、傅里叶变换、随机数生成等功能以Windows10系统为例,可以通过PyCharm等IDE搭建Python环境,然后再安装numpy,即可运行,也可以先搭建Anaconda环境,然后再通过Anaconda去下载numpy包,然后即可切换环境后在终端运行:
Win10利用Anaconda搭建Numpy环境
n维数组对象(ndarray)为numpy特有的一种数据类型,是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。
ndarray 对象是用于存放同类型元素的多维数组。
ndarray 中的每个元素在内存中都有相同存储大小的区域。
给定一个ndarray对象a,可以通过其a.ndim判断其维数,也可以通过len(b.shape)从维度间接判断
(提示: NaN = not a number, inf = infinity)
0 * np.nan #nan
np.nan == np.nan #False
np.inf > np.nan #False
np.nan - np.nan #nan
0.3 == 3 * 0.1 #False
dt64 = np.datetime64(’’) 【知识点:时间日期和时间增量】
>>>import datetime as datetime >>>dt64 = np.datetime64('2020-02-25 22:10:10') >>>x = dt64.astype(datetime.datetime) >>>print(x,type(x)) 2020-02-25 22:10:10 <class 'datetime.datetime'>dates = np.arange(‘2020-02-01’, ‘2020-02-10’, 2, np.datetime64) 【知识点:时间日期和时间增量、数学函数】 如何填写不规则系列的numpy日期中的缺失日期?
#求第一天和最后一天的日期差 >>>x = dates[-1]-dates[0] #生成一个一天的timedelta64 >>>incre = np.timedelta64(1, 'D') #计算要求的完整序列的长度 >>>num = int(x/incre) #生成完整日期List >>>result = [dates[0] + x*incre for x in range(num)] #List转成ndarray >>>totalDates = np.array(result) >>>print(totalDates) ['2020-02-01' '2020-02-02' '2020-02-03' '2020-02-04' '2020-02-05' '2020-02-06' '2020-02-07' '2020-02-08']【知识点:时间日期】
(提示: np.datetime64, np.timedelta64)
>>>x = datetime.datetime.today() >>>today = np.datetime64(x,'D') >>>incre = np.timedelta64(1, 'D') >>>yesterday = today - incre >>>tomorrow = today + incre >>>print(yesterday,today,tomorrow) 2020-10-21 2020-10-22 2020-10-23【知识点:数组的创建】
如何创建一维数组?
>>>result = np.arange(10) >>>print(result) [0 1 2 3 4 5 6 7 8 9]【知识点:数组的创建】
如何创建一个布尔数组?
>>>result = np.array([[True]*3]*3) >>>print(result,result.shape) [[ True True True] [ True True True] [ True True True]] (3, 3)【知识点:数组的创建】
(提示: array[4])
>>>result = np.array([0]*10) >>>result[4] = 1 >>>print(result) [0 0 0 0 1 0 0 0 0 0]【知识点:创建数组】
(提示: np.arange)
>>>result = np.arange(10,50) >>>print(result) [10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49]【知识点:创建数组】
(提示: np.random.random)
>>>result = np.random.random([3,3,3]) >>>print(result) [[[0.88815829 0.6792094 0.65437638] [0.9102008 0.47790747 0.63524402] [0.71283903 0.75672497 0.79040022]] [[0.02198276 0.9277967 0.33374937] [0.39277658 0.57437309 0.54687669] [0.9073761 0.36438679 0.28621699]] [[0.92801544 0.65969081 0.06107123] [0.0195701 0.87177567 0.35697029] [0.01177732 0.68109868 0.56746777]]]【知识点:二维数组的创建】
(提示: array[1:-1, 1:-1])
>>>result = np.ones([5,5]) >>>result[1:-1,1:-1] = 0 >>>print(result) [[1. 1. 1. 1. 1.] [1. 0. 0. 0. 1.] [1. 0. 0. 0. 1.] [1. 0. 0. 0. 1.] [1. 1. 1. 1. 1.]]注:[5,5]换成(5,5)也可以实现。
【知识点:数组的创建与属性】
如何在给定起始点、长度和步骤的情况下创建一个numpy数组序列?
>>>result = np.array([5+3*x for x in range(10)]) >>>print(result) [ 5 8 11 14 17 20 23 26 29 32]【知识点:数组的创建与属性】
如何将图像转换为numpy数组?
>>>from PIL import Image >>>img = Image.open('ace0.jpg') >>>a = np.array(img) >>>print(a.shape,type(a)) (500, 500, 3) <class 'numpy.ndarray'>至此,Task01全部结束,撒花完结