2025年4月9日 星期三 乙巳(蛇)年 正月初十 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > Python

python --Numpy详解(科学计算)

时间:08-15来源:作者:点击数:35

python --Numpy详解(科学计算)

安装

  • pip install numpy

什么是Numpy:Numeric Python

NumPy系统是Python的一种开源的数值计算扩展

  • 一个强大的N维数组对象Array
  • 比较成熟的(广播)函数库
  • 用于整合C/C++和Fortran代码的工具包
  • 实用的线性代数、傅里叶变换和随机数生成函数
  • numpy和稀疏矩阵运算包scipy配合使用更加强大

详解

导包

  • import numpy as np

查看版本

  • print(np.__version__) # 获取当前numpy版本号
  • # 1.21.3

创建ndarray

  • import numpy as np
  • t = np.array([1, 2, 3, 4]) # 一维数组
  • print(t, type(t))
  • 输出:
  • [1 2 3 4] <class 'numpy.ndarray'>
  • t = np.array([[1,2,3],[4,5,6]]) # 二维数组
  • print(t)
  • 输出: [[1 2 3 4]
  • [4 5 6 7]]

基础 -> ndarray的构造

可以使用多种方式来构建多维数组,最常见的是使用列表来构建多维数组。下面的例子便使用一维列表构建了一个一维数组。

  • import numpy as np
  • nda1 = np.array([1, 2, 3]) # 使用一维列表来作为输入
  • nda1
  • array([1, 2, 3])6 >>> type(nda1)
  • <class 'numpy.ndarray'>

如果希望构建二维数组,可以使用下面的方法:

  • input_list = [
  • ... [1, 2, 3],
  • ... [4, 5, 6]
  • ... ]
  • nda2 = np.array(input_list)
  • nda2
  • array([[1, 2, 3], # 查看值
  • [4, 5, 6]])
  • type(nda2) # 查看类型
  • <class 'numpy.ndarray'>

也可以指定一些特征值,让 NumPy 自动产生相关的数组。例如指定维度,让其产生所有元素都为 0 的数组,代码如下:

  • np.zeros(5) # 5个元素的一维数组
  • array([0., 0., 0., 0., 0.])
  • np.zeros((5, 2)) # 二维数组,5行,2
  • array([[0., 0.],
  • [0., 0.],
  • [0., 0.],
  • [0., 0.],
  • [0., 0.]])

也可以指定维度,让其产生所有元素值都为 1 的数组,代码如下:

  • np.ones((5, 2)) # 二维数组,5行,2列,所有元素都为1
  • array([[1., 1.],
  • [1., 1.],
  • [1., 1.],
  • [1., 1.],
  • [1., 1.]])
  • np.ones(5) # 一维数组,5个元素
  • array([1., 1., 1., 1., 1.])

还可以让 NumPy 自动产生等差数组,此时需要指定开始值、结束值和步长。代码如下:

  • np.arange(3,7,2) # 从3开始,直到7,步长为2
  • array([3, 5])
  • np.arange(3,7,1) # 从3开始,直到7,步长为1
  • array([3, 4, 5, 6])
  • np.arange(7, 3, -1) # 从7开始,直到3,步长为-1
  • array([7, 6, 5, 4])
  • np.arange(7, 3, -2) # 从7开始,直到3,步长为-2
  • array([7, 5])

arange() 函数和 range() 类似,如果仅提供一个值,那么开始值是 0,步长是 1,代码如下:

  • np.arange(7)
  • array([0, 1, 2, 3, 4, 5, 6])
  • 如果提供两个参数,那么步长为 1
  • np.arange(2, 5) # 从2开始,直到5,步长为1
  • array([2, 3, 4])
  • np.arange(2, 6) # 从2开始,直到6,步长为1
  • array([2, 3, 4, 5])

另外一个等差数列函数是 linspace(),其指定开始位置和结束位置,但不指定步长,而是指定元素个数。例如从 1 开始,到 5 结束,一共有 8 个数,那么生成的数组如下面所示:

  • np.linspace(1, 5, 8) # 包括15,等分8个点
  • array([1. , 1.57142857, 2.14285714, 2.71428571, 3.28571429,
  • 3.85714286, 4.42857143, 5])
  • # 可以发现元素个数和指定的一致,开始值和结束值也都被包含,而且它们的确是等差数列。

inspace() 函数比较有用,例如要画正弦函数在 0 到 2π 之间的图形,便可以使用该函数在 0 到 2π 之间产生均匀分布的 100 个点,然后使用 matplotlib 将它们画出来。下面是演示的代码:

  • import matplotlib.pyplot as plt
  • import numpy as np
  • x = np.linspace(0, 2*np.pi, 100)
  • y = [np.sin(e) for e in x]
  • plt.plot(x, y)
  • plt.savefig("sindemo1.png")
在这里插入图片描述

还可以使用 logspace() 函数让 NumPy 自动产生等比数列,此时需要指定开始点和结束点,同时指定点的个数。如果没有提供点的数目,默认是生成 50 个点。

  • np.logspace(2.0, 3.0, num=4) # 4个点,其实位置是102,结束位置是103
  • array([ 100. , 215.443469, 464.15888336, 1000.])

下面是一个例子,其演示了 logspace() 的用法和参数 endpoint 的用法。endpoint=True 表示结束值被包含在输出数组中,否则表示不包含在输出数组中。下面是完整的代码:

  • import matplotlib.pyplot as plt
  • import numpy as np
  • N = 10 # 一共10个点
  • x1 = np.logspace(0.1, 1, N, endpoint=True) # 10被算作是最后一个点
  • x2 = np.logspace(0.1, 1, N, endpoint=False) # 10不被算作是最后一个点
  • y = np.zeros(N)
  • plt.plot(x1, y, 'o')
  • plt.plot(x2, y + 0.5, 'x')
  • plt.ylim([-0.5, 1]) # y轴的范围是-0.51
  • plt.savefig("logspace1.png") # 保存图片到文件
在这里插入图片描述

还可以使用 full() 函数指定维度和一个值,让所有的元素都等于该值。该函数和 ones() 类似,但值是由用户指定的。

  • np.full((2, 2), np.inf) # 所有元素都是无穷大
  • array([[inf, inf],
  • [inf, inf]])
  • np.full((2, 2), 11) # 所有元素都是11
  • array([[11, 11],
  • [11, 11]])
  • np.full((2, 2), 1.51) # 所有元素都是1.51
  • array([[1.51, 1.51],
  • [1.51, 1.51]])

使用 eye() 函数还可以自动生成单位矩阵,就是仅对角线上的值为 1,其他位置上的值都为 0。

  • np.eye(2) # 2x2的单位矩阵
  • array([[1., 0.],
  • [0., 1.]])
  • np.eye(3) # 3x3的单位矩阵
  • array([[1., 0., 0.],
  • [0., 1., 0.],
  • [0., 0., 1.]])

还可以自动产生随机的矩阵,例如可以使用 random.normal() 函数产生一个正态分布的一维矩阵:

  • mu, sigma = 0, 0.1 # mu是平均值,sigma代表分散程度
  • s = np.random.normal(mu, sigma, 1000)
  • s.size # 元素个数为1000
  • 1000
  • np.mean(s) # 平均值接近0
  • -0.0011152161285000821
  • abs(mu - np.mean(s)) < 0.01 # 平均值接近mu=0
  • True
  • abs(sigma - np.std(s, ddof=1)) < 0.01 # 分散程度检查
  • True

可以将生成的数据画出来,使用下面的代码:

  • import matplotlib.pyplot as plt
  • import numpy as np
  • mu, sigma = 0, 0.1
  • s = np.random.normal(mu, sigma, 1000)
  • count, bins, ignored = plt.hist(s, 30, density=True)
  • plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) *
  • np.exp( - (bins - mu)**2 / (2 * sigma**2) ),
  • linewidth=2, color='r')
  • plt.savefig("rand1.png")
在这里插入图片描述

还可以生成完全随机的矩阵,方法是使用 np.random.rand(外形)函数。例如在下面的例子中,就生成了随机内容组成的指定外形的矩阵。

  • np.random.rand(3,2) # 3x2的二维矩阵
  • array([[0.11319256, 0.84668147],
  • [0.4040353 , 0.70912343],
  • [0.6511614 , 0.80706271]])
  • np.random.rand(3,2,2) # 3x2x2的三维矩阵
  • array([[[0.64851863, 0.3895985 ],
  • [0.63038544, 0.58402249]],
  • [[0.39816687, 0.92149102],
  • [0.07113285, 0.17109903]],
  • [[0.06713956, 0.39415293],
  • [0.06125844, 0.71276929]]])
  • np.random.rand(4) # 一维矩阵
  • array([0.11918788, 0.91847982, 0.29599804, 0.42242323])

基础 -> ndarray的常用属性

ndarray 是一个类,其包含一些属性。

最基本的便是其维度。可以用属性 ndim 来得到指定矩阵的维度,方法如下:

  • a = np.array([1, 2, 3])
  • a.ndim # 维度为1
  • 1
  • b = np.eye(3)
  • b.ndim # 维度为2
  • 2

可以用属性 shape 来得到指定数组的外形,方法如下:

  • a = np.eye(3) # 3x3的单元矩阵
  • a # 查看a的值
  • array([[1., 0., 0.],
  • [0., 1., 0.],
  • [0., 0., 1.]])
  • a.shape # a的外形
  • (3, 3)

可以用属性 dtype 来得到指定矩阵每个元素的类型,方法如下:

  • a = np.eye(3, dtype=int) # 指定类型为整型
  • a
  • array([[1, 0, 0],
  • [0, 1, 0],
  • [0, 0, 1]])
  • a.dtype # 查看类型
  • dtype('int64')

可以用属性 size 来得到指定矩阵的元素个数,方法如下:

  • a = np.eye(3, dtype=int)
  • a
  • array([[1, 0, 0],
  • [0, 1, 0],
  • [0, 0, 1]])
  • a.size # 矩阵元素个数,9
  • 9

可以用属性 T 来得到指定矩阵的转置矩阵,方法如下:

  • a = np.array([1, 2, 3]) # 一维矩阵
  • a.T # 转置矩阵是自己
  • array([1, 2, 3])
  • b = np.array([[1, 2, 3], [4, 5, 6]]) # 二维矩阵
  • b
  • array([[1, 2, 3],
  • [4, 5, 6]])
  • b.T # 转置矩阵
  • array([[1, 4],
  • [2, 5],
  • [3, 6]])

需要注意的是,转置矩阵就是将原矩阵旋转 90 度得到的矩阵,但其仅对二维以及多维矩阵有效。对于一维矩阵来说,其转置矩阵还是自己。

基础 -> ndarray常见的操作

对于多维矩阵,可以进行变形、加减乘除等操作,本节就来介绍常见的相关操作。、

变形reshape(维度列表)

例如原来是 3×4 的矩阵,可以将其变成 6×2 的矩阵。内容不变,但是样子发生了改变。方法如下:

  • x = np.arange(1, 7) # 一维矩阵
  • x
  • array([1, 2, 3, 4, 5, 6])
  • y = x.reshape(2, 3) # 变成23列的二维矩阵
  • y
  • array([[1, 2, 3],
  • [4, 5, 6]])

加减乘除操作

加法操作是指对外形相同的两个矩阵,进行相同位置元素的加法运算,得到一个和输入矩阵相同外形的矩阵。下面的代码便演示了加法操作的使用:

  • a = numpy.random.rand(3,2) # a是32列的随机二维矩阵
  • b = numpy.random.rand(3,2) # b是32列的随机二维矩阵
  • a # 查看a的值
  • array([[0.49219148, 0.30470874],
  • [0.42371119, 0.96857757],
  • [0.09432051, 0.55935613]])
  • b # 查看b的值
  • array([[0.41471195, 0.85316671],
  • [0.6231908 , 0.98244841],
  • [0.65246256, 0.73501929]])
  • a+b # a+b的值
  • array([[0.90690343, 1.15787545],
  • [1.04690199, 1.95102597],
  • [0.74678307, 1.29437542]])

与之类似的还有减法、乘法和除法操作,其运算符号和普通的数值运算符号相同,都是对相同的位置进行操作。下面的例子是减法操作的使用:

  • a = numpy.random.rand(3,2) # 随机生成3x2的矩阵
  • b = numpy.random.rand(3,2) # 随机生成3x2的矩阵
  • a # 查看矩阵a的内容
  • array([[0.49219148, 0.30470874],
  • [0.42371119, 0.96857757],
  • [0.09432051, 0.55935613]])
  • b # 查看矩阵b的内容
  • array([[0.41471195, 0.85316671],
  • [0.6231908 , 0.98244841],
  • [0.65246256, 0.73501929]])
  • a-b # 减法操作
  • array([[ 0.07747953, -0.54845797],
  • [-0.19947961, -0.01387084],
  • [-0.55814205, -0.17566316]])

下面的例子是乘法操作的使用:

  • a = numpy.random.rand(3,2) # 随机生成3x2的矩阵
  • b = numpy.random.rand(3,2) # 随机生成3x2的矩阵
  • a # 查看矩阵a的内容
  • array([[0.49219148, 0.30470874],
  • [0.42371119, 0.96857757],
  • [0.09432051, 0.55935613]])
  • b # 查看矩阵b的内容
  • array([[0.41471195, 0.85316671],
  • [0.6231908 , 0.98244841],
  • [0.65246256, 0.73501929]])
  • a * b # 乘法操作
  • array([[0.20411769, 0.25996735],
  • [0.26405291, 0.95157749],
  • [0.0615406 , 0.41113754]])

下面是除法操作运算的例子:

  • a = numpy.random.rand(3,2) # 随机生成3x2的矩阵
  • b = numpy.random.rand(3,2) # 随机生成3x2的矩阵
  • a # 查看矩阵a的内容
  • array([[0.49219148, 0.30470874],
  • [0.42371119, 0.96857757],
  • [0.09432051, 0.55935613]])
  • b # 查看矩阵b的内容
  • array([[0.41471195, 0.85316671],
  • [0.6231908 , 0.98244841],
  • [0.65246256, 0.73501929]])
  • a / b # 除法操作
  • array([[1.18682735, 0.3571503 ],
  • [0.67990604, 0.98588135],
  • [0.1445608 , 0.76100877]])

逻辑判断

还可以对矩阵进行逻辑判断,例如判断矩阵元素是否大于 0 或者小于 1。其结果是一个矩阵,分别表示各元素是否满足规定的判断。例如下面就是判断矩阵元素是否小于 0.5 的操作:

  • a = np.random.rand(3,2) # 随机生成3x2的矩阵
  • a # 查看矩阵a的内容
  • array([[0.36826283, 0.1993915 ],
  • [0.3278179 , 0.66236192],
  • [0.98973706, 0.67244684]])
  • a < 0.5 # 各个元素是否小于0.5
  • array([[ True, True],
  • [ True, False],
  • [False, False]])

当然也可以和其他矩阵进行比较,例如下面的例子:

  • a = numpy.random.rand(3,2) # 随机生成3x2的矩阵
  • b = numpy.random.rand(3,2) # 随机生成3x2的矩阵
  • a # 查看矩阵a的内容
  • array([[0.49219148, 0.30470874],
  • [0.42371119, 0.96857757],
  • [0.09432051, 0.55935613]])
  • b # 查看矩阵b的内容
  • array([[0.41471195, 0.85316671],
  • [0.6231908 , 0.98244841],
  • [0.65246256, 0.73501929]])
  • a < b # a的各个元素是否小于b对应的元素
  • array([[False, True],
  • [ True, True],
  • [ True, True]])

基础 -> 金融领域的应用

我们知道 NumPy 有强大的数值计算功能,在生活中,经常会用到的一个计算就是贷款计算。

例如如果贷款 200 万,在 15 年内还清,每个月需要还多少钱?其中支付的利息是多少?再例如,如果购买了一份医疗保险,要求每个月存钱 2000 元,一直存 20 年,20 年内每年最多可以报销医疗费用 5000 元,20 年后可以全额返还本金,这样是否划算?

由于一年期固定存/贷款利率是由央行规定的,所以这个利率在一定时间内基本是固定的。在本节中会经常用到这个概念。

首先来看看存款利息的问题,假定一年期存款利率是 5%,那么每个月存入 100 元,10 年后账户余额是多少?可以使用函数 np.fv() 来处理这类问题,该函数定义如下:

  • np.fv(利率,年限,每月存款,当前存款)

在上面的问题中,可以这么来求解,月利率是 0.05/12;年限是 12*10 个月;每月存款是 -100,负数表示支出;当前存款是 0。计算方法如下:

  • np.fv(0.05/12, 10*12, -100, 0)
  • 15528.227944566719

其中本金部分是 12000,由此得出利息收入是 3528.22。

下面来看一个贷款的问题。如果我们的还款能力是每个月 13000 元,贷款 300 万,那么应该贷款多长时间呢?可以使用函数 np.nper() 来完成该任务,该函数定义如下:

  • numpy.nper(利率, 还款能力, 贷款数目, 剩余贷款数目=0)

对于我们的场景,可以使用下面的方法来计算:

  • np.nper(0.05/12, -13000, 3000000, 0)
  • array(783.57108846)

结果是需要 783 个月才能还清。这里有一个问题,如果每个月还款的数目小于贷款每月产生的利息,那么就永远也还不清,而且欠款还会随着时间而增加。例如上面的例子,300 万每个月的利息是 12500,如果还款低于这个值就永远也还不完了。

如果希望查看每个月还的利息是多少,可以使用利息的计算函数 np.ipmt(),该函数定义如下:

  • np.ipmt(利率, 时间段列表, 还款年限, 贷款数目, 未来剩余贷款数目=0)

还是以上面的买房贷款为例,可以看到下面的情况:

  • per = np.arange(10*12) + 1 # 前10年还的利息
  • ipmt = np.ipmt(0.05/12, per, 783, 3000000)
  • ipmt # 每个月支付的利息,负数表示支付
  • array([-12500. , -12497.91151511, -12495.81432821, -12493.70840303,
  • -12491.59370315, -12489.47019203, -12487.33783295, -12485.19658903,
  • … # 省略中间数据
  • -12202.70446367, -12199.37724738, -12196.0361677 , -12192.68116684,
  • -12189.31218682, -12185.92916938, -12182.53205603, -12179.12078805])

可以很容易发现每个月还的利息数目都在减少,因为每个月都还了一部分本金,随着本金的减少,利息的基数也在减少,所以利息也在减少。

如果希望得到全部利息的数目,也就是贷款所支付的利息总和,可以对利息列表求和,方法如下:

  • per = np.arange(783) + 1 # 总计783个月
  • ipmt = np.ipmt(0.05/12, per, 783, 3000000)
  • ipmt.sum() # 总计利息为717
  • -7179968.0796168335

可以看到利息数目比较大,为了解决这个问题,可以提高每个组的还款金额或者减少还款周期,例如调整为 25 年还完,那么利息总额为:

  • per = np.arange(12*25) + 1
  • ipmt = np.ipmt(0.05/12, per, 12*25, 3000000)
  • ipmt.sum() # 利息总额是226
  • -2261310.3735718103

所以说在 5% 的年化利率情况下,等额还款方式,贷款 25 年,利息约是本金的 75%。这是比较常见的情况,如果将年限降低为 15 年,那么可以得到如下的利息总额:

  • per = np.arange(12*10) + 1
  • ipmt = np.ipmt(0.05/12, per, 12*10, 3000000)
  • ipmt.sum() # 利息总额是81
  • -818358.548606708

可以看到利息数目大幅下降,但每月的还款金额却上升的很大,每月需要支付的还款金额为:

  • np.pmt(0.05/12, 12*15, 3000000)
  • -23723.808802246393 # 每月支付的金额

本金还款计划和利息的计算方法类似,不过需要将 ipmt() 函数改为 ppmt() 函数。下面是贷款 300万,等额还款 783 个月的情况:

  • per = np.arange(10*12) + 1 # 头10年还的利息
  • ppmt = np.ppmt(0.05/12, per, 783, 3000000)
  • ppmt
  • array([-501.23637244, -503.32485732, -505.42204423, -507.52796941,
  • -509.64266928, -511.7661804 , -513.89853949, -516.0397834 ,
  • -518.18994917, -520.34907396, -522.5171951 , -524.69435008,
  • -526.88057654, -529.07591227, -531.28039524, -533.49406355,
  • -535.71695548, -537.94910947, -540.19056409, -542.44135811,
  • -544.70153043, -546.97112014, -549.25016648, -551.53870884,
  • -553.83678679, -556.14444007, -558.46170857, -560.78863235,
  • -563.12525165, -565.47160687, -567.82773857, -570.19368748,
  • -572.56949451, -574.95520073, -577.3508474 , -579.75647593,
  • -582.17212792, -584.59784512, -587.03366947, -589.4796431 ,
  • -591.93580827, -594.40220748, -596.87888334, -599.36587869,
  • -601.86323652, -604.371 , -606.8892125 , -609.41791755,
  • -611.95715888, -614.50698037, -617.06742612, -619.6385404 ,
  • -622.22036765, -624.81295252, -627.41633982, -630.03057457,
  • -632.65570196, -635.29176739, -637.93881642, -640.59689482,
  • -643.26604855, -645.94632375, -648.63776676, -651.34042413,
  • -654.05434256, -656.77956899, -659.51615052, -662.26413449,
  • -665.02356838, -667.79449991, -670.576977 , -673.37104773,
  • -676.17676043, -678.9941636 , -681.82330595, -684.66423639,
  • -687.51700404, -690.38165823, -693.25824847, -696.1468245 ,
  • -699.04743627, -701.96013392, -704.88496782, -707.82198851,
  • -710.7712468 , -713.73279366, -716.7066803 , -719.69295814,
  • -722.6916788 , -725.70289412, -728.72665618, -731.76301725,
  • -734.81202982, -737.87374661, -740.94822056, -744.03550481,
  • -747.13565275, -750.24871797, -753.37475429, -756.51381577,
  • -759.66595667, -762.83123149, -766.00969495, -769.20140201,
  • -772.40640785, -775.62476789, -778.85653775, -782.10177333,
  • -785.36053072, -788.63286626, -791.91883654, -795.21849836,
  • -798.53190877, -801.85912505, -805.20020474, -808.55520559,
  • -811.92418562, -815.30720306, -818.7043164 , -822.11558439])

可以看到最开始时还的本金特别少,而且本金在逐月增加。

总的来说,每个月还给银行的钱分为两部分,一部分是利息,一部分是本金,可以使用的公式表示:

本金+利息=每月还款额

因此,如果本金等于 0,那么就永远也还不完;如果本金小于 0,那么不仅还不完,而且背负的债务还会随时间而增加;只有当本金大于 0 时才是正常的还款情况。

利息=剩余本金*利率

剩余本金=上次剩余本金–最近一次归还本金

归还贷款的最终目的就是将剩余本金降低为 0。当剩余本金降低为 0 时,利息也降低为 0。

基础 -> 傅里叶变换

傅里叶变换是将时域数据转换成频域数据。例如周期为25的正弦波可以用下面的函数来表示:

  • y=sin(2π*f*x)=sin(50πx)

如果以 150Hz 的采样频率来采样,也就是在 0 到 1 之间有 150 个采样点,那么其时间列表,即公式中的 x 的列表如下:

  • [0. 0.00666667 0.01333333 0.02 0.02666667 0.03333333
  • 0.04 0.04666667 0.05333333 0.06 0.06666667 0.07333333
  • …. 省略中间数据
  • 0.88 0.88666667 0.89333333 0.9 0.90666667 0.91333333
  • 0.92 0.92666667 0.93333333 0.94 0.94666667 0.95333333
  • 0.96 0.96666667 0.97333333 0.98 0.98666667 0.99333333]

得到的输出列表,即 y 的列表如下:

  • [ 0.00000000e+00 8.66025404e-01 8.66025404e-01 1.22464680e-16
  • -8.66025404e-01 -8.66025404e-01 -2.44929360e-16 8.66025404e-01
  • …. 省略中间数据
  • 2.25434048e-14 8.66025404e-01 8.66025404e-01 -1.17627991e-14
  • -8.66025404e-01 -8.66025404e-01]

将这些数据画成一个图,就如图 1 所示。

在这里插入图片描述

如何将它们转换成频域图呢?很简单,只需将 y 输入到 np.fft.fft() 函数即可。下面是实现的代码:

  • import numpy as np
  • import matplotlib.pyplot as plt
  • from numpy.fft import fft,ifft
  • # x是时域值
  • # y是频域值
  • # time_span是采样时长
  • def show(x, ft, time_span = 5):
  • n = len(x) # 采样点个数
  • interval = time_span / n
  • frequency = np.arange(n / 2) / (n * interval)
  • nfft = abs(ft[range(int(n / 2))] / n )
  • plt.plot(frequency, nfft, 'red')
  • plt.xlabel('Freq (Hz)'), plt.ylabel('Amp. Spectrum')
  • #plt.show()
  • plt.savefig("fftv2_1_1.png")
  • time = np.arange(0, 5, .005)
  • x = np.sin(2 * np.pi * 10 * time) # 时域信号
  • y = np.fft.fft(x) # 频域信号
  • show(x, y, 5)
在这里插入图片描述

如果输入信号中带有两个不同幅度的正弦信号,例如输入信号为:

  • y=sin(2*10πx)+3sin(2*50πx)
在这里插入图片描述

那么它们的傅里叶变换代码如下:

  • import numpy as np
  • import matplotlib.pyplot as plt
  • from numpy.fft import fft, ifft
  • # x是时域值
  • # y是频域值
  • # time_span是采样时长
  • def show(x, ft, time_span = 5):
  • n = len(x) # 采样点个数
  • interval = time_span / n
  • frequency = np.arange(n / 2) / (n * interval)
  • nfft = abs(ft[range(int(n / 2))] / n )
  • plt.plot(frequency, nfft, 'red')
  • plt.xlabel('Freq (Hz)'), plt.ylabel('Amp. Spectrum')
  • #plt.show()
  • plt.savefig("fftv2_1_2.png")
  • time = np.arange(0, 5, .0005)
  • x0 = np.sin(2 * np.pi * 10 * time) # 10HZ
  • x1 = 3 * np.sin(2 * np.pi * 50 * time) # 30HZ
  • x = x0 + x1 # 时域信号
  • y = np.fft.fft(x) # 频域信号
  • show(x, y, 5)
在这里插入图片描述

反变换也很简单,下面便是一个反变换的例子代码:

  • import numpy as np
  • import matplotlib.pyplot as plt
  • from numpy.fft import fft,ifft
  • # 在0到2π之间取50个点
  • x = np.linspace(0, 2*np.pi, 50)
  • wave = np.cos(x) # 时域的值
  • transformed=np.fft.fft(wave) # 傅里叶变换
  • reversed_data = np.fft.ifft(transformed) # 反变换
  • plt.plot(x, wave, 'r')
  • # 反变换出来的值+0.2,以免和变换之前的值重合
  • plt.plot(x, reversed_data.real+0.2, 'b')
  • plt.savefig("fft4.png")

运行该脚本,可以得到如图 5 所示的时域图,其中上面那条曲线是傅里叶变换后再傅里叶反变换并向上移动 0.2 的曲线;下面那条曲线是 y=cos(x) 的曲线。可以发现傅里叶变换后再次反变换得到的曲线近似于输入的曲线。

在这里插入图片描述

基础 -> 在神经网络中的应用

在 20 世纪,人们认为任何神经网络都可以等效于某个 3 层的神经网络,这样就没有必要去研究多层的神经网络。直到最近几年人们才意识到多层神经的独特用途,其在图片识别、博弈等方面有着很大的优势。但不论是多少层的神经网络,其基本工作单元都是神经元,通过多个神经的不同连接方式来搭建不同的神经网络,从而解决不同的问题。

本节将介绍神经元和最简单的神经网络,以及基本的神经网络参数训练。

由于神经网络是由很多的神经元组成,神经元又是由多个输入和一个输出组成,而对于前向神经网络,最终输出和输入之间的关系基本可以用一个矩阵来表示,这和 NumPy 的基本数据结构 ndarray 是很一致的,所以很多 NumPy 的方法也可以用在神经网络技术上。

每个神经元有 n 个输入 x,一个输出 y,输出和输入的关系可以用下面的数学公式表示

  • y=S(m)
  • m=w1x2+w2x2+...+wnxn

简单来说就是对所有输入求一个加权和,然后通过 S(x) 这个函数输出出来,不同的加权和标识不同的神经网络。我们也可以用图 1 来表示神经元的基本形式。

在这里插入图片描述

S(x) 这个函数一般来说是固定的,主要是为了将 y 的输出范围压缩到指定的范围。常用的 S(x) 是 Sigmoid 函数,该函数定义如下:

在这里插入图片描述

可以使用下面的代码来画出该函数输入 x 和输出 y 的关系:

  • import numpy as np
  • import matplotlib.pyplot as plt
  • x = np.arange(-10,10,0.01)
  • y = 1.0/(np.exp(x*-1.0)+1.0)
  • plt.plot(x, y, 'b') # 画图
  • plt.savefig("sigmod1.png")
在这里插入图片描述

我们可以发现其规律如下:曲线是平滑的;输出 y 随输入 x 单调递增;输出 y 的范围是 0~1;当 x 超出 -5~5 这个范围,输出 y 基本等于 0 或者 1,和数字信息一致。由于有这些特性,Sigmoid 函数被广泛应用在各种神经元。

该函数还有一个特别的地方,就是求导特别方便,下面是其导数计算公式:

在这里插入图片描述

在训练模型的过程中,如果发现对于输入 x,输出 y 和目标输出 y0 存在差别 ∆y,就需要调整权重 w 来消除这种差别。方法就是找到 ∆w,让新的 w’=w+∆w。

该如何找到这个 ∆w 呢?这时就需要求导了,我们需要知道 y 对 w 的在当前 x 位置的导数 ∂,∆y=∆w∂,由于知道了 ∆y 和 ∂,便可以求出 ∆w。但在实际应用中我们并不会使用这个 ∆w,而是自己定义一个固定的步长 s。∂ 的作用是规定了移动的方向,s 确定了移动的长度,结合 s 和 ∂ 可以让 ∆y 变小。

按照这种方式多次迭代就可以让 ∆y 趋近于 0。这个过程就是模型训练,训练的目的就是调整权重 w 以消除 ∆y。∆y 也叫损失函数,就是真实输出和期待输出之间的差别。这种计算 ∂ 的办法也叫作梯度下降法,就是确定某个位置 x 最快下降方向。

在实际应用中,网络非常复杂,包含的神经元个数庞大,神经元之间的连接方式也是数量庞大。为了演示神经网络的使用,不太可能拿实际使用情况作为例子,这里仅以单个神经元组成的神经网络作为例子。该神经元有 3 个输入,输入基本就是 0 和 1;该神经元有一个输出,输出也只有 0 和 1 两个值,它们可以用图 5 表示。

在这里插入图片描述

该神经元的输入和输出的关系如表 6 所示

在这里插入图片描述

这里使用单个神经元来达到设计目的。由于仅有一个神经元,所以参数个数也就只有 3 个,分别是 w1、w2 和 w3。我们的任务就是通过给代码输入期望的结果来训练这 3 个参数。

  • import numpy as np
  • class NeuralNetwork():
  • def __init__(self):
  • # 设置随机数种子
  • np.random.seed(1)
  • # 将权重转化为一个3x1的矩阵,其值分布为-1~1,并且均值为0
  • self.weights = 2 * np.random.random((3, 1)) - 1
  • def sigmoid(self, x):
  • # 应用Sigmoid激活函数
  • return 1 / (1 + np.exp(-x))
  • def sigmoid_derivative(self, x):
  • #计算Sigmoid函数的偏导数
  • return x * (1 - x)
  • def train(self, training_inputs, training_outputs, iterations_num):
  • # 训练模型
  • # 输入是training_inputs,是一个二维矩阵
  • # 期待值是training_outputs,是一个一维矩阵
  • # iterations_num是迭代的次数
  • for iteration in range(iterations_num):
  • # 得到输出
  • output = self.think(training_inputs)
  • # 计算误差
  • error = training_outputs - output
  • # 微调权重
  • adjustments = np.dot(training_inputs.T, error * self.sigmoid_
  • derivative(output))
  • self.weights += adjustments
  • def think(self, inputs):
  • # 基于当前参数,计算inputs的输出
  • inputs = inputs.astype(float)
  • output = self.sigmoid(np.dot(inputs, self.weights))
  • return output
  • if __name__ == "__main__":
  • # 初始化神经类
  • neural_network = NeuralNetwork()
  • print(u"随机生成最初的权重值")
  • print(u"初始权重值为:", neural_network.weights)
  • #训练数据的输入部分
  • training_inputs = np.array([[0,0,1],
  • [1,1,1],
  • [1,0,1],
  • [0,1,1]])
  • # 训练数据的输出
  • training_outputs = np.array([[0,1,1,0]]).T
  • # 开始训练,进行150000次训练
  • neural_network.train(training_inputs, training_outputs, 15000)
  • print(u"训练后的权重:", neural_network.weights)
  • # 验证结果
  • y = neural_network.think(np.array(training_inputs[0]))
  • assert abs(y - training_outputs[0]) < 1e-2
  • y = neural_network.think(np.array(training_inputs[1]))
  • assert abs(y - training_outputs[1]) < 1e-2
  • y = neural_network.think(np.array(training_inputs[2]))
  • assert abs(y - training_outputs[2]) < 1e-2
  • y = neural_network.think(np.array(training_inputs[3]))
  • assert abs(y - training_outputs[3]) < 1e-2
  • print(u"验收通过")

$ python ex1.py

随机生成最初的权重值

初始权重值为: [[-0.16595599]

[ 0.44064899]

[-0.99977125]]

训练后的权重: [[10.08740896]

[-0.20695366]

[-4.83757835]]

验收通过

可以发现,其实训练就是调整权重参数的一个过程。虽然不知道最终我们期望的参数是多少,但是可以通过比较实际输出和期望输出的差值来微调这些权重,最终可以达到输出和我们的期望一致。


详解(附带案例)

使用np的routines函数创建

np.ones(shape, dtype=None, order=‘C’)

注:函数返回给定形状和数据类型的新数组,其中元素的值设置为1。

  • shape 形状是一个int或一个int元组,用于定义数组的大小。 如果我们仅指定一个int变量,则将返回一维数组。 对于一个整数元组,将返回给定形状的数组。
  • dtype是一个可选参数,默认值为float。 它用于指定数组的数据类型,例如int。
  • order该顺序定义是在内存中以行优先(C风格)还是列优先(F风格)顺序存储多维数组。
    • t = np.ones([3, 3])
    • print(t)
    • 输出:
    • [[1. 1. 1.]
    • [1. 1. 1.]
    • [1. 1. 1.]]
    • t = np.ones([3, 3], dtype=int)
    • print(t)
    • 输出:
    • [[1 1 1]
    • [1 1 1]
    • [1 1 1]]
    numpy.full(shape, fill_value, dtype=None, order=‘C’)[source]
    注:返回一个根据指定shape和type,并用fill_value填充的新数组。
  • shape:整数或整数序列新数组的形态,单个值代表一维,参数传元组,元组中元素个数就代表是几维,例如, (2, 3) or 2.
  • fill_value: 标量(无向量)填充数组的值
  • dtype:数据类型,可选默认值为None
    查看要填充数组的值数据类型:np.array(fill_value).dtype。
  • order:{‘C’, ‘F’}, 可选是否在内存中以行为主(C风格)或列为主(Fortran风格)连续(行或列)顺序存储多维数据。
    • np.full((2,3), 3) # 23列,填充值为3
    • 输出:
    • [[3, 3, 3],
    • [3, 3, 3]]

numpy.eye(N, M=None, k=0, dtype=<class ‘float’>, order=‘C’)

注: 返回一个二维数组,其对角线元素为1,其余位置元素为0。

  • N返回数组的行数
  • M列数(不常用)
  • K对角线的索引:0(默认值)代表主对角线,正整数代表上三角内的对角线,负整数代表下三角内的对角线。
  • dtype返回数组的数值类型
  • {‘C’, 'F},可选参数是否在内存中以C或fortran(行或列)顺序存储多维数据,版本1.14.0中的新特性
    • np.eye(5,k=1) # 55列,从第1个元素为对角填充1
    • 返回值:维度为(N,M)的多维数组 除了第k条对角线上元素为1以外,其余元素均为0的数组
    • 输出:
    • [[0., 1., 0., 0., 0.],
    • [0., 0., 1., 0., 0.],
    • [0., 0., 0., 1., 0.],
    • [0., 0., 0., 0., 1.],
    • [0., 0., 0., 0., 0.]]
    • np.eye(3,4) # 34
    • 输出:
    • [1., 0., 0., 0.],
    • [0., 1., 0., 0.],
    • [0., 0., 1., 0.]]

linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)

在指定的大间隔内,返回固定间隔的数据。他将返回“num”个等间距的样本,在区间[start, stop]中。其中,区间的结束端点可以被排除在外。

当‘endpoint=False’时,不包含该点。在这种情况下,队列包含除了“num+1"以外的所有等间距的样本。

要注意的是,当‘endpoint=False’时,步长会发生改变。

  • np.linspace(0,10,5) # 返回010的等差数列(默认包含10)
  • 输出:
  • [ 0. , 2.5, 5. , 7.5, 10. ]
  • np.linspace(1,11, 6, retstep=True) # 返回步进差值,二元组
  • 输出:
  • ([ 1., 3., 5., 7., 9., 11.]), 2.0)
  • 注意:np.arange([start, ]stop, [step, ]dtype=None) # 返回等差数列,
  • 区别:
  • arange()类似于内置函数range(),通过指定开始值、终值和步长创建表示等差数列的一维数组,注意
  • 得到的结果数组不包含终值。
  • linspace()通过指定开始值、终值和元素个数创建表示等差数列的一维数组,可以通过endpoint参数
  • 指定是否包含终值,默认值为True,即包含终值

np.random.randint(low, high=None, size=None, dtype=‘l’)

随机数组

  • import numpy as np
  • r = np.random.randint(0, 10, 6)
  • print(r)
  • # 输出: [1 0 1 3 6 4]

np.random.randn(d0, d1, …, dn)

  • np.random.randn(10)
  • # 每次都不一样
  • # 输出结果:
  • array([-1.74976547, 0.3426804 , 1.1530358 , -0.25243604, 0.98132079,
  • 0.51421884, 0.22117967, -1.07004333, -0.18949583, 0.25500144])
  • //
  • np.random.seed(100) #随机的种子,有了种子,每次都一样
  • np.random.randn(10)
  • # 输出结果:
  • array([ 0.37332715, -0.2887605 , 0.04985088, -0.93815832, -0.4087037 ,
  • 1.13352254, 0.52713526, -0.76014192, -0.97292788, 0.16290446])

np.random.random(size=None)

  • np.random.random(100)
  • # 每次每次都不一样
  • # 输出结果:
  • array([ 0.01150584, 0.52951883, 0.07689008, 0.72856545, 0.26700953,
  • 0.38506149, 0.56252666, 0.59974406, 0.38050248, 0.14719008,
  • 0.6360734 , 0.27812695, 0.73241298, 0.10904588, 0.57071762,
  • 0.56808218, 0.33192772, 0.61444518, 0.07289501, 0.86464595,
  • 0.71140253, 0.3221285 , 0.92556313, 0.26511829, 0.8487166 ,
  • 0.38634413, 0.32169243, 0.80473196, 0.92050868, 0.17325157,
  • 0.63503329, 0.89463233, 0.02796505, 0.04396453, 0.20603116,
  • 0.77663591, 0.96595455, 0.77823865, 0.90867045, 0.39274922,
  • 0.89526325, 0.26002297, 0.38606984, 0.69176715, 0.3170825 ,
  • 0.86994578, 0.35648567, 0.19945661, 0.16109699, 0.58245076,
  • 0.20239367, 0.7099113 , 0.41444565, 0.16725785, 0.01170234,
  • 0.79989105, 0.76490449, 0.25418521, 0.55082581, 0.29550998,
  • 0.02919009, 0.32737646, 0.29171893, 0.67664205, 0.24447834,
  • 0.49631976, 0.41136961, 0.82478264, 0.76439988, 0.78829201,
  • 0.24360075, 0.26151563, 0.51388418, 0.19823452, 0.44097815,
  • 0.53198973, 0.50187154, 0.72374522, 0.11090765, 0.63469357,
  • 0.69199977, 0.97093079, 0.35920669, 0.86493051, 0.01984456,
  • 0.32219702, 0.58608421, 0.26591245, 0.51851213, 0.7896492 ,
  • 0.04914308, 0.28711285, 0.36225247, 0.21299697, 0.99046025,
  • 0.11375325, 0.70964612, 0.06599185, 0.47323442, 0.62003386])
  • ///
  • np.random.random([3,3])
  • # 输出结果:
  • array([[ 0.37590691, 0.15563239, 0.7754904 ],
  • [ 0.40353019, 0.59708594, 0.57000741],
  • [ 0.33286511, 0.15678606, 0.58814922]])

np.random.normal(loc=0.0, scale=1.0)

  • np.random.normal(loc=0.0, scale=1.0)
  • # 输出: 0.9705556599476601

np.random.rand(d0,d1,…dn)

  • 注:使用方法与np.random.randn()函数相同
  • 作用:
  • 通过本函数可以返回一个或一组服从“0~1”均匀分布的随机样本值。随机样本取值范围是[0,1),不包括1
  • 应用:在深度学习的Dropout正则化方法中,可以用于生成dropout随机向量(dl),例如(keep_prob表
  • 示保留神经元的比例):dl = np.random.rand(al.shape[0],al.shape[1]) < keep_prob
  • np.random.rand(1,2,3)
  • # 输出:
  • [[[0.77655108 0.94720402 0.60342525]
  • [0.09466063 0.67177335 0.9059549 ]]]

ndarray的属性

ndim:维度

shape:形状(各维度的长度)

size:总长度

dtype:元素类型

  • np.random.seed(0)
  • x = np.random.randint(10,size=(3,4,5))
  • print(x)
  • array([[[5, 0, 3, 3, 7],
  • [9, 3, 5, 2, 4],
  • [7, 6, 8, 8, 1],
  • [6, 7, 7, 8, 1]],
  • [[5, 9, 8, 9, 4],
  • [3, 0, 3, 5, 0],
  • [2, 3, 8, 1, 3],
  • [3, 3, 7, 0, 1]],
  • [[9, 9, 0, 4, 7],
  • [3, 2, 7, 2, 0],
  • [0, 4, 5, 5, 6],
  • [8, 4, 1, 4, 9]]])
  • # 维度:x.ndim
  • # 形状,各维度的长度:x.shape
  • # 总长度:x.size
  • 元素类型:x.dtype

ndarray的基本操作

索引

  • # 一维与列表完全一致 多维时同理
  • np.random.seed(1)
  • x = np.random.randint(10,size=[3,4,5])
  • print(x[2,0,0])
  • print(x)
  • 5
  • [[[5 8 9 5 0]
  • [0 1 7 6 9]
  • [2 4 5 2 4]
  • [2 4 7 7 9]]
  • [[1 7 0 6 9]
  • [9 7 6 9 1]
  • [0 1 8 8 3]
  • [9 8 7 3 6]]
  • [[5 1 9 3 4]
  • [8 1 4 0 3]
  • [9 2 0 4 9]
  • [2 7 7 9 8]]]

切片

  • np.random.seed(0)
  • x = np.random.randint(100,size = (10,4))
  • x
  • # 输出结果:
  • array([[44, 47, 64, 67],
  • [67, 9, 83, 21],
  • [36, 87, 70, 88],
  • [88, 12, 58, 65],
  • [39, 87, 46, 88],
  • [81, 37, 25, 77],
  • [72, 9, 20, 80],
  • [69, 79, 47, 64],
  • [82, 99, 88, 49],
  • [29, 19, 19, 14]])
  • # 切片:
  • x[7:10]
  • # 切片结果:
  • array([[69, 79, 47, 64],
  • [82, 99, 88, 49],
  • [29, 19, 19, 14]])

变形

  • # 使用reshape函数,注意参数是一个tuple!
  • x = np.arange(0,16).reshape(4,4)
  • x
  • # 执行结果:
  • array([[ 0, 1, 2, 3],
  • [ 4, 5, 6, 7],
  • [ 8, 9, 10, 11],
  • [12, 13, 14, 15]])
  • # 类型是:
  • type(x.shape)

级联

np.concatenate() 级联需要注意的点:

级联的参数是列表:一定要加中括号

维度必须相同

形状相符

【重点】级联的方向默认是shape这个tuple的第一个值所代表的维度方向

可通过axis参数改变级联的方向

  • x = np.array([1,2,3])
  • y = np.array([1,5,6,7,3,20])
  • x
  • # 输出 array([1, 2, 3])
  • # 输出 array([ 1, 5, 6, 7, 3, 20])
  • z = np.concatenate([x,y])
  • z
  • # 输出 array([ 1, 2, 3, 1, 5, 6, 7, 3, 20])
  • z.shape
  • # 输出 (9,)
  • #二维
  • x = np.array([[1,2,3],[4,5,6]])
  • x
  • array([[1, 2, 3],
  • [4, 5, 6]])
  • x.shape
  • (2,3)
  • p = np.concatenate([x,x]).shape
  • p
  • (4, 3)

axis

  • import numpy as np
  • x = np.array([[[1,2,3],[2,2,3],[3,3,3]],[[4,4,4],[5,5,5],[6,6,6]]])
  • print(x)
  • print(x.shape)
  • # 输出:
  • [[[1 2 3]
  • [2 2 3]
  • [3 3 3]]
  • [[4 4 4]
  • [5 5 5]
  • [6 6 6]]]
  • (2, 3, 3)
  • /
  • w = np.concatenate([x,x],axis = 0)
  • print(w.shape)
  • print(w)
  • # 输出:
  • (4, 3, 3)
  • [[[1 2 3]
  • [2 2 3]
  • [3 3 3]]
  • [[4 4 4]
  • [5 5 5]
  • [6 6 6]]
  • [[1 2 3]
  • [2 2 3]
  • [3 3 3]]
  • [[4 4 4]
  • [5 5 5]
  • [6 6 6]]]
  • /
  • w = np.concatenate([x,x],axis = 1)
  • print(w.shape)
  • print(w)
  • # 输出:
  • (2, 6, 3)
  • [[[1 2 3]
  • [2 2 3]
  • [3 3 3]
  • [1 2 3]
  • [2 2 3]
  • [3 3 3]]
  • [[4 4 4]
  • [5 5 5]
  • [6 6 6]
  • [4 4 4]
  • [5 5 5]
  • [6 6 6]]]
  • //
  • w = np.concatenate([x,x],axis = 2)
  • print(w.shape)
  • print(w)
  • # 输出:
  • (2, 3, 6)
  • [[[1 2 3 1 2 3]
  • [2 2 3 2 2 3]
  • [3 3 3 3 3 3]]
  • [[4 4 4 4 4 4]
  • [5 5 5 5 5 5]
  • [6 6 6 6 6 6]]]

np.hstack与np.vstack 水平级联与垂直级联

  • x = np.array([[1,1],[2,2],[3,3]])
  • y = np.array([1,2,3])
  • print(np.hstack(x))
  • print(np.vstack(y))
  • # 输出:
  • [1 1 2 2 3 3]
  • [[1]
  • [2]
  • [3]]

切分

np.split()

  • x = np.arange(1,10)
  • x
  • # 输出:
  • array([1, 2, 3, 4, 5, 6, 7, 8, 9])
  • //
  • x1,x2,x3 = np.split(x,[3,5])
  • print(x1,x2,x3)
  • 输出: [1 2 3] [4 5] [6 7 8 9]

np.hsplit()

  • x = np.arange(16).reshape(4,4)
  • x
  • # 输出:
  • array([[ 0, 1, 2, 3],
  • [ 4, 5, 6, 7],
  • [ 8, 9, 10, 11],
  • [12, 13, 14, 15]])
  • //
  • print(np.hsplit(x,[2,3]))
  • # 输出:
  • [array([[ 0, 1],[ 4, 5], [ 8, 9], [12, 13]]),
  • array([[ 2], [ 6], [10], [14]]),
  • array([[ 3], [ 7], [11], [15]])]

np.vsplit()

  • x = np.arange(16).reshape(4,4)
  • x
  • # 输出:
  • array([[ 0, 1, 2, 3],
  • [ 4, 5, 6, 7],
  • [ 8, 9, 10, 11],
  • [12, 13, 14, 15]])
  • print(np.vsplit(x,[2,3]))
  • //
  • # 输出:
  • [array([[0, 1, 2, 3],
  • [4, 5, 6, 7]]), array([[ 8, 9, 10, 11]]), array([[12, 13, 14, 15]])]

副本

所有赋值运算不会为ndarray的任何元素创建副本。对赋值后的对象的操作也对原来的对象生效。

  • a = np.array([1,2,3])
  • b=a
  • print(a,b)
  • # 输出:
  • [1 2 3] [1 2 3]
  • //
  • b[0]=2
  • a
  • # 输出:
  • array([2, 2, 3])

可使用copy()函数创建副本

  • a = np.array([1,2,3])
  • b = a.copy()
  • b
  • # 输出:
  • [1,2,3]
  • //
  • b[0]=3
  • print(a,b)
  • 输出: [1 2 3] [3 2 3]

ndarray的聚合操作

求和np.sum

  • import numpy as np
  • np.random.seed(0)
  • a = np.random.randint(1000,size = 100)
  • print(np.sum(a))
  • //
  • b = np.random.randint(1000,size = (3,4,5))
  • print(np.sum(b))
  • # 输出:
  • 52397
  • 32865
  • //
  • # 计算求和时间
  • %timeit np.sum(a)
  • # 输出:
  • 2.63 µs ± 34.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
  • //
  • l = [1,2,3]
  • np.sum(l)

最大最小值:np.max/ np.min

其他聚合操作

  • # 求平均值
  • np.mean(heights)
  • # 求最大值
  • np.max(heights)
  • # 求最小值
  • np.min(heights)
  • # 计算标准差
  • heights.std()

ndarray的矩阵操作

算术运算符(加减乘除):

  • a = np.array([[1,2,3],
  • [4,5,6]])
  • a
  • # 输出:
  • array([[1, 2, 3],
  • [4, 5, 6]])
  • //
  • a+1
  • # 输出:
  • array([[2, 3, 4],
  • [5, 6, 7]])
  • //
  • a*2
  • # 输出:
  • array([[ 2, 4, 6],
  • [ 8, 10, 12]])
  • //
  • a+[[1,4,9],[3,3,3]]
  • # 输出:
  • array([[ 2, 6, 12],
  • [ 7, 8, 9]])
  • //
  • a*2-2
  • # 输出:
  • array([[ 0, 2, 4],
  • [ 6, 8, 10]])

矩阵积

  • a = np.array([[1,2,3],
  • [4,5,6]])
  • a
  • # 输出:
  • array([[1, 2, 3],
  • [4, 5, 6]])
  • //
  • b = np.array([[1,1],
  • [1,1],
  • [1,1]])
  • b
  • # 输出:
  • array([[1, 1],
  • [1, 1],
  • [1, 1]])
  • //
  • np.dot(a,b)
  • # 输出:
  • array([[ 6, 6],
  • [15, 15]])

广播机制

【重要】ndarray广播机制的两条规则

规则一:为缺失的维度补1

规则二:假定缺失元素用已有值填充

  • # 例1: m = np.ones((2, 3)) a = np.arange(3) 求m+a
  • m = np.ones((2,3))
  • m
  • # 输出:
  • array([[ 1., 1., 1.],
  • [ 1., 1., 1.]])
  • a = np.arange(3)
  • a
  • # 输出:
  • array([0, 1, 2])
  • m+a
  • # 输出:
  • array([[ 1., 2., 3.],
  • [ 1., 2., 3.]])
  • # 例2: a = np.arange(3).reshape((3, 1)) b = np.arange(3) 求a+b
  • a = np.arange(3).reshape((3,1))
  • a
  • # 输出:
  • array([[0],
  • [1],
  • [2]])
  • b = np.arange(3)
  • b
  • # 输出:
  • array([0, 1, 2])
  • a+b
  • # 输出:
  • array([[0, 1, 2],
  • [1, 2, 3],
  • [2, 3, 4]])
  • # 习题 a = np.ones((4, 1)) b = np.arange(4) 求a+b
  • a = np.ones((4,1))
  • b = np.arange(4)
  • a+b
  • # 输出:
  • array([[ 1., 2., 3., 4.],
  • [ 1., 2., 3., 4.],
  • [ 1., 2., 3., 4.],
  • [ 1., 2., 3., 4.]])

ndarray的排序

选择排序

  • import numpy as np
  • a = np.array([33,2,67,9,88,22,34])
  • def selectSort(x):
  • for i in range(len(x)):
  • swap = np.argmin(x[i:])+i
  • [x[i],x[swap]] = [x[swap],x[i]]
  • selectSort(a)
  • a
  • # 输出:
  • array([ 2, 9, 22, 33, 34, 67, 88])

快速排序

  • # np.sort()与ndarray.sort()都可以,但有区别:
  • # 1. np.sort()不改变输入
  • # 2. ndarray.sort()本地处理,不占用空间,但改变输入
  • # np.sort()不改变输入
  • np.random.seed(10)
  • a = np.random.randint(0,100,10)
  • b = np.random.randint(0,100,10)
  • print(a,b)
  • print(np.sort(a),a)
  • # 输入:
  • [ 9 15 64 28 89 93 29 8 73 0] [40 36 16 11 54 88 62 33 72 78]
  • [ 0 8 9 15 28 29 64 73 89 93] [ 9 15 64 28 89 93 29 8 73 0]
  • # ndarray.sort()本地处理,不占用空间,但改变输入
  • np.random.seed(20)
  • a = np.random.randint(0,100,10)
  • b = np.random.randint(0,100,10)
  • print(a,b)
  • print(a.sort(),a)
  • # 输出:
  • [99 90 15 95 28 90 9 20 75 22] [71 34 96 40 85 90 26 83 16 62]
  • None [ 9 15 20 22 28 75 90 90 95 99]
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐