Numpy常用操作

numpy简介

Python中用列表(list)可以用来当作数组使用,不过由于列表的元素可以是任何对象,因此列表中所保存的是对象的指针。这样为了保存一个简单的[1,2,3],需要有3个指针和三个整数对象。对于数值运算来说这种结构显然比较浪费内存和CPU计算时间。
此外python还提供了一个array模块,array对象和列表不同,它直接保存数值,和C语言的一维数组比较类似。但是由于它不支持多维,也没有各种运算函数,因此也不适合做数值运算。

NumPy的诞生弥补了这些不足,NumPy提供了两种基本的对象:ndarray(N-dimensional array object)和 ufunc(universal function object)。ndarray是存储单一数据类型的多维数组,而ufunc则是能够对数组进行处理的函数。Numpy内部运算是通过C语言实现的,所以性能方面也很不错。

1、生成numpy的ndarray的几种方式

numpy提供了ndarray和matrix两种类型的数据,numpy的二维数组能够很好地实现矩阵的各种功能,而且比matrix要灵活,速度也更快。
numpy有ndarray和matix,性能方面ndarray优于matix,所以一般使用ndarray。
我们可以通过给array函数传递Python的序列对象创建数组,如果传递的是多层嵌套的序列,将创建多维数组。
(1)创建numpy的array几种方法

import numpy as np
a = np.array([1, 2, 3, 4])
b = np.array((5, 6, 7, 8))
##b的结果如下
array([5, 6, 7, 8])
c = np.array([[1, 2, 3, 4],[4, 5, 6, 7], [7, 8, 9, 10]])
##c的结果如下
array([[ 1, 2, 3, 4],
[ 4, 5, 6, 7],
[ 7, 8, 9, 10]])

(2)利用numpy内置函数创建

zeros = np.zeros((2,2)) ###生成一个全为0的数组或矩阵
结果为:
array([[ 0., 0.],
[ 0., 0.]])

e = np.eye(2) ###生成一个单位矩阵
##结果如下:
array([[ 1., 0.],
[ 0., 1.]])

(3) 数组的大小可以通过其shape属性获得

c.ndim ##获取数组或矩阵维数
c.shape ##获取矩阵各维长度
c.shape[0] ##获取矩阵行数,shape[1]获取矩阵的列数
c.size ##获取矩阵的元素个数
c.dtype ##查看数组数据类型

(4)修改其形状
数组c的shape有两个元素,因此它是二维数组,其中第0轴的长度为3,第1轴的长度为4。还可以通过修改数组的shape属性,在保持数组元素个数不变的情况下,改变数组每个轴的长度。

c.reshape(4,3) ##把原来3x4矩阵,转换为4x3矩阵
##结果为:array([[ 1, 2, 3],
[ 4, 4, 5],
[ 6, 7, 7],
[ 8, 9, 10]])
c.reshape(2,-1) ###当某个轴的元素为-1时,将根据数组元素的个数自动计算 ###此轴的长度

(5)arange函数类似于python的range函数,通过指定开始值、终值和步长来创建一维数组,注意数组不包括终值:
np.arange(0,1,0.1)
##结果为:array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])

2、存取元素

(1)数组元素的存取方法和Python的标准方法相同

a = np.arange(10)
a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
a[5] # 用整数作为下标可以获取数组中的某个元素
5
a[3:5] # 用范围作为下标获取数组的一个切片,包括a[3]不包括a[5]
##结果为:array([3, 4])
a[:-1] # 下标可以使用负数,表示从数组后往前数
结果为:array([0, 1, 2, 3, 4, 5, 6, 7, 8])
a[2:4] = 100,101 # 下标还可以用来修改元素的值
a
#结果为:array([ 0, 1, 40, 41, 4, 5, 6, 7, 8, 9])
a[1:-1:2] # 范围中的第三个参数表示步长,2表示隔一个元素取一个元素
#结果为:array([ 1, 41, 5, 7])

(2) 和Python的列表序列不同,通过下标范围获取的新的数组是原始数组的一个视图。它与原始数组共享同一块数据空间。

b = a[3:7] # 通过下标范围产生一个新的数组b,b和a共享同一块数据空间
b[2] = -10 # 将b的第2个元素修改为-10
#a结果如下
array([ 0, 1, 40, 41, 4, -10, 6, 7, 8, 9])
#b的结果如下
array([ 41, 4, -10, 6])

3、多维数组

创建一个6x6的多维数组或矩阵

a = np.arange(0, 60, 10).reshape(-1, 1) + np.arange(0, 6)
#运行结果如下:
array([[ 0, 1, 2, 3, 4, 5],
[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25],
[30, 31, 32, 33, 34, 35],
[40, 41, 42, 43, 44, 45],
[50, 51, 52, 53, 54, 55]])

a[3:, [0, 2, 5]]
##下标中的第0轴是一个范围,它选取第3行之后的所有行; ##第1轴是整数序列,它选取第0, 2, 5三列
#运行结果为:
array([[30, 32, 35],
[40, 42, 45],
[50, 52, 55]])

a[2::2,::2]
##第0轴,从第2行开始,步长为2;第1轴,从第0行开始,步长为2
##运行结果为:
array([[20, 22, 24],
[40, 42, 44]])

4、矩阵操作

(1)以下介绍矩阵操作,包括两个矩阵间操作如矩阵乘法等。

A = np.array([[1, 2], [-1, 4]])
B = np.array([[2, 0], [3, 4]])
###对应元素相乘
A*B
##结果如下:
array([[ 2, 0],
[-3, 16]])

####矩阵乘法
np.dot(A, B) # 或者 A.dot(B)
##运行结果如下
array([[ 8, 8],
[10, 16]])

(2)线性代数运算
对矩阵进行线性代数运行,如求转置、特征向量等。求A的转置

##求A的转置
A.transpose() ##或A.T
##运行结果
array([[ 1, -1],
[ 2, 4]])

## 求A的逆矩阵
linalg.inv(A)
##运行结果
array([[ 0.66666667, -0.33333333],
[ 0.16666667, 0.16666667]])

# 求A的特征值和特征向量
eigenvalues, eigenvectors = linalg.eig(A)
##其中eigenvalues为 特征值,eigenvectors为特征向量

(3)调整坐标顺序
transpose的参数为坐标,正常顺序为(0, 1, 2, ... , n - 1),
现在传入的为(1, 0)代表C[x][y]转换为C[y][x],第0个和第1个坐标互换。

C.transpose((1,0)) ###第0个和第1个坐标互换
##结果如下:
array([[ 0.68752896, -0.11705268, 0.49078462, -0.48826679, -1.26943352,
-0.97029925],
[ 1.01686837, -1.55073073, -1.40240593, -0.98632156, 0.80378005,
0.33703986],
[ 0.95644284, -0.19360605, 1.82482162, -0.45383782, 0.26197213,
0.9131711 ]])

(4)在矩阵或数组上运用数学和统计方法

import numpy as np
import numpy.random as np_random

print('求和,求平均')
arr = np.random.randn(5, 4)
print(arr)
print(arr.mean())
print(arr.sum())
print(arr.mean(axis = 1)) # 对每一行的元素求平均
print(arr.sum(0)) # 对每一列元素求和,axis可以省略。

(5)向量或矩阵运算与循环运算性能比较

import time as tm  
import numpy as np
 
dim = 100000#数据长度(包含的元素个数)  
x1 = np.ones(dim)  
x2 = np.ones(dim)  
yFor = np.ones(dim)  

tStart = tm.clock()#开始计时  
#for循环解算x1*x2(对应元素相乘)  
for i in range(dim):  
    yFor[i] = x1[i]*x2[i]  
tEnd=tm.clock()#停止计时  
tFor = tEnd-tStart#计算用时  

tStart = tm.clock()#开始计时  
#向量计算x1*x2(对应元素相乘)  
yVector = x1*x2  
tEnd = tm.clock()#停止计时  
tVector = tEnd-tStart#计算用时  

print ('for循环用时tFor=',tFor)  
print ('向量运算用时tVector=',tVector)

5、 数据合拼与拆分

import numpy as np
import numpy.random as np_random

print('连接两个二维数组')
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([[7, 8, 9], [10, 11, 12]])
print(np.concatenate([arr1, arr2], axis = 0)) # 按行连接
print(np.concatenate([arr1, arr2], axis = 1)) # 按列连接

##或通过以下命令进行连接,效果一样
print('垂直stack与水平stack')
print(np.vstack((arr1, arr2))) # 垂直堆叠
print(np.hstack((arr1, arr2))) # 水平堆叠

6、numpy上的通用函数(ufunc)

ufunc是universal function的缩写,它是一种能对数组的每个元素进行操作的函数。NumPy内置的许多ufunc函数都是在c语言级别实现的,因此它们的计算速度非常快。让我们来看一个例子:

import time
import math
import numpy as np

x = [i * 0.001 for i in np.arange(1000000)]
start = time.clock()
for i, t in enumerate(x):
x[i] = math.sin(t)
print ("math.sin:", time.clock() - start )

x = [i * 0.001 for i in np.arange(1000000)]
x = np.array(x)
start = time.clock()
np.sin(x)
print ("numpy.sin:", time.clock() - start )

运行结果如下:
math.sin: 0.5793389999999974
numpy.sin: 0.06916299999999964
说明,numpy.sin比math.sin快10倍多。这得利于numpy.sin在C语言级别的循环计算。

发表评论