NumPy-快速处理数据

NumPy-快速处理数据

  标准安装的Python中用列表(list)保存一组值,可以用来当作数组使用,不过由于列表的元素可以是任何对象,因此列表中所保存的是对象的指针。这样为了保存一个简单的[1,2,3],需要有3个指针和三个整数对象。对于数值运算来说这种结构显然比较浪费内存和CPU计算时间。
  此外Python还提供了一个array模块,array对象和列表不同,它直接保存数值,和C语言的一维数组比较类似。但是由于它不支持多维,也没有各种运算函数,因此也不适合做数值运算。
  NumPy的诞生弥补了这些不足,NumPy提供了两种基本的对象:ndarray和ufunc。ndarray是存储单一数据类型的多维数组,而ufunc则是能够对数组进行处理的函数。

一、ndarray对象

函数库的导入

import numpy as np
1、创建

首先需要创建数组才能对其进行其它操作。
我们可以通过给array函数传递Python的序列对象创建数组,如果传递的是多层嵌套的序列,将创建多维数组(下例中的变量c):
这里写图片描述

数组的大小可以通过其shape属性获得:
这里写图片描述
数组a的shape只有一个元素,因此它是一维数组。而数组c的shape有两个元素,因此它是二维数组,其中第0轴的长度为3,第1轴的长度为4。还可以通过修改数组的shape属性,在保持数组元素个数不变的情况下,改变数组每个轴的长度。下面的例子将数组c的shape改为(4,3),注意从(3,4)改为(4,3)并不是对数组进行转置,而只是改变每个轴的大小,数组元素在内存中的位置并没有改变:
这里写图片描述
当某个轴的元素为-1时,将根据数组元素的个数自动计算此轴的长度,因此下面的程序将数组c的shape改为了(2,6):
这里写图片描述
使用数组的reshape方法,可以创建一个改变了尺寸的新数组,原数组的shape保持不变:
这里写图片描述
数组a和d其实共享数据存储内存区域,因此修改其中任意一个数组的元素都会同时修改另外一个数组的内容:
这里写图片描述
数组的元素类型可以通过dtype属性获得
这里写图片描述
arange函数类似于python的range函数,通过指定开始值、终值和步长来创建一维数组,注意数组不包括终值:
这里写图片描述
linspace函数通过指定开始值、终值和元素个数来创建一维数组,可以通过endpoint关键字指定是否包括终值,缺省设置是包括终值:
这里写图片描述
logspace函数和linspace类似,不过它创建等比数列,下面的例子产生1(10^0)到100(10^2)、有20个元素的等比数列:
这里写图片描述

2、存取元素

数组元素的存取方法和Python的标准方法相同:
这里写图片描述
和Python的列表序列不同,通过下标范围获取的新的数组是原始数组的一个视图。它与原始数组共享同一块数据空间:
这里写图片描述
除了使用下标范围存取元素之外,NumPy还提供了整数序列和布尔数组两种存取元素的高级方法。
使用整数序列
当使用整数序列对数组元素进行存取时,将使用整数序列中的每个元素作为下标,整数序列可以是列
表或者数组。使用整数序列作为下标获得的数组不和原始数组共享数据空间。
这里写图片描述
使用布尔数组
当使用布尔数组b作为下标存取数组x中的元素时,将收集数组x中所有在数组b中对应下标为True的元素。使用布尔数组作为下标获得的数组不和原始数组共享数据空间,注意这种方式只对应于布尔数组,不能使用布尔列表。
这里写图片描述

3、多维数组

创建一个多维数组
这里写图片描述

4、结构数组

假设我们需要定义一个结构数组,它的每个元素都有name, age和weight字段,在NumPy中可以如下定义:
这里写图片描述
我们先创建一个dtype对象persontype,通过其字典参数描述结构类型的各个字段。字典有两个关
键字:names,formats。每个关键字对应的值都是一个列表。names定义结构中的每个字段名,而
formats则定义每个字段的类型。

5、内存结构

ndarray数组对象在内存中的储存方式
这里写图片描述
上图中显示的是如下数组的内存结构:

a = np.array([[0,1,2],[3,4,5],[6,7,8]], dtype=np.float32)

二、ufunc运算

ufunc是一种能对数组的每个元素进行操作的函数,umPy内置的许多ufunc函数都是在C语言级别实现的,因此它们的计算速度非常快。
这里写图片描述
先用linspace产生一个从0到2*PI的等距离的10个数,然后将其传递给sin函数,由于np.sin是一个ufunc函数,因此它对x中的每个元素求正弦值,然后将结果返回,并且赋值给y。计算之后x中的值并没有改变,而是新创建了一个数组保存结果。
如果我们希望将sin函数所计算的结果直接覆盖到数组x上去的话,可以将要被覆盖的数组作为第二个参数传递给ufunc函数,两个变量的id是相同的(变量t和变量x指向同一块内存区域)。
这里写图片描述
numpy.sin比math.sin快10倍多,不过对单个数的计算math.sin则比numpy.sin快得多了。
NumPy中有众多的ufunc函数为我们提供各式各样的计算。除了sin这种单输入函数之外,还有许多多个输入的函数,add函数就是一个最常用的例子。
这里写图片描述
add函数返回一个新的数组,此数组的每个元素都为两个参数数组的对应元素之和。它接受第3个参数
指定计算结果所要写入的数组,如果指定的话,add函数就不再产生新的数组。

下面是数组的运算符和其对应的ufunc函数的一个列表,注意除号”/”的意义根据是否激活future.division有所不同。

运算符 ufunc函数
y = x1 + x2 add(x1, x2 [, y])
y = x1 - x2 subtract(x1, x2 [, y])
y = x1 * x2 multiply (x1, x2 [, y])
y = x1 / x2 divide (x1, x2 [, y]), 如果两个数组的元素为整数,那么用整数除法
y = x1 / x2 true divide (x1, x2 [, y]), 总是返回精确的商
y = x1 // x2 floor divide (x1, x2 [, y]), 总是对返回值取整
y = -x negative(x [,y])
y = x1**x2 power(x1, x2 [, y])
y = x1 % x2 remainder(x1, x2 [, y]), mod(x1, x2, [, y])

假设a b c三个数组采用算式x=a*b+c计算,那么它相当于:

t = a * b
x = t + c
del t
1、广播

如果两个数组的shape不同的话,会进行如下的广播(broadcasting)处理,它有4条规则:

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

reduce 方法和Python的reduce函数类似,它沿着axis轴对array进行操作,相当于将运算符插入到沿axis轴的所有子数组或者元素当中。
accumulate 方法和reduce方法类似,只是它返回的数组和输入的数组的shape相同,保存所有的中间计算结果。
reduceat 方法计算多组reduce的结果,通过indices参数指定一系列reduce的起始和终了位置。

3、矩阵运算

dot : 对于两个一维的数组,计算的是这两个数组对应下标元素的乘积和(数学上称之为内积);对于二维数组,计算的是两个数组的矩阵乘积;对于多维数组,它的通用计算公式如下,即结果数组中的每个元素都是:数组a的最后一维上的所有元素与数组b的倒数第二位上的所有元素的乘积和。

dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])

inner : 和dot乘积一样,对于两个一维数组,计算的是这两个数组对应下标元素的乘积和;对于
多维数组,它计算的结果数组中的每个元素都是:数组a和b的最后一维的内积,因此数组a和b
的最后一维的长度必须相同。

inner(a, b)[i,j,k,m] = sum(a[i,j,:]*b[k,m,:])

outer : 只按照一维数组进行计算,如果传入参数是多维数组,则先将此数组展平为一维数组之
后再进行运算。outer乘积计算的列向量和行向量的矩阵乘积。

猜你喜欢

转载自blog.csdn.net/y_bing/article/details/81293494