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_

整形

int8int16int32int32int64分别是 8、16、32、64为整形

还有int_默认整形,intc和 C 语言中的int相同,intp索引整形 和 C 语言的ssize_t相同

此外还有无符号整形uint8uint16uint32uint64

浮点型

flaot16float32float64分别是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) # 聚合成一列

posted @ 2022-05-22 15:44  PHarr  阅读(40)  评论(0编辑  收藏  举报