数据类型和数组重建
常量
- numpy.nan:表示空值。两个
numpy.nan
是不相等的 numpy.isnan(x, *args, **kwargs)
返回布尔数组True/False Test element-wise for NaN and return result as a boolean array.- numpy.inf:表示正无穷大。
- numpy.pi: 表示圆周率
- numpy.e:表示自然常数
数据类型
常见数据类型
为了加以区分 numpy 在这些类型名称末尾都加了“_”。下表列举了常用 numpy 基本类型。
类型 | 备注 | 说明 |
---|---|---|
bool_ = bool8 | 8位 | 布尔类型 |
int8 = byte | 8位 | 整型 |
int16 = short | 16位 | 整型 |
int32 = intc | 32位 | 整型 |
int_ = int64 = long = int0 = intp | 64位 | 整型 |
uint8 = ubyte | 8位 | 无符号整型 |
uint16 = ushort | 16位 | 无符号整型 |
uint32 = uintc | 32位 | 无符号整型 |
uint64 = uintp = uint0 = uint | 64位 | 无符号整型 |
float16 = half | 16位 | 浮点型 |
float32 = single | 32位 | 浮点型 |
float_ = float64 = double | 64位 | 浮点型 |
str_ = unicode_ = str0 = unicode | Unicode 字符串 | |
datetime64 | 日期时间类型 | |
timedelta64 | 表示两个时间之间的间隔 |
创建数据类型
numpy 的数值类型实际上是 dtype 对象的实例。
每个内建类型都有一个唯一定义它的字符代码,如下:
字符 | 对应类型 | 备注 |
---|---|---|
b | boolean | ‘b1’ |
i | signed integer | ‘i1’(type:int8 itemsize:1), ‘i2’(int16 2), ‘i4’(32 4), ‘i8’ |
u | unsigned integer | ‘u1’, ‘u2’ ,‘u4’ ,‘u8’(同上) |
f | floating-point | ‘f2’(16 2), ‘f4’, ‘f8’ |
c | complex floating-point | |
m | timedelta64 | 表示两个时间之间的间隔 |
M | datetime64 | 日期时间类型 |
O | object | |
S | (byte-)string | S3(bytes_)表示长度为3的字符串 |
U | Unicode | Unicode (U3:dtype:str_,itemsize:12)字符串 |
V | void |
数据类型信息
Python 的浮点数通常是64位浮点数,几乎等同于 np.float64
。
NumPy和Python整数类型的行为在整数溢出方面存在显着差异,与 NumPy 不同,Python 的int
是灵活的。这意味着Python整数可以扩展以容纳任何整数并且不会溢出。
Machine limits for integer types.
ii16 = np.iinfo(np.int16)
print(ii16.min) # -32768
print(ii16.max) # 32767
Machine limits for floating point types.
ff16 = np.finfo(np.float16)
print(ff16.bits) # 16
print(ff16.min) # -65500.0
print(ff16.max) # 65500.0
print(ff16.eps) # 0.000977 #表示浮点相对精度 取非负的最小值
#具体作用和应用
eps = np.finfo(height.dtype).eps
height = np.maximum(height, eps)
dy = (base_ctr_y - ctr_y) / height
dh = xp.log(base_height / height)
dw = xp.log(base_width / width
这里可以看到有除法,我们要考虑到除法的分母是不能为0的,而且式子中log内也不能为负数,不然会直接跳出显示错误。
代码中是用上半部分来处理的,eps开始的三行将可能出现的负数和零,使用eps来替换,这样就不会出现错误了。
finfo函数是根据height.dtype类型来获得信息,获得符合这个类型的float型,eps是取非负的最小值。
时间日期和时间增量
datetime64 基础
在 numpy 中,我们很方便的将字符串转换成时间日期类型 datetime64
(datetime
已被 python 包含的日期时间库所占用)。
1秒 = 1000 毫秒
- 从字符串创建 datetime64 类型时,默认情况下,numpy 会根据字符串自动选择对应的单位,也可以强制指定使用的单位。
a = np.datetime64('2020-03', 'D')
- 从字符串创建 datetime64 数组时,如果单位不统一,则一律转化成其中最小的单位。
a = np.array(['2020-03', '2020-03-08', '2020-03-08 20:00'], dtype='datetime64')
print(a, a.dtype)
# ['2020-03-01T00:00' '2020-03-08T00:00' '2020-03-08T20:00'] datetime64[m]
- 使用
arange()
创建 datetime64 数组,用于生成日期范围。np.arange(‘2020-08-01’, ‘2020-08-10’, dtype=np.datetime64)
datetime64 和 timedelta64 运算
- timedelta64 表示两个 datetime64 之间的差。timedelta64 和相减运算中的两个 datetime64 中的较小的单位保持一致。
a = np.datetime64('2020-03') + np.timedelta64(20, 'D')
print(a, a.dtype) # 2020-03-21 datetime64[D]
-
生成 timedelta64时,要注意年(‘Y’)和月(‘M’)这两个单位无法和其它单位进行运算(一年有几天?一个月有几个小时?不确定)。
-
timedelta64 的运算
c = np.timedelta64(1, 'W')
d = np.timedelta64(1, 'D')
print(c / d) # 7.0
- numpy.datetime64(2020-06-01T20:05:30) 与 datetime.datetime(2020-06-01 20:05:30) 相互转换A.astype(B)
import numpy as np
import datetime
dt = datetime.datetime(year=2020, month=6, day=1, hour=20, minute=5, second=30)
dt64 = np.datetime64(dt, 's')
print(dt64, dt64.dtype)
# 2020-06-01T20:05:30 datetime64[s]
dt2 = dt64.astype(datetime.datetime)
print(dt2, type(dt2))
# 2020-06-01 20:05:30 <class 'datetime.datetime'>
datetime64 的应用
为了允许在只有一周中某些日子有效的上下文中使用日期时间,NumPy包含一组“busday”(工作日)功能。
numpy.busday_offset(dates, offsets, roll='raise', weekmask='1111100', holidays=None, busdaycal=None, out=None)
- 将指定的偏移量应用于工作日,单位天(‘D’)。计算下一个工作日,如果当前日期为非工作日,默认报错。可以指定
forward
或backward
规则来避免报错。(一个是向前取未来第一个有效的工作日,一个是向后取过去第一个有效的工作日)
可以指定偏移量为 0 来获取当前日期向前或向后最近的工作日,当然,如果当前日期本身就是工作日,则直接返回当前日期。
# 2020-07-10 星期五
a = np.busday_offset('2020-07-10', offsets=1)
print(a) # 2020-07-13
a = np.busday_offset('2020-07-11', offsets=1)
print(a) # ValueError: Non-business day date in busday_offset
a = np.busday_offset('2020-07-11', offsets=0, roll='forward')
print(a) # 2020-07-13
a = np.busday_offset('2020-07-11', offsets=1, roll='forward')
print(a) # 2020-07-14
-
返回指定日期是否是工作日:np.is_busday(‘2020-07-10’) # True
-
统计一个
datetime64[D]
数组中的工作日天数:np.count_nonzero(np.is_busday(a)) / 两个日期之间的工作日数量numpy.busday_count()
numpy.busday_count(begindates, enddates, weekmask='1111100', holidays=[], busdaycal=None, out=None)
Counts the number of valid days betweenbegindates
andenddates
, not including the day ofenddates
. -
自定义周掩码值,即指定一周中哪些星期是工作日:np.is_busday(‘2020-07-10’, weekmask=[1, 1, 1, 1, 1, 0, 0]) #True
数组的创建
numpy 提供的最重要的数据结构是ndarray
,它是 python 中list
的扩展。
1. 依据现有数据来创建 ndarray
-
(a)通过array()函数进行创建。
np.array([0, 1, 2, 3, 4]) -
(b)通过asarray()函数进行创建
array()
和asarray()
都可以将结构数据(list)转化为 ndarray(np.array([1,2])=np.asarray([1,2]))
但是array()
和asarray()
主要区别就是当数据源是ndarray 时,array()
仍然会 copy 出一个副本,占用新的内存(和改变前ndarray相同),但不改变 dtype 时 asarray()
不会。
import numpy as np
x = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]])
y = np.array(x)
z = np.asarray(x)
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
更改为较大的dtype时,其大小必须是array的最后一个axis的总大小(以字节为单位)的除数 ?!
import numpy as np
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.
- (c)通过fromfunction()函数进行创建
给函数绘图的时候可能会用到fromfunction()
,该函数可从函数中创建数组。
def fromfunction(function, shape, **kwargs):
import numpy as np
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]]
x = np.fromfunction(lambda i, j: i == j, (3, 3), dtype=int)
print(x)
# [[ True False False]
# [False True False]
# [False False True]]
x = np.fromfunction(lambda i, j: i + j, (3, 3), dtype=int)
print(x)
# [[0 1 2]
# [1 2 3]
# [2 3 4]]
2.随机初始化矩阵
zeros(shape) zeros_like(x)
-
zeros()
函数:返回给定形状和类型的零数组。 -
zeros_like()
函数:返回与给定数组形状和类型相同的零数组。 -
ones()
函数:返回给定形状和类型的1数组。 -
ones_like()
函数:返回与给定数组形状和类型相同的1数组。 -
empty()
函数:返回一个空数组,数组元素为随机数。 -
empty_like
函数:返回与给定数组具有相同形状和类型的新数组。 -
eye()
函数:返回一个对角线上为1,其它地方为零的单位数组。eye(4):4*4 -
identity()
函数:返回一个方的单位数组。 -
diag(v, k=0)
函数:提取对角线或构造对角数组。k表示对角线上方的第几条线(负数表示下方) np.diag(v)构造以v为对角线的数组 -
full(shape,const)
函数:返回一个常数数组。 -
full_like()
函数:返回与给定数组具有相同形状和类型的常数数组。
3. 利用数值范围来创建ndarray
arange()
函数:返回给定间隔内的均匀间隔的值。linspace()
函数:返回指定间隔内的等间隔数字。logspace()
函数:返回数以对数刻度均匀分布。 相当于 10 ** i for i in x (x是linspace产生的)numpy.random.rand()
返回一个由[0,1)内的随机数组成的数组。
x = np.logspace(0, 1, 5)
print(np.around(x, 2))
# [ 1. 1.78 3.16 5.62 10. ]
#np.around 返回四舍五入后的值,可指定精度。
# around(a, decimals=0, out=None)
# a 输入数组
# decimals 要舍入的小数位数。 默认值为0。 如果为负,整数将四舍五入到小数点左侧的位置
x = np.linspace(start=0, stop=1, num=5)
x = [10 ** i for i in x]
print(np.around(x, 2))
# [ 1. 1.78 3.16 5.62 10. ]
4. 结构数组的创建
结构数组,首先需要定义结构,然后利用np.array()
来创建数组,其参数dtype
为定义的结构。
- (a)利用字典来定义结构
personType = np.dtype({
'names': ['name', 'age', 'weight'],
'formats': ['U30', 'i8', 'f8']})
a = np.array([('Liming', 24, 63.9), ('Mike', 15, 67.), ('Jan', 34, 45.8)],
dtype=personType)
print(a, type(a))
# [('Liming', 24, 63.9) ('Mike', 15, 67. ) ('Jan', 34, 45.8)]
# <class 'numpy.ndarray'>
- (b)利用包含多个元组的列表来定义结构
import numpy as np
personType = np.dtype([('name', 'U30'), ('age', 'i8'), ('weight', 'f8')])
a = np.array([('Liming', 24, 63.9), ('Mike', 15, 67.), ('Jan', 34, 45.8)],
dtype=personType)
print(a, type(a))
# [('Liming', 24, 63.9) ('Mike', 15, 67. ) ('Jan', 34, 45.8)]
# <class 'numpy.ndarray'>
# 结构数组的取值方式和一般数组差不多,可以通过下标取得元素:
print(a[0])
# ('Liming', 24, 63.9)
print(a[-2:])
# [('Mike', 15, 67. ) ('Jan', 34, 45.8)]
# 我们可以使用字段名作为下标获取对应的值
print(a['name'])
# ['Liming' 'Mike' 'Jan']
print(a['age'])
# [24 15 34]
print(a['weight'])
# [63.9 67. 45.8]
数组的属性
在使用 numpy 时,你会想知道数组的某些信息。很幸运,在这个包里边包含了很多便捷的方法,可以给你想要的信息。
numpy.ndarray.ndim
用于返回数组的维数(轴的个数)也称为秩,一维数组的秩为 1,二维数组的秩为 2,以此类推。numpy.ndarray.shape
表示数组的维度,返回一个元组,这个元组的长度就是维度的数目,即ndim
属性(秩)。numpy.ndarray.size
数组中所有元素的总量,相当于数组的shape
中所有元素的乘积,例如矩阵的元素总量为行与列的乘积。numpy.ndarray.dtype
ndarray
对象的元素类型。numpy.ndarray.itemsize
以字节的形式返回数组中每一个元素的大小。
在ndarray
中所有元素必须是同一类型,否则会自动向下转换,int->float->str
。
b = np.array([1, 2, 3, 4, ‘5’])
print(b) # [‘1’ ‘2’ ‘3’ ‘4’ ‘5’]
部分练习
1.numpy是python中基于数组对象的科学计算库。
提炼关键字,可以得出numpy以下三大特点:
拥有n维数组对象;
拥有广播功能(后面讲到);
拥有各种科学计算API,任你调用;
print(0 * np.nan)# nan
print(np.nan == np.nan)# False
print(np.inf > np.nan)# False
print(np.nan - np.nan)# nan
print(0.3 == 3 * 0.1)# False
3.填充缺失的日期,使其成为连续的日期序列
import numpy as np
dates = np.arange('2020-02-01', '2020-02-10', 2, np.datetime64)
print(dates)
# ['2020-02-01' '2020-02-03' '2020-02-05' '2020-02-07' '2020-02-09']
out = []
for date, d in zip(dates, np.diff(dates)):
out.extend(np.arange(date, date + d))
fillin = np.array(out)
output = np.hstack([fillin, dates[-1]])
print(output)
# ['2020-02-01' '2020-02-02' '2020-02-03' '2020-02-04' '2020-02-05'
# '2020-02-06' '2020-02-07' '2020-02-08' '2020-02-09']
4.#得到当下时间日期
yesterday = np.datetime64('today', 'D') - np.timedelta64(1, 'D')
today = np.datetime64('today', 'D')
tomorrow = np.datetime64('today', 'D') + np.timedelta64(1, 'D')
5.#创建布尔数组
import numpy as np
arr = np.full([3, 3], True, dtype=np.bool)
print(arr)
# [[ True True True]
# [ True True True]
# [ True True True]]
6.创建一个二维数组,其中边界值为1,其余值为0
Z = np.ones((10,10))
Z[1:-1,1:-1] = 0
print(Z)
7.将本地图像导入并将其转换为numpy数组
import numpy as np
from PIL import Image
img1 = Image.open('Scarlett.jpg')
a = np.array(img1)
print(a.shape, a.dtype)
# (700, 500, 3) uint8
(700, 500, 3) uint8