关于Numpy的一些简单使用

Numpy入门

以下只是简单地记录下上课时学习Numpy的一些例子

# 导入numpy包,并取别名为np
import numpy as np 

# 查看numpy版本
numpy.__version__ 

# 整型数组
np.array([1, 4, 2, 5, 3])

# 如果类型不匹配,Numpy会向上转换(如果可行的话,指的是向更大类型的数据转换)
# 此处是整型被转换为浮点型
np.array([3.14, 4, 2, 3]) 

# dtype关键字可以设置数组的数据类型
np.array([1, 2, 3, 4], dtype="float32")

# 嵌套列表构成多维数组
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,值全相同的数组
np.full((3, 5), 3.14)

# 从0开始,到20结束(不包括20),步长为2
np.arange(0, 20, 2)

# 创建一个5元素数组,这五个值均匀分配到0-1(包括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)

基本的数组操作

import numpy as np
np.random.seed(42) # 设置随机数种子,相同的随机数种子在相同版本的python、numpy下生成的随机数是相同的, np.random.RandomState(42)也和种子的效果一样
x1 = np.random.randint(10, size=6) # 一维数组,默认从0开始(随机数从0-10中抽取,数组大小为6)
x2 = np.random.randint(10, size=(3, 4)) # 3*4的二维数组
x3 = np.random.randint(10, size(3, 4, 5)) # 3*4*5的三位数组

print("x3 ndim: ", x3.ndim) # 显示数组的维度
print("x3 shape: ", x3.shape) # 显示数组每个维度的大小,也就是数组的形状,此处是(3, 4, 5)
print("x3 size: ", x3.size) # 显示数组的总大小,此处是3*4*5=60
print("dtype: ", x3.dtype) # 显示数组的数据类型

数组索引,获取单个元素(与列表的操作类似)

x1 = np.array([5, 0, 3, 3, 7, 9])
x1[0] # 索引为0的元素,此处为5
x1[-1] # 最后一个元素,此处为9
x1[-2] # 倒数第二个元素,此处为7

x2 = np.array([[3, 5, 2, 4],
               [7, 6, 8, 8],
               [1, 6, 7, 7]])
x2[0,0] # 获取坐标为0,0的元素,此处为3
x2[2,-1] # 第二行最后一列元素,此处为7
x2[0,0] = 12 # 将第0行第0列元素修改为12

# 当我们试图将一个浮点值插入到一个整型数组中,浮点值会被截取成整型,向下截取,比如3.14被截取成3

数组切片:获取子数组

x = np.arange(10)

x[:5] # 索引为0-4的元素,共5个
x[5:] # 索引从5开始到最后一个
x[4:7] # 索引为4、5、6的元素
x[::2] # 从0开始,步长为2,此处结果为0,2,4,6,8
x[::-1] # 所有元素逆序
x[::-2] # 所有元素逆序后以步长为2取元素,此处结果为9,7,5,3,1

多维切片也采用同样的方式处理,用冒号分隔

x2 = np.array([[3, 5, 2, 4],
               [7, 6, 8, 8],
               [1, 6, 7, 7]])
x2[:2, :3] # 选取0、1行的0、1、2列
x2[:3, ::2] # 选取0、1、2行的0,2列
x2[::-1, ::-1] # 选取2,1,0行的3,2,1,0列(逆序了)
x2[0, :] # 第0行的所有列
x2[0] # 与x2[0, :]等价
x2[:, 0] # 所有行的第0列

# 以下是需要注意的地方,由浅复制引起的
x2_sub = x2[:2, :2] # x2_sub与x2指向同一个地址,操作x2_sub等于操作了x2
x2_sub_copy = x2[:2, :2].copy() # x2_sub_copy与x2指向不同的地址,为深复制

数组的变形

x = np.arange(1, 10) # array([1, 2, 3, 4, 5, 6, 7, 8, 9])
grid = x.reshape((3, 3)) # array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

x[np.newaxis, :] # 本质上就是在x的形状左边补1,此处得到的shape变成(1, 9)
x[:, np.newaxis] # 本质上就是在x的形状右边补1,此处得到的shape变成(9, 1)

数组拼接和分裂

x = np.array([1, 2, 3])
y = np.array([3, 2, 1])
np.concatenate([x, y]) # array([1, 2, 3, 3, 2, 1])

grid = np.array([[1, 2, 3], [4, 5, 6]])
np.concatenate([grid, grid]) # 默认沿第一个轴拼接,此处第一个轴是行,所以按行拼接,此处结果为array([[1, 2, 3], [4, 5, 6],[1, 2, 3], [4, 5, 6]])
np.concatenate([grid, grid], axis = 1) # 沿第二个轴拼接(axis=0表示沿第一个轴),此处结果为array([[1, 2, 3, 1, 2, 3], [4, 5, 6, 4, 5, 6]])

x = np.array([1, 2, 3])
grid = np.array([[9, 8, 7], [6, 5, 4]])
np.vstack([x, grid]) # 垂直栈数组,此处可理解为按行拼接,排列成矩阵正好是垂直拼接
y = np.array([[99], [99]])
np.hstack([grid, y]) # 水平栈数组,此处可理解为按列拼接,排列成矩阵正好是水平拼接

数组的分裂

x = [1, 2, 3, 99, 99, 3, 2, 1]
x1, x2, x3 = np.split(x, [3, 5]) # 从索引为3和5的地方来对x进行分裂,此处结果为[1 2 3] [99 99] [3 2 1]

grid = np.arange(16).reshape((4, 4))
upper, lower = np.vsplit(grid, [2]) # 从索引为2的行开始分裂,此处结果为[[0 1 2 3] [4 5 6 7]] [[8 9 10 11] [12 13 14 15]]
left, right = np.hsplit(grid, [2]) # 从索引为2的列开始分裂,此处结果为[[0 1] [4 5] [8 9] [12 13]] [[2 3] [6 7] [10 11] [14 15]]

通用函数

import numpy as np
np.random.seed(0)

def compute_reciprocals(values):
    output = np.empty(len(values))
    for i in range(len(values)):
        output[i] = 1.0 / values[i]
    return output
big_array = np.random.randint(1, 100, size = 1000000)
%timeit compute_reciprocals(big_array) # %timeit会计算其右方函数运行七次的时间,此次的一个可能结果是 1.44 s ± 8.87 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit (1.0 / big_array) # 一个可能的结果是:3.29 ms ± 15.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 二者的前后对比可以看出python循环所花费的时间明显更多,所以使用这种解释性语言,尽量少用循环,多用函数包里内嵌的一些方法与特性来解决问题,这样可以提高性能与效率

# 多维数组运算
x = np.arange(9).reshape((3, 3))
2 ** x # 结果是array([[1, 2, 4],[8, 16, 32],[64, 128, 256]], dtype=int32)

运算符与对应的通用函数

运算符 对应的通用函数 描述
+ np.add 加法运算
- np.subtract 减法运算
- np.negative 负数运算
* np.multiply 乘法运算
/ np.divide 除法运算
// np.floor_divide 整除法
** np.power 指数运算
% np.mod 取模或取余
np.absolute(x) # 对x取绝对值

theta = np.linspace(0, np.pi, 3)
np.sin(theta) 
np.cos(theta)
np.tan(theta)

x = [-1, 0, 1]
np.arcsin(x)
np.arccos(x)
np.arctan(x)

x = [1, 2, 3]
np.exp(x) # e^x
np.exp2(2) # 2^x
np.power(3, x) # 3^x
np.log(x) # ln(x)
np.log2(x) # log2(x)
np.log10(x) # lg(x)

# 指定输出
x = np.arange(5)
y = np.empty(5)
np.multiply(x, 10, out=y) # 将x与10相乘,得出来的值赋给y
print(y) # [0 10 20 30 40]

y = np.zeros(10)
np.power(2, x, out=y[::2]) # 计算2^x,得出来的值按步长为2从0开始赋值给y
print(y) # [1 0 2 0 4 0 8 0 16 0]

聚合

x = np.arange(1, 6)
np.add.reduce(x) # reduce可以计算最终结果,此处输出为15
np.multiply.reduce(x) # 计算6!,输出为120
np.add.accumulate(x) # accumulate可以存储每次计算的中间结果,此处结果为[1 3 6 10 15]
np.multiply.accumulate(x) # 此处结果为[1 2 6 24 120]
np.multiply.outer(x, x) # 计算外积

# 以下为两种求和方式的对比
big_array = np.random.rand(1000000)
%timeit sum(big_array) # 69.4 ms ± 440 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit np.sum(big_array) # 439 µs ± 4.07 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# 以下为两种方式求最值的对比
%timeit min(big_array) # 45.1 ms ± 1.67 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit np.min(big_array) # 499 µs ± 1.08 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# np.min(big_array)等价于big_array.min(),max、sum可以类比

M = np.random.random((3, 4))
M.min(axis = 0) # 按列求最小值
M.max(axis = 1) # 按行求最大值
函数名称 NaN安全版本 描述
np.sum np.nansum 计算元素的和
np.prod np.nanprod 计算元素的积
np.mean np.nanmean 计算元素的标准差
np.std np.nanstd 计算元素的标准差
np.var np.nanvar 计算元素的方差
np.min np.nanmin 找出最小值
np.max np.nanmax 找出最大值
np.argmin np.nanargmin 找出最小值的索引
np.argmax np.nanargmax 找出最大值的索引
np.median np.nanmedian 计算元素的中位数
np.percentile np.nanpercentile 计算基于元素排序的统计值
np.any 验证是否存在元素为真
np.all 验证是否所有元素都为真

广播

规则1:如果两个数组的维度数不相同,那么小维度数组的形状将会在最左边补1

规则2:如果两个数组的形状在任何一个维度上都不匹配,那么数组的形状会沿着维度为1的维度扩展以匹配另一个数组的形状

规则3:如果两个数组的形状在任何一个维度上都不匹配,且没有任何一个维度等于1,那么会引发异常

M = np.ones((2, 3))
a = np.arange(3)

在这里插入图片描述

M + a # array([[1., 2., 3.], [1.,2.,3.]])
a = np.arange(3).reshape((3, 1))
b = np.arange(3)

在这里插入图片描述

a + b # array([[0, 1, 2],[1, 2, 3], [2, 3, 4]])
M = np.ones((3, 2))
a = np.arange(3)

在这里插入图片描述

在这里插入图片描述

掩码(Mask)

x = np.array([1, 2, 3, 4, 5])
x < 3 # array([True, True, False, False, False])
(2 * x) == (x ** 2) # array([False, True, False, False, False])

rng = np.random.RandomState(42) # 和种子的效果差不多
x = rng.randint(10, size=(3, 4)) # array([[6, 3, 7, 4], [6, 9, 2, 6], [7, 4, 3, 7]])
x < 6 # array([[False, True, False, True], [False, False, True, False], [False, True, True, False]])

np.count_nonzero(x < 6) # 计算有多少值小于6,在python中,0为False,其他非零数为True
np.sum(x < 6) # 由于True的默认取值为1,所以就相当于计算x<6的个数
np.sum(x < 6, axis = 1) # 计算每行有多少个值小于6
np.any(x > 8) # 是否存在值大于8
np.all(x < 10) # 是否所有值都小于10

x = np.array([[5, 0, 3, 3],[7, 9, 3, 5],[2, 4, 7, 6]])
x[x < 5] # array([0, 3, 3, 3, 2, 4])

花哨的索引

rand = np.random.RandomState(42)
x = rand.randint(100, size=10) # [51 92 14 71 60 20 82 86 74 74]
[x[3],x[7],x[2]] # [71, 86, 14]
ind = [3, 7, 4]
x[ind] # 索引为3、7、4的元素,array([71, 86, 60])

# 利用花哨的索引,结果的形状与索引数组的形状一致,而不是与被索引数组的形状一致
ind = np.array([[3, 7], [4, 5]])
x[ind] # array([[71, 86], [60, 20]])

x = np.arange(12).reshape((3, 4))
row = np.array([0, 1, 2])
col = np.array([2, 1, 3])
x[row, col] # 取坐标为(0, 2),(1, 1),(2, 3)的元素,结果为array([2, 5, 11])
x[2, [2, 0, 1]] # 可以用广播来理解,取坐标为(2, 2),(2, 0),(2, 1)的元素,结果为array([10, 8, 9])
x[1:, [2, 0, 1]] # 取第1、2行的第2、0、1列,结果为array([6, 4, 5],[10, 8, 9])

# 将花哨的索引和掩码组合使用
mask = np.array([1, 0, 1, 0], dtype=bool)
row = np.array([[0], [1], [2]])
x[row, mask] # 将第0、1、2行的第1、3列元素取出,结果为array([0, 2], [4, 6], [8, 10])

# 用花哨的索引修改值
x = np.arange(10)
i = np.array([2, 1, 8, 4])
x[i] = 99 # [0 99 99 3 99 5 6 7 99 9]
x[i] -= 10 # [0 89 89 3 89 5 6 7 89 9]

数组的排序

x = np.array([2, 1, 4, 3, 5])
np.sort(x) # 将x的结果递增排序,但不会改变x本身,结果为array([1, 2, 3, 4, 5])
x,sort() # 将x的结果递增排序,但会改变x本身, 结果为array([1, 2, 3, 4, 5])
x = np.array([2, 1, 4, 3, 5])
i = np.argsort(x) # 将x中的元素正序排列后,返回每个数据原来所在的索引位置到数组中,此次结果为[1 0 3 2 4]
# 此时使用下列语句可以返回x排列后的数值结果
x[i] # array([1, 2, 3, 4, 5])

rand = np.random.RandomState(42)
x = rand.randint(0, 10, (4, 6))
np.sort(x, axis=0) # 对每一列进行排序
np.sort(x, axis=1) # 对每一行进行排序

# 部分排序: 分隔
# np.partition 函数的输入是数组和数字 K, 输出结果是一个新数组, 最左边是第 K 小的值, 往右是任意顺序的其他值,二者都不排序
x = np.array([7, 2, 3, 1, 6, 5, 4])
np.partition(x, 3) # 数组中前三个值是数组中最小的三个值, 剩下的位置是原始数组剩下的值

猜你喜欢

转载自blog.csdn.net/myWarren/article/details/109344411