用于表示数据
1. NumPy库入门
在cmd命令安装NumPy包
pip install -i https://mirrors.aliyun.com/pypi/simple/ NumPy
python中调用NumPy库,运行没有报错,说明安装完成
import numpy as np
as np:将import的numpy给出一个别名,即引入模块的别名。这里可以去掉as np,也可将np改成其他的名字
尽管别名可以省略或者更改,但是建议使用上述约定的别名
1.1 数据的维度
维度:一组数据的组织形式
一维数据:由对等关系的有序或无序数据构成,一般采用线性方式组织。对应列表、数组、集合等概念
列表和数组:都是表示一组数据的有序结构。列表的数据类型可以不同,数组的数据类型相同
二维数据:由多个一维数据构成,是一维数据的组合形式。表格是电信的二维数据,其中表头可以是二维数据的一部分,也可是之外的部分
多维数据:由一维或二维数据在新维度上扩展而形成的
高维数据:仅利用最基本的二元关系展示数据间的复杂结构。对应键值对,如湖南-长沙、陕西-西安等
类型 | 数据的Python表示 | |
---|---|---|
一维数据 | 列表 | [1, 2, 3](有序) |
一维数据 | 集合 | {1, 2, 3}(无序) |
二维/多维 | 列表 | [[1, 2, 3], [1, 2, 3]] |
高维数据字典 | 字典 | {'键' : '值', '键' : '值'} |
高维数据字典 | 数据表示格式 | JSON、XML、YAML |
1.2 ndarray
ndarray是NumPy中的数组类型
1.2.1 NumPy:开源的Python科学计算基础库
1)提供一个强大的N维数组对象ndarray,也叫数组
2)提供一组广播功能的函数,用于数组之间计算
3)整合C/C++/Fortran代码,并且提供整合这些代码的工具
4)提供线性代数、傅里叶变换、随机数生成等功能
1.2.2 ndarray:N维数组对象
# ndarray对象定义
import numpy as np
a = np.arary([1, 2])
a = np.arary([[1, 2], [1,2]]) # 用[]将数据括起来
用以下例子表明numpy和正常运算的区别:计算A2+B3,A、B是一维数组
'''正常运算'''
def pySum():
a = [0, 1, 2, 3, 4]
b = [9, 8, 7, 6, 5]
c = []
for i in range(len(a)):
c.append(a[i]**2 + b[i]**3)
return c
print(pySum()) # [729, 513, 347, 225, 141]
'''numpy方法'''
import numpy as np
def npSum():
# 用np.array生成一个数组ab
a = np.array([0, 1, 2, 3, 4])
b = np.array([9, 8, 7, 6, 5])
c = a**2 + b**3
return c
print(npSum()) # [729, 513, 347, 225, 141]
- 数组对象可以去掉元素间运算所需的循环,使一维数据更像单个数据
- 设置专门的数组对象,提示运算速度
- 在科学计算中,一个维度所有数据的类型往往相同。所以数组对象采用相同的数据类型,有利于节省运算和存储空间
ndarray由2部分构成:实际的数据、表述这些数据的元数据(数据维度、数据类型等)
ndarray要求所以有元素类型相同(同质),数组下标从0开始
'''ndarray实例'''
import numpy as np
# 用np.arrary定义一个ndarray数组。ndarray在程序中的别名就是array
a = np.array([[0, 1, 2, 3, 4], [9, 8, 7, 6, 5]])
a # 直接显示时,会用array()来表明数组类型(如下图)
print(a) # 打印时用[]来表示维度关系,元素间以空格来分离
1.2.3 ndarray属性
ndarray的2个基本概念:1)轴(axis):保存数据的维度;2)秩(rank):轴的数量,或者维度的数量,即数组有多少个维度
轴和秩是描述ndarray类型的基本向量和方式
ndarray属性 | 说明 |
---|---|
.ndim |
秩 |
.shape |
尺度,对于矩阵n行m列 |
.size |
元素个数,相当于.shape 中n*m的值 |
.dtype |
元素类型 |
.itemsize |
每个元素大小,以字节为单位 |
import numpy as np
a = np.array([[0, 1, 2, 3, 4], [9, 8, 7, 6, 5]])
a.ndim # 2
a.shape # (2, 5)
a.size # 10
a.dtype # dtype('int32')【int32在基础的Python语法中并不存在,他是numpy定义的元素类型(具体见下表)】
a.itemsize # 4
ndarray元素类型
元素类型 | 说明 | 元素类型 | 说明 |
---|---|---|---|
bool | 布尔类型,True或False | uint8 | 8位无符号整数,取值:[0, 225] |
intp | 用于索引的整数 | uint16 | 16位无符号整数,取值:[0, 65535] |
intc | int32或int64 | uint32 | 32位无符号整数,取值:[0, 2^32-1] |
int8 | 8位字节长度的整数,取值:[-128, 127] | uint64 | 8位无符号整数,取值:[0, 2^64-1] |
int16 | 16位长度的整数,取值:[-32768, 32767] | float16 | 16位半精度浮点数:1位符号位,5位指数,10位尾数 |
int32 | 32位长度的整数,取值:[-2^31, 2^31-1] | float32 | 32位半精度浮点数:1位符号位,8位指数,23位尾数 |
inte64 | 字节长度的整数,取值:[-2^63, 2^63-1] | float64 | 64位半精度浮点数:1位符号位,11位指数,52位尾数 |
complex64 | 复数类型,实部和虚部都是32位浮点数 | complex128 | 复数类型,实部和虚部都是64位浮点数 |
Python语法仅支持整数、浮点数和复数3种数据类型
ndarray的元素多样性
- 能够符合在科学计算(数据多)对存储和性能的高要求
- 对元素类型精细定义,有助于NumPy合理使用存储空间并优化性能,且有助于程序员对程序的规模合理评估
ndarray最好是同质的数组类型,但也可以包含非同质的元素(如下代码)
import numpy as np
a = np.array([[0, 1, 2, 3, 4], [9, 8, 7, 6]])
a # array([list([0, 1, 2, 3, 4]), list([9, 8, 7, 6])], dtype=object)
a.ndim # 1
# .shape只看到2个元素,但是没有进一步分析
a.shape # (2,)
a.size # 2
# 非同质ndarray,将每个元素认为是一个对象类型(dtype('0'))
a.dtype # dtype('0')
a.itemsize # 8
非同质ndarray无法发挥UnmPy的优势,应该尽量避免
1.3 数组创建
ndarray数组创建方法
- Python中的列表、元组
- NumPy中的函数
- 字节流(raw bytes)
- 从文件中读取特定格式
1.3.1 从Python中的列表、元组创建ndarray数组
import numpy as np
# 直接将列表、元组当相关参数输入给np.array()函数
# 可以用dtype指定每个元素的数据类型【如果不指定,NumPy将根据读入的数据关联一个dtype类型】
a = np.array(list/tuple, dtype = np.float34)
只要元组和列表包含的数据个数相同,可以将列表和元组回合,一起混合使用,来创建
1.3.2 使用NumPy中的函数创建ndarray数组
函数 | 说明 |
---|---|
np.arange(n) | 类似range(),返回ndarray类型,元素从0-n-1(整数类型) |
np.ones(shape) | 根据shape生成一个全1数组,shape是元组类型(浮点数类型) |
np.zeros(shape) | 根据shape生成一个全0数组,shape是元组类型(浮点数类型) |
np.full(shape,val) | 根据shape生成一个数组,每个元素值都是val |
np.eye(n) | 创建一个正方的n*n单位矩阵,对角线为1,其余为0(浮点数类型) |
np.arange(10) # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.ones((3,6))
# Out[]: array([[1., 1., 1., 1., 1., 1.],
# [1., 1., 1., 1., 1., 1.],
# [1., 1., 1., 1., 1., 1.]])
np.zeros((3, 6), dtype=np.int32)
# Out[]: array([[0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0]])
np.eye(3)
# Out[]: array([[1., 0., 0.],
# [0., 1., 0.],
# [0., 0., 1.]])
# 生成多维数组。最外层有2个元素,每个元素有3个维度,每个维度有4个元素
x = np.ones((2,3,4))
x
# Out[]: array([[[1., 1., 1., 1.],
# [1., 1., 1., 1.],
# [1., 1., 1., 1.]],
# [[1., 1., 1., 1.],
# [1., 1., 1., 1.],
# [1., 1., 1., 1.]]])
x.shape # (2,3,4)[shape是由最外层到最内层表示]
np.full((2,3,4), 25, dtype=np.int)
# array([[[25, 25, 25, 25],
# [25, 25, 25, 25],
# [25, 25, 25, 25]],
# [[25, 25, 25, 25],
# [25, 25, 25, 25],
# [25, 25, 25, 25]]])
函数 | 说明 |
---|---|
np.ones_like(a) |
根据数组a的形状生成一个全1数组 |
np.zeros_like(a) |
根据数组a的形状生成一个全0数组 |
np.full_like(a, val) |
根据数组a的形状生成一个全val数组 |
np.linspace() |
根据起止数据等间距地填充数据 |
np.concatenate() |
将2个或多个数组合并成1个新数组 |
a = np.linspace(1, 10, 4)
a # array([ 1., 4., 7., 10.])[起始分别为1,10,一共4个数据),不限定数据类型时,生成的是浮点数]
# endpoint表示最后一个元素10是否是元素中的一个
b = np.linspace(1, 10, 4, endpoint = False)
b # array([1. , 3.25, 5.5 , 7.75])[在1-10之间等间距的生成一个新的值]
c = np.concatenate((a, b))
c # array([ 1. , 4. , 7. , 10. , 1. , 3.25, 5.5 , 7.75])
1.4 数组变换
维度变换
方法 | 说明 |
---|---|
.reshape(shape) | 不改变数组元素,返回一个shape形状的新数组(保证元素总体个数不发生改变) |
.resize(shape) | 与.reshape(shape)类似,但是替换原数组 |
.swapaxces(ax1, ax2) | 将数组n个维度中的2个维度进行调换 |
.flatten() | 对数组进行降维,返回折叠后的一维数组,原数组不变 |
a = np.ones((2,3,4), dtype=np.int32)
a
# array([[[1, 1, 1, 1],
# [1, 1, 1, 1],
# [1, 1, 1, 1]],
# [[1, 1, 1, 1],
# [1, 1, 1, 1],
# [1, 1, 1, 1]]])
# 将3维数组变为2维数组。都是24个元素个数,a未改变
a.reshape(3, 8)
# Out[]: array([[1, 1, 1, 1, 1, 1, 1, 1],
# [1, 1, 1, 1, 1, 1, 1, 1],
# [1, 1, 1, 1, 1, 1, 1, 1]])
# a已改变
a.resize(3, 8)
a
# Out[]: array([[1, 1, 1, 1, 1, 1, 1, 1],
# [1, 1, 1, 1, 1, 1, 1, 1],
# [1, 1, 1, 1, 1, 1, 1, 1]])
a.flatten()
# Out[]: array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
astype()
类型变换
# np.int:程序会将元素解析为整数类型,是int32还是int64,是由程序自动调节
a = np.ones((2,3,4), dtype=np.int)
a
# np.float代表一类浮点数类型
b = a.astype(np.float)
b
# array([[[1., 1., 1., 1.],
# [1., 1., 1., 1.],
# [1., 1., 1., 1.]],
# [[1., 1., 1., 1.],
# [1., 1., 1., 1.],
# [1., 1., 1., 1.]]])
astype()
方法一定会创建一个新的数组,即使定义一个与原数组类型相同的数组,也会有一个新的数组,即可利用这个特性进行拷贝数组
a.tolist()
方法将ndarray数组向列表转换
a = np.full((2,3,4), 25, dtype=np.int)
a
a.tolist() # [[[25, 25, 25, 25], [25, 25, 25, 25], [25, 25, 25, 25]], [[25, 25, 25, 25], [25, 25, 25, 25], [25, 25, 25, 25]]]
列表时Python中最原始的数据类型,可能在空间和运算速度比NumPy慢很多。但是更适合传统的或者原生的Python语言语法
1.4 ndarray操作
对数组的索引:获取数组中特定位置元素的过程
对数组的切片:获取数组元素子集的过程
一维数组的索引和切片(与python列表相似)
import numpy as np
a = np.array([1, 2, 3, 4, 5])
a[2] # 3
# 切片,[开始编号:终止编号(不含):步长]
a[1 : 4 : 2] # array([2, 4])
a # array([1, 2, 3, 4, 5])
多维数组的索引和切片
a = np.arange(24).reshape((2, 3, 4))
a
# 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]]])
# 索引,每个维度使用逗号分隔,[第一维度,第二维度,第三维度]
a[1, 2, 3] # 23
a[0, -1, 1] # 9
# 切片,不考虑第一维度,第二维度是1,第三维度是-3的元素
a[:, 1, -3] # array([ 5, 17])
# 切片,第一维度是1,第三维度是所有范围,但是以2为步长
a[1, :, :: 2]
# array([[12, 14],
# [16, 18],
# [20, 22]])
1.5 ndarray运算
数组与标量之间的运算:运算作用于数组的每一个元素
a = np.arange(12).reshape((2, 3, 2))
# 平均值
a.mean() # 5.5
# 相除
a / a.mean()
# array([[[0. , 0.18181818],
# [0.36363636, 0.54545455],
# [0.72727273, 0.90909091]],
# [[1.09090909, 1.27272727],
# [1.45454545, 1.63636364],
# [1.81818182, 2. ]]])
NumPy一元函数:对ndarray中的数据执行元素级运算的函数
函数 | 说明 |
---|---|
np.abs(x) np.fabs(x) |
计算数组x各元素的绝对值 |
np.sqrt(x) np.square(x) |
计算数组x元各素的平方根、平方 |
np.log(x) np.log(10) np.log2(x) |
计算数组x各元素的自然对数、10底对数、2底对数 |
np.ceil(x) np.floor(x) |
计算数组x各元素的ceiling值(大于元素的最小整数值)、floor值(小于元素的最大整数值) |
np.rint(x) |
计算数组x各元素的四舍五入 |
np.modf(x) |
将数组x各元素的小数部分和整数部分以2个独立数组返回 |
np.cos(x) np.cosh(x) np.sin(x) np.sinh(x) np.tan(x) np.tanh(x) |
计算数组x各元素的普通型和双曲线型三角函数 |
np.exp(x) |
计算数组x各元素的指数值 |
np.sign(x) |
计算数组x各元素的符号值,1(+),0,-1(-) |
a = np.array([[1.1, 2.1, 3.6], [2.5, 5.9, 4.1]])
np.ceil(a)
# array([[2., 3., 4.],
# [3., 6., 5.]])
np.floor(a)
# array([[1., 2., 3.],
# [2., 5., 4.]])
np.modf(a)
# (array([[0.1, 0.1, 0.6],
# [0.5, 0.9, 0.1]]), array([[1., 2., 3.],
# [2., 5., 4.]]))
np.exp(np.array([1, 2, 3])) # array([ 2.71828183, 7.3890561 , 20.08553692])
在使用数组时,一定要注意原数组是否被真实改变,
一元函数几乎都是只改变输出结果,不改变原数组(要改变需要重新赋值)
NumPy的二元函数 | 说明 |
---|---|
+ - * / ** |
2个数组各元素进行对应运算 |
np.maximum(x,y) np.fmax() np.miximum(x,y) np.fmix() |
元素级的最大值/最小值计算 |
np.mod(x,y) |
元素级的模运算 |
np.copysign(x,y) |
将数组y中个元素值的符号赋值给数组x |
< > =< => == != |
算术比较,产生布尔型数组 |
a = np.array([[1.1, 2.1, 3.6], [2.5, 5.9, 4.1]])
b = np.array([[1, 2, 3], [4, 5, 6]])
np.maximum(a, b)
# array([[1.1, 2.1, 3.6],
# [4. , 5.9, 6. ]])
np.fmax(a, b)
# array([[1.1, 2.1, 3.6],
# [4. , 5.9, 6. ]])
a > b
# array([[ True, True, True],
# [False, True, False]])
np.mod(a, b)
# array([[0.1, 0.1, 0.6],
# [2.5, 0.9, 4.1]])
2. NumPy数据存取
2.1 一、二维
CSV(Comma-Separated Value)逗号分隔值
一种文件格式,用来存储批量数据
将数据写入CSV文件(将数据保存为CSV文件)
np.savetxt(frame, array, fmt = '%.18e', delimiter = None)
frame
:文件、字符串或产生器,可以是.gz或.bz的压缩包
array
:存入文件的数组
fmt
:写入文件的格式,例如%d(整数)、%.2f(保留2个小数点)、%.18e(科学计算法,保留18位小数点的浮点数)
delimiter
:分割字符串,默认是任何空格(写入CSV需呀改成逗号)
a = np.arange(100).reshape(5, 20)
np.savetxt('a.csv', a, fmt = '%d', delimiter=',') # 【在python运行目录下生成相应的a.csv文件,包含维度信息】
读入csv文件
np.loadtxt(frame, dtype = np.float, delimiter = None, unpack = False)
dtype
:数据类型,可选np.int
unpack
:False读入文件写入一个数组,如果True,读入属性将分别写入不同变量
b = np.loadtxt('a.csv', delimiter=',')
局限性:只能有效存储一维和二维数组
2.2 多维数组
写入/存储多维数组
a.tofile(frame, sep = '', format = '%s')
frame
:文件、字符串
sep
:数据分隔字符串,如果是空串,写入文件为二进制
format
: 写入数据的格式
a = np.arange(100).reshape(5, 10, 2)
a.tofile('b.dat', sep = ',', format = '%d') # 【在python运行目录下生成相应的b.dat文件,不包含维度信息)
读入多维数据文件
np.fromfile(frame, dtype = np.float, count = -1, sep = '')
count
:读入元素个数,-1表示读入整个文件
c = np.fromfile('b.dat', dtype = np.int, sep = ',')
c # 【一维数组,没有维度信息】
c.reshape(5, 10, 2)
tofile()
写入多维数组,维度信息消失,读取后需要重新定义维度信息
存入是需要知道数组的维度信息和元素类型
2.3 便捷文件存储
# 存入(有原数组的维度信息)
np.save(frame, array)
np.savez(frame, array)
# 读取(有原数组的维度信息)
np.load(frame)
frame
:文件名,以.npy为扩展名,压缩扩展名为.npz
a = np.arange(100).reshape(5, 10, 2)
np.save('a.npy', a)
b = np.load('a.npy')
这个方法是以二进制 存储文件,第一行为数组的原始信息(包括维度)
3. NumPy函数
3.1 随机数函数
NumPy的random子库,能够提供随机数,调用方法np.random.
常用随机数函数 | 说明 |
---|---|
randint(low,high, (shape)) |
根据shape创建随机整数数组,范围[low,high) |
seed(s) |
随机数种子,s是给定的种子值 |
np.random.randint(100, 200, (5,))
# array([111, 128, 174, 188, 109])【一维数组创建】
np.random.randint(100, 200, (2,3))
# array([[109, 115, 164],
# [128, 189, 193]])
np.random.seed(10)
np.random.randint(100, 200, (2,3))
# array([[109, 115, 164],
# [128, 189, 193]])
np.random.seed(10)
np.random.randint(100, 200, (2,3))
# array([[109, 115, 164],
# [128, 189, 193]])
通过重复给定随机数种子,可以生成同一个随机数组
高级随机数函数 | 说明 |
---|---|
shuffle(a) |
根据数组a的第0轴(最外维度)进行随机排列,改变数组a |
permutation(a) |
根据数组a的第0轴进行随机排列,产生一个新数组,不改变数组a |
choice(a,size,replace,p) |
从一维数组a中以概率p抽取元素,形成size形状的新数组,replace表示是否可以重用元素,默认为Ture |
a = np.random.randint(100, 200, (2,3))
a
# array([[127, 118, 193],
# [177, 122, 123]])
np.random.shuffle(a)
a
# array([[177, 122, 123],
# [127, 118, 193]])【数组改变】
np.random.permutation(a) # 【不改变数组】
# array([[127, 118, 193],
# [177, 122, 123]])
a
# array([[177, 122, 123],
# [127, 118, 193]])
b = np.random.randint(100, 200, (5,))
b
# array([105, 104, 171, 188, 188])
np.random.choice(b,(2,2))
# array([[171, 188],
# [171, 105]])
np.random.choice(b,(2,2),p = b/np.sum(b))
# array([[171, 104],
# [171, 105]]) 【设定的这个概率使得越大的数抽到的概率越大】
分布式随机数函数 | 说明 |
---|---|
rand(d0,d1,...,dn) |
产生浮点数[0,1)的均匀分布的数组,d0-dn是维度信息 |
uniform(low, high, size) |
产生具有均匀分布的数组 |
randn(d0,d1,...,dn) |
产生数值是标准正态分布的数组,d0-dn是维度信息 |
normal(loc, scale,size) |
产生具有正太分布的数组,loc均值,scale标准差 |
poisson(lam, size) |
产生具有泊松分布的数组,lam随机事件发生概率 |
np.random.rand(2, 3)
# array([[0.37447814, 0.03649257, 0.4805653 ],
# [0.48993116, 0.41622894, 0.5778854 ]])
np.random.randn(2,3)
# array([[-0.70733753, -1.97096895, 0.9567542 ],
# [ 1.09554293, 1.52540993, -0.84229966]])
np.random.uniform(1, 10, (2,2))
# array([[1.35353591, 4.21463583],
# [1.71651781, 3.74913927]])
np.random.normal(10, 5, (2,2))
# array([[15.64392577, 6.51094985],
# [ 9.59438908, 7.3535196 ]])
3.2 统计函数
NumPy直接提供统计函数,调用方法np.
常用统计函数 | 说明 |
---|---|
sum(a, axis = None) |
根据给定轴axis计算数组a相关元素之和 |
mean(a, axis = None) |
根据给定轴axis计算数组a相关元素的期望 |
average(a,axis=None,weights=None) |
根据给定轴axis计算数组a相关元素的加权平均值 |
std(a, axis = None) |
根据给定轴axis计算数组a相关元素的标准差 |
var(a, axis = None) |
根据给定轴axis计算数组a相关元素的方差 |
axis
= None是统计函数的标配参数,axis
是整数或元组
a = np.arange(24).reshape(2,3,4)
a
# 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]]])
np.sum(a) # 276
# 第一维度上,相对应的元素相加,得到一个第二维度和第三维度的数组
# 本例中,第一维度有2个,第1个第一维度+第2个第一维度
np.sum(a, axis = 0)
# array([[12, 14, 16, 18],
# [20, 22, 24, 26],
# [28, 30, 32, 34]])
# 第二维度上,相对应的元素相加,得到一个第一维度和第三维度的数组
# 本例中,第二维度有3个,在第1个第一维度中:第1个第二维度+第2个第二维度+第3个第二维度;在第2个第一维度中亦然
np.sum(a, axis = 1)
# array([[12, 15, 18, 21],
# [48, 51, 54, 57]])
# 第三维度上,相对应的元素相加,得到一个第一维度和第二维度的数组
np.sum(a, axis = 2)
# array([[ 6, 22, 38],
# [54, 70, 86]])
axis
= 0,红框数字运算
axis
= 1,蓝框数字运算
axis
= 2,黄框数字运算
np.average(a,axis=1)
# array([[ 4., 5., 6., 7.],
# [16., 17., 18., 19.]])
# 轴为1时,是第二维度数据,第二维度有3个,所有需要分别指出其加权力度
np.average(a,axis=1, weights=[2,4,6])
# array([[ 5.33333333, 6.33333333, 7.33333333, 8.33333333],
# [17.33333333, 18.33333333, 19.33333333, 20.33333333]])
加权平均数=元素*相应加权之和/权重之和
不设定时,默认哥权重为1,即平均值
其他统计函数 | 说明 |
---|---|
min(a) max(a) |
计算数组a中元素的最小、大值 |
argmin(a) argmax(a) |
计算数组a中元素最小、大值的降一维下标(即获得最小、大值的一维位置) |
unravel_index(index,shape) |
根据shape将一维下标的index装换成多维下标 |
ptp(a) |
计算数组a中元素最大值与最小值差 |
median(a) |
计算数组a中元素中位数的运算(中值) |
np.argmax(a) # 23
np.unravel_index(np.argmax(a), a.shape) # (1, 2, 3)
axis
= 0,黑框,第1个第一维度
axis
= 1,红框,第1个第二维度
axis
= 2,绿框,第4个第三维度
3.3 阶梯函数
np.gradient(a)
:计算数组a中的梯度,当a为多维数组时,返回每个维度梯度
梯度:连续值之间的变化率,即斜率。反应元素的变化率
在XY坐标抽连续三个X坐标应用的Y轴值:a,b,c,b的梯度是(c-a)/2
对于2个顶点数值,是(当前数值-隔壁数值)/1
import numpy as np
a = np.random.randint(0, 20,(5))
a # array([ 2, 19, 15, 12, 19])
np.gradient(a) # array([17. , 6.5, -3.5, 2. , 7. ])
b = np.arange(24).reshape(2,3,4)
np.gradient(b)
# [array([[[12., 12., 12., 12.],
# [12., 12., 12., 12.],
# [12., 12., 12., 12.]],
# [[12., 12., 12., 12.],
# [12., 12., 12., 12.],
# [12., 12., 12., 12.]]]),【数组在第一维度(红框)梯度值】
# array([[[4., 4., 4., 4.],
# [4., 4., 4., 4.],
# [4., 4., 4., 4.]],
# [[4., 4., 4., 4.],
# [4., 4., 4., 4.],
# [4., 4., 4., 4.]]]), 【数组在第二维度(蓝框)梯度值】
# array([[[1., 1., 1., 1.],
# [1., 1., 1., 1.],
# [1., 1., 1., 1.]],
# [[1., 1., 1., 1.],
# [1., 1., 1., 1.],
# [1., 1., 1., 1.]]])] 【数组在第三维度(黄框)梯度值】
4. 图像的手绘
4.1 图像的数组
RBG色彩模式:通过颜色通道变化和叠加得到各种颜色,形成的颜色包括人类实例所能感知的所有颜色
- R红色:0-255
- G绿色:0-255
- B蓝色:0-255
PIL库(Python Image Library):具有强大图像处理能的第三方库
# 安装
pip install pillow
# 导入
from PIL import Image
Image
:是PIL库中代表一个图像的类(对象)
图像的数组表示:由像素组成的三维矩阵,每个元素是一个RGB值
from PIL import Image
import numpy as np
# 将打开的图片生成一个数组
im = np.array(Image.open('E:\TDRDIS Book\编程\Python应用\pig\数据算法途径.jpg'))
# 打印维度和类型
print(im.shape, im.dtype) # (1136, 2122, 3) uint8
维度分别是高度、宽度、像素RGB值构成
4.2 图像的变换
from PIL import Image
import numpy as np
# 读入图像,并获得RGB值数组
im = np.array(Image.open('E:\\TDRDIS Book\\编程\\Python应用\\pig\\111.jpg'))
# 改变数组像素,计算补值
a = [255, 255, 255] - im
# 将数组生成图像对象
im_a = Image.fromarray(a.astype('uint8'))
# 保存图像
im_a.save('E:\\TDRDIS Book\\编程\\Python应用\\pig\\111_a.jpg') # 【获得图片】
convert(L)
将彩色变换成灰色图片,生成的数组时一个二维数组,对应的值是灰度值,不是RGB值
im = np.array(Image.open('E:\\TDRDIS Book\\编程\\Python应用\\pig\\aaa.jpg').convert('L'))
# 灰度值取反
b = 255 - im
im_a = Image.fromarray(b.astype('uint8'))
im_a.save('E:\\TDRDIS Book\\编程\\Python应用\\pig\\aaa_b.jpg')
# 区间变化,对当前图片的灰度值做一个区间压缩,再扩充一个区间范围(150)
c = (100/255)*im + 150
im_a = Image.fromarray(b.astype('uint8'))
im_a.save('E:\\TDRDIS Book\\编程\\Python应用\\pig\\aaa_c.jpg')
# 像素平方
d = 255*(a/255)**2
im_a = Image.fromarray(b.astype('uint8'))
im_a.save('E:\\TDRDIS Book\\编程\\Python应用\\pig\\aaa_d.jpg')
4.3 图形的手绘
手绘效果特点:
- 黑白灰色
- 边界线较重
- 相同或相近色彩趋于白色
- 略有光源效果:根据灰度变化模拟人类视觉的远近程度
from PIL import Image
import numpy as np
a = np.array(Image.open('E:\\TDRDIS Book\\编程\\Python应用\\pig\\doctor.jpg').convert('L')).astype('float')
# 预设虚拟深度值为10【取值范围是(0-100)】
depth = 10.
# 取图像灰度的梯度值
grad = np.gradient(a)
# 分别取横纵图像梯度值
grad_x, grad_y = grad
# 根据深度调整xy方向的梯度值【添加深度对于梯度的影响因素】
# /100对深度值进行归一化
grad_x = grad_x*depth/100.
grad_y = grad_y*depth/100.
# 构造xy梯度的三维归一化单位坐标系
A = np.sqrt(grad_x**2 + grad_y**2 + 1.)
# 继续整体归一化,uni_x、uni_y、uni_z表示图像平面的单位法向量
uni_x = grad_x/A
uni_y = grad_y/A
uni_z = 1./A
# 光源的俯视角度,弧度值
vec_el = np.pi/2.2
# 光源的方位角度,弧度值
vec_az = np.pi/4.
# 光源对xyz 轴的影响,np.cos(vec_el)在个方向上的投影长度
# dx,sy,dz可以看做光源在坐标中的表示
dx = np.cos(vec_el)*np.cos(vec_az)
dy = np.cos(vec_el)*np.sin(vec_az)
dz = np.sin(vec_el)
# 光源归一化【梯度与光源相互作用,将梯度转化为灰度】
b = 255*(dx*uni_x + dy*uni_y + dz*uni_z)
# 之前各种归一化,都是为了将影响因子局限在0-1之间,以免投影到梯度范围内,产生溢出,但也有不可避免的
# 为了避免数据越界(溢出),将生产的灰度值裁剪至0-255
# clip()舍弃掉少许溢出的灰度值
b = b.clip(0,255)
# 重构图像
im = Image.fromarray(b.astype('uint8'))
im.save('E:\\TDRDIS Book\\编程\\Python应用\\pig\\doctor_手绘.jpg')
利用像素之间的梯度值和虚拟深度值对图像进行重构
根据灰度变化来模拟人类视觉的明暗程度
目录:Python数据分析与展示
一、NumPy库
二、Matplotlib库
三、Pandas库