NumPy 入门
理解 Python中的数据类型
在 Python 中变量的数据类型是动态推断的,并且可以自动进行转换
x = 4
x = "four"
因为Python 是由 C 编写的所以 Python 的整形实际上是 C 中的一个结构体,通过储存一些额外的信息 Python 可以进行自由、动态的编码
Python 列表不仅仅是一个列表
Python 中的列表是可变长的多元素的容器,也就是说 Python 的列表中不一定是相同元素
a = [0 , '1' , 'two' ]
正因为这种灵活的类型,列表中的每一项都要保存各自的完整信息。如果列表中所有的变量都是同一种类型,那么很多的信息都会很多余。同时冗余的信息也会降低运行的效率
Python 中固定类型的数组
Python (3.3 之后)提供了固定类型的数组
import array
L = list( range(10))
A = array.array( 'i' , L )
这样就可以创建一个数组,期中的 'i'
是整数类型码,标识数据都是整形的
通常更加实用的是NumPy 包中的ndarray
对象,不仅有更高效的存储,还有更加高效的操作
首先要做的是用别名np
引入包
import numpy as np
首先可以声明整形变量
np.array( [1 , 2 , 3 ])
numpy 要求数组必须是相同的类型,如果数据不匹配就会自动向上转换(如果可以的话),下面的整形就会被转换成浮点型
np.array( [1 , 2 , 3.14])
如果希望设置数组的数据类型,可以用dtype
关键字
np.array( [1,2,3] , dtype='float32')
不同于 Python 的列表。numpy 数组是支持多维的
np.array( [range(i,i+3) for i in [ 2 , 4 , 6 ]] )
从头创建数组
刚才的几种方法都只是用列表来创建数组,当数据量很多时候,往往直接从头创建才是更加高效的方法
# 长度为 10,数字都是 0
np.zeros( 10 , dtype=int)
# 3*5 浮点型 值都是 1
np.ones( (3,5) , dtype=float)
# 3*5 值全部都是 3.14
np.full( (3,5) , 3.14 )
# 从 0 开始 20 结束 步长是 2 的等差数列
np.arange( 0 , 20 , 2 )
# 5 个数数组,均匀的分布在 0 到 1 中
np.linspace( 0 , 1 , 5 )
# 3*3 随机分布在 0 到 1 的数组
np.random.random((3,3))
#3*3 均值 0 方差 1 的正态分布的的随机数组
np.random.normal( 0 , 1 , (3,3) )
#3*3 [0,10) 随机分布的数组
np.random.randint( 0 , 10 , (3,3) )
# 3*3 单位矩阵
np.eye(3)
# 长度为 3 未初始化的数组
# 值是随机值
np.empty(3)
NumPy 的基本数据类型
NumPy 中单独的数据类型,以下是基础类型
布尔型
bool_
整形
int8
、int16
、int32
、int32
、int64
分别是 8、16、32、64为整形
还有int_
默认整形,intc
和 C 语言中的int
相同,intp
索引整形 和 C 语言的ssize_t
相同
此外还有无符号整形uint8
、uint16
、uint32
、uint64
浮点型
flaot16
、float32
、float64
分别是16、32、64 位浮点型
float_
是float64
简化形式
复数
complex64
两个 32 位浮点数表示,complex128
两个 64位浮点数表示
complex_
是complex128
的简化
NumPy数组基础
NumPy 数组的属性
首先我们先设置一下随机数的种子,然后生产三个数组
import numpy as np
np.random.seed(0)
x1 = np.random.randint( 10 , size=6 ) # 一维
x2 = np.random.randint( 10 , size=(3,4) ) # 二维
x3 = np.random.randint( 10 , size=(3,4,5) ) # 三维
然后对于数组来说他的属性有 nidm(数组维度)、shape(每个维度的大小)、size(数组总的大小)、dtype(数组中元素数据类型)、itemsize(数组中元素字节大小)、nbytes(数组总字节大小),一般认为 nbytes 是 itemsize 于 size 的乘积
print("x3 nidm: " , x3.ndim )
print("x3 shape: " , x3.shape )
print("x3 size: " , x3.size )
print("x3 dtype: " , x3.dtype )
print("x3 itemsize" , x3.itemsize )
print("x3 nbytes" , x3.nbytes )
数组索引:获取单个元素
首先可以用数组名获得完整的数组,然后也可用[]
访问单个元素
print(x1)
print(x1[3])
对于多维数组,每一维度之间逗号间隔就好
print(x2)
print(x2[2,0])
可以用下标访问,也可以用下标直接进行修改
x2[2,0] = 999
print(x2)
注意的是如果数据类型不匹配,会自动进行转换,并且没有错误和警告
数组切片:获取子数组
一维数组
一维数组和 Python 的语法很类似x[star:stop:step]
,如果未指定默认值是star = 0,stop = 维度大小,step = 1
x = np.arange(10)
print(x)
print(x[:3]) # 前三个
print(x[6:]) # 6之后的所有
print(x[2:7]) # 之间的
print(x[::2]) # 隔一个
print(x[3::2]) # 隔一个从三开始
print(x[::-1]) # 倒叙
print(x[6::-1]) #从 6 开始倒叙
多维子数组
多维数组也是类似的
print(x2)
print(x2[:2,:3]) # 前两行,前三列
print( x2[::2,:]) # 间隔一行取
print( x2[ : ,::-1]) # 每一列倒叙
获取数组的行列
如果需要获得单行或单列,可以将索引与切片组合
print( x2[ : , 0 ]) #第一列
print( x2[0]) # 获取单行时候可以省略列 , 等价于 x2[0,:]
非副本的子数组
之前的各种切片操作都是一个视图
print(x2)
x2_sub = x2[ :2 , :2 ] # 切出 2*2 的数组
print(x2_sub)
x2_sub[0,0] = -11
print( x2_sub )
print(x2)
可以看到,对于 x2_sub 数组操作也会影响到原数组
在处理非常大的数据集的时候可以获得并处理这个几何子集
副本子数组
x2_sub_copy = x2[:2,:2].copy();
x2_sub_copy[0,0] = 111;
print(x2)
我们可以通过 copy 方法来创建副本,这样对副本修改的时候就不会修改原数组
数组的变形
数组变形最灵活的方法是reshape()
函数
x = np.arange(15)
print(x)
x = x.reshape( (3,5) )
print(x)
数组的拼接和分裂
拼接
首先可以用np.concatenate()
进行拼接
x = np.array([1,2,3])
y = np.array([3,2,1])
print( np.concatenate( [x,y] ) )
也可以同时拼接两个以上的数组
z = np.array( [99,99] )
print( np.concatenate( [x,y,z] ) )
同时也支持多维数组的拼接,默认第一维是轴(下标从 0 开始)
a = np.array( [ [1,2] , [3,4] ] )
b = np.array( [ [5,6] , [7,8] ] )
print( np.concatenate( [a,b] ) )
也可指定第二维是轴
a = np.array( [ [1,2] , [3,4] ] )
b = np.array( [ [5,6] , [7,8] ] )
print( np.concatenate( [a,b] , axis=1) )
值得注意的是做轴的维度的大小必须相同
沿着固定维度处理数组时,可以使用np.vstack()
垂直栈和np.hstack()
水平栈函数会更加简洁
print( np.vstack( [a,b] ) )
print( np.hstack( [a,b] ) )
数组的分裂
与拼接过程相反的是,分裂可以用np.split()
,索引列表记录是分裂点的位置
x = [1 , 2 , 3 , 4 , 5 , 6]
x1 , x2 , x3 = np.split( x , [ 2 , 5 ] )
print( x1 , x2 , x3 )
当然也可以横着拆分和竖着拆分
横向
upper , lower = np.vsplit( gird , [2] )
print(upper)
print(lower)
纵向
left , right = np.hsplit( gird , [2] )
print(left)
print(right)
Numpy数组的计算:通用函数
通用函数介绍
首先NumPy中的向量操作是通过通用函数实现的
比如
np.arange(5) / np.arange(1,6)
但是也不只是一维向量
np.arange(5) * 2
探索 NumPy 的通用函数
数组运算
首先 Numpy继承了 python 的语法,可以很自然的使用 Python 的运算符
但实际这些运算符都是 Numpy 内置函数的封装器
运算符 | 对应的通用函数 |
---|---|
+ | np.add |
- | np.subtract |
- | np.negative |
* | np.negative |
/ | np.divide |
// | np.floor_divide |
** | np.power |
% | np.mod |
绝对值
可以直接用 Python 函数
x = np.array( [-2,-1,0,1,2] )
abs(x)
也可以用 np 的通用函数
np.absolute(x)
三角函数
三角函数的调佣也是非常直观的
theta = np.linspace( 0 , np.pi , 3 )
np.sin(theta)
指对数
指数的运算是非常直观的
x = [1,2,3]
print( "x = " , x )
print( "e^x = " , np.exp(x) )
print( "2^x = " , np.exp2(x) )
print( "3^x = " , np.power(3,x) )
对数也是类似的
print("ln(x) = " , np.log(x))
print("log2(x) = " , np.log2(x) )
print("log10 = ", np.log10(x) )
如果需要其他形式的对数可以用换底公式
专有通用函数
还有更多函数在numpy中,但是除此之外还有更加专业的函数是来自子模块scipy
from scipy import special
x = [ 1 , 5 , 10 ]
print("Gamma(x) = " . special.gamma(x) )
高级通用函数的性质
可以用out关键字来指定通用函数输出数据存放的位置
x = np.arange(5)
y = np.empty(5)
np.multiply( x , 10 , out = y )
print(y)
聚合,通过reduce
函数会对指定的元素进行重复的操作直到只剩下一个元素
x = np.arange(1,6)
np.add.reduce(x) # 所有元素的和
np.multiply.reduce(x) # 所有元素的乘积
外积,任何一个通用函数都可以通过outer
关键字得到从两个数组中获得元素的运算结果
np.multiply.outer( x , x )
聚合:最值和其他值
求和直接用sum
函数就好,这比python自带的函数要快
np.sum(x)
最大值最小值类似
np.max(x)
np.min(x)
如果是一个二维数组直接使用函数获得就是整个数组的最值
x = np.arange(9).reshape((3,3))
x.min()
但是我们可以用axis
关键字来指定按哪一个轴来进行聚合
x.min(axis=0) # 聚合成一行
x.min(axis=1) # 聚合成一列