文章目录

  • 1. 索引和切片
  • 2. 改变结构
  • 3. 合并与拆分
  • 4. 复制
  • 5. 排序
  • 6. 查找和筛选
    • 6.1 查找
    • 6.2 筛选
  • 7. 数组I/O

1. 索引和切片

NumPy数组对象的内容可以通过索引或切片来访问和修改。对于一维数组的索引和切片,NumPy数组和Python的列表一样灵活。

a = np.arange(9)
>>> a[-1]                            # 最后一个元素
8
>>> a[2:5]                           # 返回第2到第5个元素
array([2, 3, 4])
>>> a[:7:3]                          # 返回第0到第7个元素,步长为3
array([0, 3, 6])
>>> a[::-1]                          # 返回逆序的数组
array([8, 7, 6, 5, 4, 3, 2, 1, 0])

对于多维数组操作,NumPy数组比 Python的列表更加灵活、强大。假设有一栋2层楼,每层楼内的房间都是3行4列,那我们可以用一个三维数组来保存每个房间的居住人数(当然,也可以是房间面积等其他数值信息)。

>>> a = np.arange(24).reshape(2,3,4)    # 2层3行4列
>>> a
array([[[ 0,  1,  2,  3],[ 4,  5,  6,  7],[ 8,  9, 10, 11]],[[12, 13, 14, 15],[16, 17, 18, 19],[20, 21, 22, 23]]])
>>> a[1][2][3]                          # 虽然可以这样
23
>>> a[1,2,3]                            # 但这才是规范的用法
23
>>> a[:,0,0]                            # 所有楼层的第1排第1列
array([ 0, 12])
>>> a[0,:,:]                            # 1楼的所有房间,等价与a[0]或a[0,...]
array([[ 0,  1,  2,  3],[ 4,  5,  6,  7],[ 8,  9, 10, 11]])
>>> a[:,:,1:3]                          # 所有楼层所有排的第2到4列
array([[[ 1,  2],[ 5,  6],[ 9, 10]],[[13, 14],[17, 18],[21, 22]]])
>>> a[1,:,-1]                           # 2层每一排的最后一个房间
array([15, 19, 23])

提示:

  1. 对多维数组切片或索引得到的结果,维度不是确定的;
  2. 切片返回的数组不是原始数据的副本,而是指向与原始数组相同的内存区域。数组切片不会复制内部数组数据,只是产生了原始数据的一个新视图。
>>> a = np.arange(12).reshape(3,4)
>>> a
array([[ 0,  1,  2,  3],[ 4,  5,  6,  7],[ 8,  9, 10, 11]])
>>> b = a[1:,2:] # 数组b是数组a的切片
>>> b
array([[ 6,  7],[10, 11]])
>>> b[:,:] = 99 # 改变数组b的值,也会同时影响数组a
>>> b
array([[99, 99],[99, 99]])
>>> a
array([[ 0,  1,  2,  3],[ 4,  5, 99, 99],[ 8,  9, 99, 99]])

2. 改变结构

NumPy数组的存储顺序和数组的视图是相互独立的,因此改变数组的维度是非常便捷的操作,这一类操作不会改变所操作的数组本身的存储顺序, resize() 除外。

  • reshape() - 按照指定的结构(形状)返回数组的新视图,但不会改变数组
  • resize() - 按照指定的结构(形状)改变数组,无返回值
  • ravel() - 返回多维数组一维化的视图,但不会改变原数组
  • transpose() - 返回行变列的视图,但不会改变原数组
  • rollaxis() - 翻滚轴,返回新的视图
>>> a = np.arange(12)
>>> b = a.reshape((3,4)) # reshape()返回数组a的一个新视图,但不会改变数组a
>>>> a.shape
(12,)
>>> b.shape
(3, 4)
>>> b is a
False
>>> b.base is a
True
a.resize([4,3]) # resize()则真正改变了数组a的结构
>>> a.shape
(4, 3)
>>> a.ravel() # 返回多维数组一维化的视图,但不会改变原数组
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
>>> a.transpose() # 返回行变列的视图,但不会改变原数组
array([[ 0,  3,  6,  9],[ 1,  4,  7, 10],[ 2,  5,  8, 11]])
>>> a.T  # 返回行变列的视图,等价于transpose()
array([[ 0,  3,  6,  9],[ 1,  4,  7, 10],[ 2,  5,  8, 11]])
>>> np.rollaxis(a, 1, 0) # 翻滚轴,1轴变0轴
array([[ 0,  3,  6,  9],[ 1,  4,  7, 10],[ 2,  5,  8, 11]])

3. 合并与拆分

NumPy数组一旦创建就不能再改变其元素数量了。如果要动态改变数组元素数量,只能通过合并或者拆分的方法,生成新的数组。对于刚刚上手NumPy的程序员来说,最大的困惑就是不能使用append() 方法向数组内添加元素,甚至连 append() 方法都找不到了。其实,NumPy仍然保留了append() 方法,只不过这个方法不再是NumPy数组的方法,而是是升级到最外层的NumPy命名空间,并且该方法的功能不再是追加元素,而是合并数组。

>>> np.append([[1, 2, 3]], [[4, 5, 6]])
array([1, 2, 3, 4, 5, 6])
>>> np.append([[1, 2, 3]], [[4, 5, 6]], axis=0) array([[1, 2, 3],[4, 5, 6]])
>>> np.append([[1, 2, 3]], [[4, 5, 6]], axis=1)array([[1, 2, 3, 4, 5, 6]])

不过,这个append()委实不够好用,我给大家推荐的是stack()方法。

>>> a = np.arange(4).reshape(2,2)
>>> b = np.arange(4,8).reshape(2,2)
>>> np.hstack((a,b)) # 水平合并
array([[0, 1, 4, 5],[2, 3, 6, 7]])
>>> np.vstack((a,b)) # 垂直合并
array([[0, 1],[2, 3],[4, 5],[6, 7]])
>>> np.dstack((a,b)) # 深度合并
array([[[0, 4],[1, 5]],[[2, 6],[3, 7]]])

stack 函数原型为 stack(arrays, axis=0),请注意体会下面例子中的 axis 的用法。

>>> a = np.arange(60).reshape(3,4,5)
>>> b = np.arange(60).reshape(3,4,5)
>>> a.shape, b.shape
>>> np.stack((a,b), axis=0).shape
(2, 3, 4, 5)
>>> np.stack((a,b), axis=1).shape
(3, 2, 4, 5)
>>> np.stack((a,b), axis=2).shape
(3, 4, 2, 5)
>>> np.stack((a,b), axis=3).shape
(3, 4, 5, 2)

因为数组切片非常简单,所以数组拆分应用较少。拆分是合并的逆过程,最常用的方法是split()。

>>> a = np.arange(8).reshape(2,4)
>>> np.vsplit(a, 2) # 垂直方向拆分成2部分
[array([[0, 1, 2, 3]]), array([[4, 5, 6, 7]])]
>>> np.hsplit(a, 2) # 水平方向拆分成2部分
[array([[0, 1],[4, 5]]), array([[2, 3],[6, 7]])]

4. 复制

改变数组结构返回的是原元数据的一个新视图,而不是原元数据的副本。浅复制(view)和深复制(copy)则是创建原数据的副本,但二者之间也有细微差别:浅复制(view)是共享内存,深复制(copy)则是独享。

>>> a = np.arange(6).reshape((2,3))
>>> b = a.view()
>>> b is a
False
>>> b.base is a
False
>>> b.flags.owndata
False
>>> c = a.copy()
>>> c is a
False
>>> c.base is a
False
>>> c.flags.owndata
True

5. 排序

NumPy 数组排序函数有两个,一个是sort(),一个是argsort()。sort()返回输入数组的排序副本,argsort()返回的是数组值从小到大的索引号。从函数原型看,这两个函数的参数是完全一样的。

numpy.sort(a, axis=-1, kind=‘quicksort’, order=None)
numpy.argsort(a, axis=-1, kind=‘quicksort’, order=None)

  • a - 要排序的数组
  • axis - 沿着它排序数组的轴,如果没有,则沿着最后的轴排序
  • kind - 排序方法,默认为’quicksort’(快速排序),其他选项还有 ‘mergesort’(归并排序)和 ‘heapsort’(堆排序)
  • order - 如果数组包含字段,则是要排序的字段
>>> a = np.random.random((2,3))
>>> a
array([[0.79658569, 0.14507096, 0.63016223],[0.24983103, 0.98368325, 0.71092079]])
>>> np.argsort(a) # 返回行内从小到大排序的索引序号(列排序),相当于axis=1(最后的轴)
array([[1, 2, 0],[0, 2, 1]], dtype=int64)
>>> np.sort(a) # 返回行内从小到大排序的一个新数组(列排序)
array([[0.14507096, 0.63016223, 0.79658569],[0.24983103, 0.71092079, 0.98368325]])
>>> np.sort(a,axis=0) # 返回列内每一行都是从小到大排序(行排序)
array([[0.24983103, 0.14507096, 0.63016223],[0.79658569, 0.98368325, 0.71092079]])

我们再看看排序字段的使用。先定义一个新的数据类型dt:dt类似于一个字典,有两个键值对,一个是姓名name,一个是年龄age,姓名长度10个字符,年龄是整型。

>>> dt = np.dtype([('name',  'S10'),('age',  int)])
>>> a = np.array([("zhang",21),("wang",25),("li",  17),  ("zhao",27)], dtype = dt)
>>> np.sort(a, order='name') # 如果指定姓名排序,结果是李王张赵
array([(b'li', 17), (b'wang', 25), (b'zhang', 21), (b'zhao', 27)],dtype=[('name', 'S10'), ('age', '<i4')])
>>> np.sort(a, order='age') # 如果指定年龄排序,结果则是李张王赵
array([(b'li', 17), (b'zhang', 21), (b'wang', 25), (b'zhao', 27)],dtype=[('name', 'S10'), ('age', '<i4')])

6. 查找和筛选

这里,我们约定查找是返回符合条件的元素的索引号,筛选是返回符合条件的元素。查找和筛选,是 NumPy 数组最令人心动的功能,也是相对比较烧脑的操作。

6.1 查找

下面的代码演示了返回数组中最大值和最小值的索引(对于多维数组,这个索引是数组转成一维之后的索引):

>>> a = np.random.random((2,3))
>>> a
array([[0.47881615, 0.55682904, 0.29173085],[0.41107703, 0.91467593, 0.88852535]])
>>> np.argmax(a)
4
>>> np.argmin(a)
2

下面的代码演示了返回数组中非零元素的索引:

>>> a = np.random.randint(0, 2, (2,3))
>>> a
array([[0, 0, 0],[0, 1, 1]])
>>> np.nonzero(a)
(array([1, 1], dtype=int64), array([1, 2], dtype=int64))

numpy.where() 用于返回数组中满足给定条件的元素的索引,还可以用于替换符合条件的元素:

numpy.where(condition[, x, y])

>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> np.where(a < 5)
(array([0, 1, 2, 3, 4], dtype=int64),)
>>> a = a.reshape((2, -1))
>>> a
array([[0, 1, 2, 3, 4],[5, 6, 7, 8, 9]])
>>> np.where(a < 5)
(array([0, 0, 0, 0, 0], dtype=int64), array([0, 1, 2, 3, 4], dtype=int64))
>>> np.where(a < 5, a, 10*a) # 满足条件的元素不变,其他元素乘以10
array([[ 0,  1,  2,  3,  4],[50, 60, 70, 80, 90]])

6.2 筛选

筛选有3种方式,一是使用np.where()返回的python元组,二是使用逻辑表达式返回的布尔型数组,三是使用整型数组。

>>> a = np.random.random((3,4))
>>> a
array([[0.41551063, 0.38984904, 0.01204226, 0.72323978],[0.82425869, 0.64216573, 0.41475495, 0.21351508],[0.30104819, 0.52046164, 0.58286043, 0.66749564]])
>>> a[np.where(a>0.5)] # 返回大于0.5的元素(使用np.where()返回的python元组)
array([0.72323978, 0.82425869, 0.64216573, 0.52046164, 0.58286043,0.66749564])
>>> a[(a>0.3)&(a<0.7)] # 返回大于0.3且小于0.7的元素(使用逻辑表达式返回的布尔型数组)
array([0.41551063, 0.38984904, 0.64216573, 0.41475495, 0.30104819,0.52046164, 0.58286043, 0.66749564])
>>> a[np.array([2,1])] # 返回整形数组指定的项(使用整型数组)
array([[0.30104819, 0.52046164, 0.58286043, 0.66749564],[0.82425869, 0.64216573, 0.41475495, 0.21351508]])
>>> a = a.ravel()
>>> a[np.array([3,5,7,11])] # 返回整形数组指定的项(使用整型数组)
array([0.72323978, 0.64216573, 0.21351508, 0.66749564])
>>> a[np.array([[3,5],[7,11]])] # 返回整形数组指定的项(使用整型数组)
array([[0.72323978, 0.64216573],[0.21351508, 0.66749564]])

使用np.where()或者直接使用逻辑表达式来筛选数组元素,很容易想象到这样的做的目的,使用整形数组来筛选数组元素的用途是什么呢?看似不起眼的一个功能,却蕴含着无穷的想象空间。下面用一个例子来演示通过整型数组筛选数组元素的神奇魔法。

上图是用字符表现像素灰度的效果图。一般而言,灰度图像每个像素的值域范围是 [0, 255]。假如用于表现不同灰度的字符集是[’ ‘, ‘.’, ‘-’, ‘+’, ‘=’, ‘*’, ‘#’, ‘@’],从 ’ ’ 到 ‘@’ 表示从白到黑的 8 个灰度等级。我们需要将每个像素的灰度值分段转换成相应的字符。例如,灰度值小于32的像素用 ‘@’ 表示,大于或等于32且小于64的像素用 ‘#’ 表示,依次类推直至大于或等于224的像素用’ '表示。

如何实现图像数组从灰度值到对应字符的转换呢?乍一看,好像只有用循环的方式遍历所有像素才能实现。但是,下面的代码却用“整型数组筛选数组元素”的方法完成了这个转换,不但代码简洁,而且代码的执行速度也非常快。

>>> img = np.random.randint(0, 256, (5, 10), dtype=np.uint8) # 生成10x5的灰度图
>>> img
array([[145, 95, 60, 14, 66, 150, 221, 43, 184, 66],[229, 138, 76, 90, 179, 217, 2, 20, 154, 191],[165, 120, 77, 117, 42, 108, 156, 5, 208, 50],[164, 196, 227, 111, 82, 84, 19, 208, 124, 16],[146, 50, 107, 26, 34, 229, 137, 104, 93, 223]], dtype=uint8)
>>> img = (img/32).astype(np.uint8) # 将256级灰度值转为8级灰度值
>>> img
array([[0, 3, 3, 3, 1, 7, 7, 4, 2, 7],[6, 3, 4, 5, 4, 5, 4, 7, 3, 4],[6, 7, 1, 2, 2, 2, 2, 4, 7, 7],[5, 7, 1, 2, 0, 2, 7, 0, 7, 5],[3, 5, 0, 7, 0, 4, 6, 2, 5, 0]], dtype=uint8)
>>> chs = np.array([' ', '.', '-', '+', '=', '*', '#', '@']) # 灰度字符集
>>> chs[img] # 用整型数组筛选数组元素(我认为这是NumPy最精彩之处!)
array([[' ', '+', '+', '+', '.', '@', '@', '=', '-', '@'],['#', '+', '=', '*', '=', '*', '=', '@', '+', '='],['#', '@', '.', '-', '-', '-', '-', '=', '@', '@'],['*', '@', '.', '-', ' ', '-', '@', ' ', '@', '*'],['+', '*', ' ', '@', ' ', '=', '#', '-', '*', ' ']], dtype='<U1')

7. 数组I/O

所谓数组I/O,就是讨论如何分发、交换数据。在机器学习算法模型的例子中,海量的训练数据通常都是从数据文件中读出来的,而数据文件一般是csv格式,NumPy 自带的csv文件读写函数,可以很方便的读写csv格式的数据文件。除了支持通用的csv格式的数据文件, NumPy 为数组对象引入了新的二进制文件格式,用于数据交换。后缀名为.npy 文件用于存储单个数组,后缀名为.npz 文件用于存取多个数组。

下面的代码演示了NumPy读写CSV格式的数据文件的方法。实际操作下面的代码时,请注意结合实际情况替换对应的文件路径和文件名。

>>> a = np.random.random((15,5))
>>> np.savetxt('demo.csv', a, delimiter=',') # 将数组a保存成CSV格式的数据文件
>>> data = np.loadtxt('demo.csv', delimiter=',') # 打开CSV格式的数据文件
>>> data.shape, data.dtype
((15, 5), dtype('float64'))

NumPy 自定义的数据交换格式也是一个非常好用的数据交换方式,使用它保存 NumPy 数组时不会丢失任何信息,特别是数据类型的信息。实际操作下面的代码时,请注意结合实际情况替换对应的文件路径和文件名。

>>> single_arr_fn = 'single_arr.npy' # 存储单个数组文件名
>>> multi_arr_fn = 'multi_arr.npz' # 存储多个数组文件名
>>> lon = np.linspace(10,90,9)
>>> lat = np.linspace(20,60,5)
>>> np.save(single_arr_fn, lon) # 用save()函数把经度数组保存成.npy文件
>>> lon = np.load(single_arr_fn) # 接着用load()函数读出来
>>> np.savez(multi_arr_fn, longitude=lon, latitude=lat) #保存两个数组到一个文件
>>> data = np.load(multi_arr_fn) # 用load()函数把这个.npz文件读成一个结构data
>>> data.files # 查看所有的数组名
>>> data['longitude'] # 使用data[数组名],就可以取得想要的数据
>>> data['latitude'] # 使用data[数组名],就可以取得想要的数据

科学计算基础软件包NumPy入门讲座(4):操作数组相关推荐

  1. 科学计算基础软件包NumPy入门讲座(5):常用函数

    文章目录 1. 特殊值 2. 函数命名空间 3. 数学函数 4. 统计函数 5. 插值函数 6. 多项式拟合函数 7. 自定义广播函数 7.1.使用np.frompyfunc定义广播函数 7.2 使用 ...

  2. 科学计算基础软件包NumPy入门讲座(7):矩阵

    文章目录 1. 矩阵对象 2. 创建矩阵 3. 矩阵属性 4. 矩阵乘法 1. 矩阵对象 在数学上,矩阵(Matrix)是一个按照矩形阵列排列的复数或实数集合,但在NumPy中,矩阵np.matrix ...

  3. 科学计算基础软件包Numpy学习 02

    创建数组 以下介绍Numpy创建数组的一些常用方法,主要有:蛮力构造法,特殊数值法,随机数值法,定长分割法,重复构造法,网络构造法,自定义数据类型 蛮力构造法 蛮力构造法使用np.array()函数来 ...

  4. 初识 Python 科学计算库之 NumPy(创建多维数组对象)

    文章目录 参考 描述 NumPy 特点 获取 导入 多维数组对象 np.array() np.asarray() 范围 随机 概览 np.random.randn() np.random.normal ...

  5. python 科学计算基础教程电子版-自学Python 编程基础、科学计算及数据分析

    自学Python 编程基础.科学计算及数据分析 epub pdf mobi txt 下载 自学Python 编程基础.科学计算及数据分析 epub pdf mobi txt 下载 ☆☆☆☆☆ 李金 著 ...

  6. 【Python基础】科学计算库Scipy简易入门

    0.导语 Scipy是一个用于数学.科学.工程领域的常用软件包,可以处理插值.积分.优化.图像处理.常微分方程数值解的求解.信号处理等问题.它用于有效计算Numpy矩阵,使Numpy和Scipy协同工 ...

  7. 初识人工智能(一):数据分析(二):numpy科学计算基础库(一)

    1. numpy科学计算基础库 1.1 什么是numpy NumPy(Numerical Python)是Python语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数 ...

  8. python科学计算基础教程pdf下载-Python科学计算基础教程_PDF电子书

    因资源下载地址容易失效,请加微信号359049049直接领取,直接发最新下载地址. 前言 ======================================================= ...

  9. Python科学计算基础篇

    关于Numpy Numpy是Python的一个矩阵类型,提供大量矩阵处理函数,内部通过C实现. 包含两种数据结构,数组array和矩阵matrix,其实就是array而已 构建数组array 通过tu ...

最新文章

  1. 【机器视觉】 measure_projection算子
  2. Symbian^3对标准C++的支持
  3. Mac 10.12启动QXDM crash解决
  4. 生如夏花之绚烂,Lisp风格的Lialang诞生了!
  5. 一元二次方程解法的实现(Python)
  6. Nonebot QQ机器人插件八:点歌(网易云音乐)
  7. PhpSpreadsheet VS Box\Spout读取excel性能对比
  8. 万能查看电脑连接过的WiFi密码
  9. 智行订票系统需求分析报告
  10. 服务器处理蜘蛛抓取网页的过程,搜索引擎蜘蛛抓取页面过程图解
  11. Ubuntu 18.04安装openJDK7编译安卓6.0.0_r1
  12. 学计算机会设置路由器,Win7电脑怎么设置无线路由器上网
  13. redis设置过期时间与直接detele key有什么区别
  14. PostgreSQL的查询技巧: 零除, GENERATED STORED, COUNT DISTINCT, JOIN和数组LIKE
  15. 【Java】房屋管理系统
  16. 高性能Linux架构实战 [高俊峰] 笔记摘要
  17. 各个浏览器a标签href下载文件链接长度过长,导致下载失败解决方案
  18. “极致成本向左,本质安全向右”-谈谈锂电池储能系统的发展趋势
  19. 薅羊毛脚本更新 青龙面板 22/11/2
  20. pycharm专业版配置ssh连接服务器

热门文章

  1. python做学生管理系统数据库模型_数据库建模:学生信息系统搭建实验
  2. ad服务器做虚拟化,为虚拟桌面准备AD服务器
  3. idea全局搜索问题
  4. 云宏大讲坛 | Ceph分布式存储高性能设计
  5. [JM] 如何结合标准看JM代码(JM86)
  6. VBS脚本实现宽带上网加网页认证上网双验证
  7. 现代计算机系统必须配置的核心,第一章 计算机系统概述
  8. 跳转指令JMP(04)和跳转结束指令JME(05)
  9. SUSCTF Ez_Pager_Tiper
  10. 科软-信息安全实验2-netfilter实验