NumPy系统是Python的一种开源的数值计算扩展。这种工具可用来存储和处理大型矩阵,比Python自身的嵌套列表(nested list structure)结构要高效的多。
ndarray中的所有元素的类型都是相同的,而Python列表中的元素类型是任意的,所以ndarray在存储元素时内存可以连续,而python原生list就只能通过寻址方式找到下一个元素,这虽然也导致了在通用性能方面Numpy的ndarray不及Python原生list,但在科学计算中,Numpy的ndarray就可以省掉很多循环语句,代码使用方面比Python原生list简单的多。numpy内置了并行运算功能,当系统有多个核心时,做某种计算时,numpy会自动做并行计算。Numpy底层使用C语言编写,数组中直接存储对象,而不是存储对象指针,所以其运算效率远高于纯Python代码。
一.基本操作
使用前一定要先导入 Numpy 包 import numpy as np
1.生成数组
- arange()函数
arange类似于Python中的 range
函数,只不过返回的不是列表,而是数组,arange(start, stop=None, step=1, dtype=None)产生一个在区间 [start, stop)
之间,以 step
为间隔的数组,如果只输入一个参数,则默认从 0
开始,并以这个值为结束.
与 range
不同, arange
允许非整数值输入,产生一个非整型的数组
np.arange(4) #array([0, 1, 2, 3])
- linspace()函数
linspace(start, stop, N),产生 N
个等距分布在 [start, stop]
间的元素组成的数组,包括 start, stop
- logspace()函数
logspace(start, stop, N),产生 N 个对数等距分布的数组,默认以10为底
- meshgrid()函数
有时候需要在二维平面中生成一个网格,这时候可以使用 meshgrid
来完成
ogrid
相当于 meshgrid(indexing='ij', sparse=True)
mgrid
相当于 meshgrid(indexing='ij', sparse=False)
其中Numpy 使用的是 start:end:step
的表示且这里的结果不包括 end
的值
为了包含 end
的值,我们可以使用这样的技巧:
#在 step 的位置传入一个复数 5j ,表示我们需要一个 5 个值的数组,此时返回值就会包含 end
x, y = np.ogrid[-1:1:5j, -1:1:5j]
(array([[-1. ],
[-0.5],
[ 0. ],
[ 0.5],
[ 1. ]]), array([[-1. , -0.5, 0. , 0.5, 1. ]]))
- r_,c_函数
np.r_[0:1:.1] #array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
np.r_[0:1:5j] #array([ 0. , 0.25, 0.5 , 0.75, 1. ])
np.r_[(3,22,11), 4.0, [15, 6]] #array([ 3., 22., 11., 4., 15., 6.])
列向量:
np.c_[1:3:5j] #array([[ 1. ],[ 1.5],[ 2. ],[ 2.5],[ 3. ]])
- one_like(),zero_like()函数
a = np.arange(0, 10, 2.5)
np.empty_like(a)
np.zeros_like(a)
np.ones_like(a)
- identity()
np.identity(3) #产生一个 n 乘 n 的单位矩阵
2.矩阵
numpy基本类型为 ndarray,
但提供了支持矩阵操作的类 matrix
mat方法
a = np.array([[1,2,4],[2,5,3], [7,8,9]])
A = np.mat(a) #matrix([[1, 2, 4],[2, 5, 3],[7, 8, 9]])
#A = np.mat('1,2,4;2,5,3;7,8,9')
a = np.array([[ 1, 2],
[ 3, 4]])
b = np.array([[10,20],
[30,40]])
np.bmat('a,b;b,a')
matrix([[ 1, 2, 10, 20], [ 3, 4, 30, 40], [10, 20, 1, 2], [30, 40, 3, 4]])
注意:
对array,A*B是逐元素相乘,对matrix,A*B是矩阵相乘,multiply函数才能实现逐元素相乘。
3.Numpy类型
布尔型 | bool | |
整型 | int8, int16, int32, int64, int128, int | |
无符号整型 | | |
浮点数 | float16, float32, float64, float, longfloat | 默认为双精度 |
复数 | complex64, complex128, complex, longcomplex | 默认为 |
字符串 | string, unicode | 可以使用 |
对象 | object | 数组中可以使用任意值 |
Records | void | |
时间 | datetime64, timedelta64 | |
| |
a = array([1,1.2,'hello', [10,20,30]],dtype=object)
a * 2
array([2, 2.4, 'hellohello', [10, 20, 30, 10, 20, 30]], dtype=object)
可用asarray()修改类型,但不会改变原数组值
b = a.view(uint8) #view 会将 a 在内存中的表示看成是 uint8 进行解析,修共用一块内存
asarray(a, dtype=uint8)
4.各种属性查看
- 查看列表属性:
type(a) #numpy.ndarray
- 查看数组维度:
np.array(a) #1
1
- 查看数组中的数据类型:
a.dtype
int32
- 查看array形状:
a.shape
a.shape=2,2 #(4L,)
a.reshape(2,2) #array([1,2],[3,4])
- 查看每个元素所占的字节:
a.itemsize
- 增加或去除数组维数:
y = a[newaxis, :] #(1L, 3L)
y = a[:, newaxis] #(3L, 1L)
y = a[newaxis, newaxis, :] #(1L, 1L, 3L)
a = arange(6)
a.shape = (2,1,3)
b = a.squeeze() #(2L, 3L) #去除多余的轴,返回一个将所有长度为1的维度去除的新数组
- 列表不支持将列表中的每个元素增加1的操作,用array可以
a+1
b=array([2,3,4,5])
a+b
a*b //对应元素相乘,不是按照矩阵乘法(多维矩阵时注意)
5.where语句
- 对于一维:
a = array([0, 12, 5, 20])
a > 10
array([False, True, False, True], dtype=bool)
indices = where(a > 10)
indices = indices[0]
indices
indices = where(a>10)[0] #array([1, 3], dtype=int64)
注意到 where
的返回值是一个元组。
使用元组是由于 where 可以对多维数组使用,此时返回值就是多维的。
可以直接用 where
的返回值进行索引:
loc = where(a > 10)
a[loc]
array([12, 20])
2.多维数组
a = array([[0, 12, 5, 20],
[1, 2, 11, 15]])
loc = where(a > 10)
loc
(array([0, 0, 1, 1], dtype=int64), array([1, 3, 2, 3], dtype=int64))
3.np.where(condition, x, y):符合条件输出x,否则y
np.where([[True,False], [True,True]], # 官网上的例子
[[1,2], [3,4]],
[[9,8], [7,6]])
array([[1, 8],
[3, 4]])
第一个值从[1,9]
中选,因为条件为True,所以是选1。第二个值从[2,8]
中选,因为条件为False,所以选8,后面以此类推
6.数据读取
txt文本文件,npy二进制文件
data = np.loadtxt('myfile.txt',
skiprows=1, #忽略第一行
dtype=np.int, #数组类型
delimiter=',', #逗号分割
usecols=(0,1,2,4), #指定使用哪几列数据
comments='%' #百分号为注释符
)
import os
a = array([102,111,212],
dtype=uint8)
a.tofile('foo.dat') #写入二进制数据
b = frombuffer('foo', dtype=uint8) #从数据中读入,要指定类型
os.remove('foo.dat') #清理数据文件
data = np.array([[1,2],
[3,4]])
np.savetxt('out.txt', datafmt="%d") #保存为整数,默认使用科学计数法的形式保存
with open('out.txt') as f:
for line in f:
print line
1 2
3 4
7.数组方法
求和:
a = array([[1,2,3],[4,5,6]])
sum(a) #求所有元素的和或a.sum()
sum(a, axis=0) #沿着第一维求和或a.sum(axis=0)
sum(a, axis=-1) #沿着最后一维求和
求积:
a.prod() #求所有元素的乘积
prod(a, axis=0) #array([4,10,18])
求最大最小值:
a.min() #全局最小
a.min(axis=0) #沿着某个轴的最小
a.argmin()
a.argmin(axis=0) #max同理
均值:
a.mean()
a.mean(axis=-1)
average(a, axis = 0)
average(a, axis = 0, weights=[1,2]) #average 函数还支持加权平均
标准差:
a.std(axis=1) #用 std 方法计算标准差
a.var(axis=1) #用 var 方法计算方差
限制数据:
a.clip(3,5) #小于3的变成3,大于5的变成5
计算最大值和最小值之差:
a.ptp(axis=1)
a.ptp()
数组倒置:
对于复数数组,转置并不返回复共轭,只是单纯的交换轴的位置,原数组的值也改变
a.transpose()
#a.T //缩写
连接:
#x(2L,3L),y(2L.3L)
z = concatenate((x,y)) #默认沿着第一维进行连接(4L,3L)
z = concatenate((x,y), axis=1) #沿着第二维进行连接(2L,6L)
vstack((x, y)) #(4L, 3L)
hstack((x, y)) #(2L, 6L)
dstack((x, y)) #(2L, 3L, 2L)
查看它的对角线元素:
a.diagonal()
a.diagonal(offset=1) #使用偏移来查看它的次对角线,正数表示右移,负数表示左移
i = [0,1,2]
a[i, i] = 2 #更新对角线的值
8.排序
weights = array([20.8, 93.2, 53.4, 61.8])
#也支持方法操作,但是sort方法会改变数组的值
sort(weights) #返回的结果是从小到大排列的
argsort(weights) #从小到大的排列在数组中的索引位置
二维:
a = array([[.2, .1, .5], [.4, .8, .3],[.9, .6, .7]])
sort(a) #默认相当于对每一行进行排序
sort(a, axis = 0) #改变轴,对每一列进行排序
searchsorted(sorted_array, values),第一个必需是已排序的数组,返回的值相当于保持第一个数组的排序性质不变,将第二个数组中的值插入第一个数组中的位置
from numpy.random import rand
data = rand(100)
data.sort()
bounds = .4, .6
low_idx, high_idx = searchsorted(data, bounds)
data[low_idx:high_idx] #利用插入位置,将数组中所有在这两个值之间的值提取出来
9.数组与字符串转换
a.tostring() #转化为字符串
a = np.fromstring(s, dtype=np.uint8) #使用 fromstring 函数从字符串中读出数据,不过要指定类型
二.索引操作
简单操作
提取元素,切片,索引操作与python数组相同,下面之讲解多维数组。
a=array([0,1,2,3],[10,11,12,13])
a[1,3]=-1 //利用索引赋值
a[1] //返回第二行元素组成的array
a[0,1:3] //第一行第2,3个元素
a[0::1,::2] //[lower:upper:step]
(ps:切片是引用机制,意味着,Python并没有为 b
分配新的空间来存储它的值,而是让 b
指向了 a
所分配的内存空间,因此,改变 b
会改变 a
的值
a=array([1,2,2,3,4])
b=a[2:4]
b[0]=10
print(a)
[0,1,10,3,4]
若不改变可采用copy()进行赋值,申请新的内存
a = array([0,1,2,3,4])
b = a[2:4].copy()
b[0] = 10
print(a)
[0, 1, 2, 3, 4]
但是这种现象在列表中不会出现
花式索引
- 一维
切片只能支持连续或者等间隔的切片操作,要想实现任意位置的操作,需要使用花式索引
与 range 函数类似,我们可以使用 arange 函数来产生等差数组
a = np.arange(0, 80, 10)
花式索引需要指定索引位置:
indices = [1, 2, -3]
y = a[indices]
print y
[10 20 50]
还可以使用布尔数组来花式索引:
mask = array([0,1,1,0,0,1,0,0],
dtype=bool)
a[mask]
array([10, 20, 50])
或者用布尔表达式生成 mask(
mask 必须是布尔数组):
from numpy.random import rand
a = rand(10)
mask = a > 0.5
a[mask]
array([ 0.73365131, 0.62068734, 0.53085308])
- 二维:
对于二维花式索引,我们需要给定 row
和 col
的值
a = 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[(0,1,2,3,4), (1,2,3,4,5)]
array([ 1, 12, 23, 34, 45])
mask = array([1,0,1,0,0,1],
dtype=bool)
a[mask, 2]
array([ 2, 22, 52])
三.其他操作
1.向量化函数
def sinc(x):
if x == 0.0:
return 1.0
else:
w = np.pi * x
return np.sin(w) / w
但这个函数不能作用于数组x = np.array([1,2,3])
此时可以使用 numpy
的 vectorize
将函数 sinc
向量化,产生一个新的函数
vsinc = np.vectorize(sinc) #其作用是为 x 中的每一个值调用 sinc 函数
2.ufunc对象
Numpy 有两种基本对象:ndarray (N-dimensional array object)
和 ufunc (universal function object)
。ndarray
是存储单一数据类型的多维数组,而 ufunc
则是能够对数组进行处理的函数,比如add()对象,accumulate方法等
a = np.array([1,2,3,4])
np.add.accumulate(a) #array([ 1, 3, 6, 10])
outer()方法
a = np.array([0,1])
b = np.array([1,2,3])
#对于 a 中每个元素,将 op 运用到它和 b 的每一个元素上所得到的结果
np.add.outer(a, b) #array([[1, 2, 3],[2, 3, 4]])
3.choose函数实现条件筛选
control = np.array([[1,0,1],
[2,1,0],
[1,2,2]])
np.choose(control, [10, 11, 12]) #将 0,1,2 对应的值映射为了 10, 11, 12
array([[11, 10, 11], [12, 11, 10], [11, 12, 12]])
i0 = np.array([[0,1,2],
[3,4,5],
[6,7,8]])
i2 = np.array([[20,21,22],
[23,24,25],
[26,27,28]])
control = np.array([[1,0,1],
[2,1,0],
[1,2,2]])
np.choose(control, [i0, 10, i2])#choose 不仅仅能接受下标参数,还可以接受下标所在的位置
array([[10, 1, 10], [23, 10, 5], [10, 27, 28]])
np.choose(a < 10, (a, 10)) #将数组中所有小于 10 的值变成了 10
np.choose(choice, (a, 10, 15)) #将数组中所有小于 10 的值变成了 10,大于 15 的值变成了 15
4.结构化数组
a = np.array([1.0,2.0,3.0,4.0], np.float32)
使用 view
方法,将 a
对应的内存按照复数来解释,即我们可以把复数看成一个结构体:
a.view(np.complex64)
换句话说,我们只需要换种方式解释这段内存,便可以得到结构化数组的效果,dtype
创造了自定义的结构类型,然后用自定义的结构来解释数组 a
所占的内存
my_dtype = np.dtype([('mass', 'float32'), ('vol', 'float32')])
a.view(my_dtype)
my_data[0]['vol'] #得到第一个元素的速度信息,可以使用域的名称来索引
自定义排序规则,先按速度,再按质量:
my_data.sort(order=('vol', 'mass'))
生成记录数组要使用 numpy.rec
里的 fromrecords
方法
from numpy import rec
particals_rec = rec.fromrecords([(1,1), (1,2), (2,1), (1,3)],
dtype = partical_dtype)
#在记录数组中,域可以通过属性来获得:
particals_rec.mass #也可以通过域来查询:particals_rec['mass']
array([ 1., 1., 2., 1.])
5.内存映射
内存映射也是一种处理文件的方法,内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对文件进行映射。
使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。
- memmap
memmap(filename,
dtype=uint8,
mode='r+'
offset=0
shape=None
order=0)
mode
表示文件被打开的类型:
r
只读,c
复制+写,但是不改变源文件r+
读写,使用 flush
方法会将更改的内容写入文件,w+
写,如果存在则将数据覆盖
offset
表示从第几个位置开始。
四.比较总结
matlab,numpy_array, numpy_matrix
|
|
|
|
|
|
| 分块矩阵构造 |
|
|
| 最后一个元素 |
|
|
| 复共轭转置 |
|
|
| 矩阵乘法 |
|
|
| 逐元素乘法 |
|
|
| 逐元素立方 |
|
|
| 找出行向量 |
|
|
| 找出列向量 |
|
|
| 将所有小于 0.5 的元素设为 0 |
|
|
| 这里 |
|
|
| |
|
|
| 列向量 |
|
|
| |
|
|
| 0~1 随机数 |
|
|
| 网格 |
|
| 建议在 | |
|
|
| |
|
| | |
|
|
| 产生 |
|
|
| 列对齐连接 |
|
|
| 行对齐连接 |
|
|
| 模 |
|
|
| QR 分解 |
|
|
| LU 分解 |
|
|
| FFT |
|
|
| IFFT |
|
|
| 排序 |