Python进阶之NumPy快速入门(二)

前言

NumPy是Python的一个扩展库,负责数组和矩阵运行。相较于传统Python,NumPy运行效率高,速度快,是利用Python处理数据必不可少的工具

这个NumPy快速入门系列分为四篇,包含了NumPy大部分基础知识,每篇阅读时间不长,但内容含量高。大家最好亲自码一遍代码,这样可以更有收获。

概要

学会数组的运算,轻松应对数学公式

学会数组的索引,瞬间定位数组位置

学会数组的迭代,快速遍历数组元素

01

NumPy数组运算

基础运算

NumPy数组的基本运算,即加减乘除。我们分成两种情况:

  • 数组形状相同时,即对对应元素进行运算,
  • 数组形状不一致的时候有广播机制来弥补

我们先看两个形状一样的数组基础运算:

代码:

import numpy as np

a = np.array([1, 2, 3])
b = np.arange(10,13)
print (a+b, a-b)
print (a*b, a/b)

讲解:

我们建立了a,b两个一维数组,分别采用直接创建和用arange函数创建的方法。对于同样大小的数组之间的加减乘除运算,运算规则是对位元素一一对应。也就是说a的第一个元素和b的第一个元素进行运算,a的第二个元素和b的第二个元素进行运算,以此类推,所有对位的元素进行运算。

运行结果:

[11 13 15] [-9 -9 -9]

[10 22 36] [0.1 0.18181818 0.25]

广播机制

如果a,b两个数组的形状(shape)并不一样,那么运算规则又是什么样子的呢?Numpy对于两个不同形状的数组的运算采用一种叫做广播(broadcast)的机制负责运算:

代码:

a = np.array([[1, 2, 3],[4, 5, 6]])
b = np.arange(0,3)
print (a+b)

讲解:

a是一个2*3的数组,而b的形状是1*3,广播机制会让他们之间的加法得到一个相对合理的结果:

运行结果:

[[1 3 5]

[4 6 8]]

不难发现广播让a中第一个维度[1,2,3]加上b之后成为结果的第一个维度,让a中的第二个维度[4,5,6]加上之后成为结果的第二个维度。广播的规律总结起来有以下几点:

  1. 让所有输入数组都向其中形状最长的数组看齐,形状中不足的部分都通过在前面加 1 补齐。
  2. 输出数组的形状是输入数组形状的各个维度上的最大值。
  3. 如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为 1 时,这个数组能够用来计算,否则出错。
  4. 当输入数组的某个维度的长度为 1 时,沿着此维度运算时都用此维度上的第一组值。

对于NumPy的广播,我给大家的建议是会多少用多少,尽量不要超出自己知识范围内使用。

高级运算:

  • 乘方:numpy.power,用法是numpy(a,n),其中a是NumPy数组,n是幂
  • 取余:numpy.mod(a,b),数组a对于数组b除法后取余数。
  • 三角函数:numpy.sin(), numpy.cos()等

代码:

a = np.array([1, 2, 3])
b = np.arange(10,13)
print (a**2, np.power(a,2))
print (np.sin(a))
print (np.mod(b,a))

讲解:

我们建立了a,b两个数组,第一个运算是求a每个元素的平方,有两种方法实现,二者结果相同。第二个运算,我们尝试了一下三角函数中的正弦函数。最后,我们用数组b对于数组a取余运算,除了11对于2取余等于1之外,其余都是0。

运行结果:

[1 4 9] [1 4 9]

[0.84147098 0.90929743 0.14112001]

[0 1 0]

02

NumPy索引

索引就是像是GPS导航,可以直接到数组中的特定位置的元素。我们把数组的索引按方式不同分成两种,然后分别介绍:

  • 数字索引
  • 布尔(条件)索引

数字索引

数字索引,顾名思义,就是根据数字来定位数组中元素,这个十分好理解。我们将数字索引分成两种方式:

  1. 单个数字索引
  2. 范围数字索引

对于一维数组,单个数字索引和列表方法一样。比如我们有一个数组A,那么A[x]就是索引A数组中的第x个元素,这里切记x从0开始计数,所以准确来讲是索引第x+1个元素。

对于二维的NumPy数组,我们也可以用一维索引的方法,这时我们会索引出某一行。

代码:

import numpy as np
A = np.arange(0,12)
print (A[3])
A = A.reshape((2,6))
print (A[1])

讲解:

我们首先建立了一个0到11的数组A,我们试图索引它的第四个元素。接着我们利用了一个变形技术reshape把A转换成一个二维数组,然后用一维索引得到变形后的第二行所有元素。

运行结果:

3

[ 6 7 8 9 10 11]

单个数字也可以扩展到二维甚至更高维度,例如对于二维数组索引方式一般可以写成A[1,1]或者A[1][1]。

现在我们着重介绍一下用冒号进行范围索引,因为我们有时候想要一段的数组,这时候范围索引就显得很方便实用。具体而言,有两种方式:

  • a:b,从a位置出发到b位置结束。
  • a:b:c,a是起始值,b是终止值,c是步长。

代码:

A = np.eye(5)
print (A[2,2], A[2][2])
print (A[1][0:4:2])

讲解:

我们首先用numpy.eye()函数建立了一个5乘以5的单位矩阵。先测试一下二维索引中单体索引,A[2,2]和A[2][2]两种方式都是可以的。接着我们测试一下范围索引,第一个[1]表示A矩阵的第二行:[0 1 0 0 0];后面的[0:4:2]其实只能索引出来两个数字,就是0和3两个位置上的数字。

运行结果:

1.0 1.0

[0. 0.]

布尔索引

这是一种通过布尔(逻辑)运算来获得符合条件元素的索引方式。简单来说,你可以通过给定一定的条件,筛选出满足条件的元素。这种索引方式是我们日常使用Numpy数组较为常用和使用的方法。

代码:

A = np.arange(0,9).reshape(3,3)
B = np.array([1,  2+6j,  5,  3.5+5j])
print (A>5)
print (A[A>5])
print (B[np.iscomplex(B)])

讲解:

我们先用两行代码给大家展示一下布尔索引的运算过程,第18行代码其实才是完整的操作,打印出A数组中大于5的元素,以一个一维数组的形式数出来。第17代码其实给出布尔运算的一步,输出结果为:大于5的位置是True而小于5的位置是False,接着通过真假关系带入A数组,最终把真的元素挑出来。这就是布尔索引的运算过程。B是一个打印出复数元素的例子,原理是一样的。

03

数组迭代

这一节课我们尝试用循环的方式,遍历数组中所有元素。考虑到常见的数组往往不止一个维度,因此单纯用while和for循环写起来很费事,所以我们有必要学习NumPy自带的遍历方法。

迭代数组 nditer

Numpy自带一个数组迭代器,叫nditer,可以让我们灵活访问数组中元素:

代码:

import numpy as np
A = np.arange(0,12).reshape(3,4)
for n in np.nditer(A):
 print (n, end=' ')

讲解:

我们照例创建了一个形状为(3,4)的二维数组A,利用nditer配合for循环的格式,依次迭代访问数组A中的元素。注意到在print函数中,我们给参数end赋值了一个空格字符串,目的是让打印出来的元素可以被空格间隔。

运行结果:

0 1 2 3 4 5 6 7 8 9 10 11

大家可以尝试一下给end赋值别的字符串,例如逗号,换行等等。

控制顺序

事实上,nditer有一个参数来控制遍历顺序。这个参数叫order,有两个值可以选择:

  • 如果order='C',那么就会按行优先的顺序访问;
  • 如果order='F',那么则会按列顺序优先访问。

我们来看个例子:

代码:

B = np.arange(0,9).reshape(3,3)
for n in np.nditer(B,order='C'):
 print (n, end=' ')
print ('\n')   
for n in np.nditer(B, order='F'):
 print (n, end=' ') 

讲解:

正如我们上面所说,'C'和'F'分别代表行和列优先。值得一提的这里的C,F并不是我们常见的row和column的缩写,而是代码C语言标准格式和Fortran格式,二者都是一种程序语言。

运行结果:

0 1 2 3 4 5 6 7 8

0 3 6 1 4 7 2 5 8

修改元素

nditer在遍历数组的时候,给我们提供了一个读写的选项,也就是说,我们根据这个读写开关可以改变数组的数值。这个参数叫做op_flags,默认值是只读模式'read-only',此时不可以修改元素。但是我们可以让op_flags赋值'readwrite' 或者 'writeonly':

代码:

C = np.arange(0,8).reshape(2,4)
for n in np.nditer( C,op_flags=['writeonly'] ):
 n[...] = 2*n
print (C) 

讲解:

我们利用'writeonly'将遍历的读写模式变成只写模式,大家也可以尝试'readwrite'一下看看效果如何。对于每个元素,我们都让它扩大两倍。有一点,我们用了n[...]格式,让乘以两倍后的元素重新赋值回去,[...]不可或缺。

运行结果:

[[ 0 2 4 6]

[ 8 10 12 14]]

总结回顾

1

学习了基础运算,以及当数组形状不一致时候的广播机制;高级运算。

2

学习用数字和逻辑索引两种基本数组索引方式。

3

学习了数组的迭代器,以及迭代顺序的控制。

本文分享自微信公众号 - Python与机器学习之路(gh_39aead19f756)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏相约机器人

17种深度强化学习算法用Pytorch实现

深度强化学习已经在许多领域取得了瞩目的成就,并且仍是各大领域受热捧的方向之一。本文推荐一个包含了 17 种深度强化学习算法实现的 PyTorch 代码库。

21040
来自专栏汇智网教程

Pandas DataFrame创建方法大全

Pandas是Python的数据分析利器,DataFrame是Pandas进行数据分析的基本结构,可以把DataFrame视为一个二维数据表,每一行都表示一个数...

26720
来自专栏JAVAandPython君

10分钟带你学完Python基础

这篇文章是我总结的python的基础,同时也参考了一些资料,内容不是特别全面,目的是带大家来看看Python里面非常基础的一些东西,想要更详细的了解,大家可以去...

10360
来自专栏小詹同学

深入理解 Python 中的上下文管理器

操作文本对象的时候,几乎所有的人都会让我们要用 with open ,这就是一个上下文管理的例子。你一定已经相当熟悉了,我就不再废话了。

6630
来自专栏JAVAandPython君

Python可视化学习(饼状图,坐标系...)

今天资源君带大家学习一下Python的可视化,何谓可视化呢?我们常常听说Python的数据分析,数据分析中很重要的一个就是将数据展示出来,如何展示出来呢...

28910
来自专栏安恒网络空间安全讲武堂

通过SSH隧道传递票证

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测以及文章作者不为此承担任何责任。 雷神众测拥有对此文章的修改和...

9730
来自专栏新智元

17种深度强化学习算法用Pytorch实现

深度强化学习已经在许多领域取得了瞩目的成就,并且仍是各大领域受热捧的方向之一。本文推荐一个包含了 17 种深度强化学习算法实现的 PyTorch 代码库。

10920
来自专栏二狗的DBA之路

pip-修改为国内镜像源

44630
来自专栏二狗的DBA之路

shell脚本检测https证书有效期

申请的https证书越多,管理起来越容易出问题,因此有必要添加定期巡检的脚本(当然,首先要把https证书的申请权限收口到运维侧统一管理,不然还是无法根治问题)

15430
来自专栏从零开始学自动化测试

python测试开发django-59.restful接口开发

REST 不是什么具体的软件或者代码,而是一种思想。现在流行前后端分离开发项目,一般用 json 来交换数据。 相信写过模板的同学都知道,只要哪怕页面中的数据有...

12430

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励