随机数
numpy.random.permutation
>>> np.random.permutation(10)
array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6])
>>> np.random.permutation([1, 4, 9, 12, 15])
array([15, 1, 9, 4, 12])
>>> arr = np.arange(9).reshape((3, 3))
>>> np.random.permutation(arr)
array([[6, 7, 8],
[0, 1, 2],
[3, 4, 5]])
来源:http://www.jb51.net/article/49397.htm
1、Numpy是什么
很简单,Numpy是Python的一个科学计算的库,提供了矩阵运算的功能,其一般与Scipy、matplotlib一起使用。其实,list已经提供了类似于矩阵的表示形式,不过numpy为我们提供了更多的函数。如果接触过matlab、scilab,那么numpy很好入手。 在以下的代码示例中,总是先导入了numpy:
>>> import numpy as np
>>> print np.version.version
1.6.2
2、多维数组
多维数组的类型是:numpy.ndarray。
使用numpy.array方法
以list或tuple变量为参数产生一维数组:
>>> print np.array([1,2,3,4])
[1 2 3 4]
>>> print np.array((1.2,2,3,4))
[ 1.2 2. 3. 4. ]
>>> print type(np.array((1.2,2,3,4)))
<type 'numpy.ndarray'>
以list或tuple变量为元素产生二维数组:
>>> print np.array([[1,2],[3,4]])
[[1 2]
[3 4]]
生成数组的时候,可以指定数据类型,例如numpy.int32, numpy.int16, and numpy.float64等:
>>> print np.array((1.2,2,3,4), dtype=np.int32)
[1 2 3 4]
使用numpy.arange方法
>>> print np.arange(15)
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
>>> print type(np.arange(15))
<type 'numpy.ndarray'>
>>> print np.arange(15).reshape(3,5)
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
>>> print type(np.arange(15).reshape(3,5))
<type 'numpy.ndarray'>
使用numpy.linspace方法
例如,在从1到3中产生9个数:
>>> print np.linspace(1,3,9)
[ 1. 1.25 1.5 1.75 2. 2.25 2.5 2.75 3. ]
使用numpy.zeros,numpy.ones,numpy.eye等方法可以构造特定的矩阵
>>> print np.zeros((3,4))
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
>>> print np.ones((3,4))
[[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]]
>>> print np.eye(3)
[[ 1. 0. 0.]
[ 0. 1. 0.]
[ 0. 0. 1.]]
创建一个三维数组:
>>> print np.zeros((2,2,2))
[[[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]]]
获取数组的属性:
>>> a = np.zeros((2,2,2))
>>> print a.ndim #数组的维数
3
>>> print a.shape #数组每一维的大小
(2, 2, 2)
>>> print a.size #数组的元素数
8
>>> print a.dtype #元素类型
float64
>>> print a.itemsize #每个元素所占的字节数
8
数组索引,切片,赋值
>>> a = np.array( [[2,3,4],[5,6,7]] )
>>> print a
[[2 3 4]
[5 6 7]]
>>> print a[1,2]
7
>>> print a[1,:]
[5 6 7]
>>> print a[1,1:2]
[6]
>>> a[1,:] = [8,9,10]
>>> print a
[[ 2 3 4]
[ 8 9 10]]
>>> for x in np.linspace(1,3,3):
... print x
...
1.0
2.0
3.0
基本的数组运算
先构造数组a、b:
>>> a = np.ones((2,2))
>>> b = np.eye(2)
>>> print a
[[ 1. 1.]
[ 1. 1.]]
>>> print b
[[ 1. 0.]
[ 0. 1.]]
数组的加减乘除:
>>> print a > 2
[[False False]
[False False]]
>>> print a+b
[[ 2. 1.]
[ 1. 2.]]
>>> print a-b
[[ 0. 1.]
[ 1. 0.]]
>>> print b*2
[[ 2. 0.]
[ 0. 2.]]
>>> print (a*2)*(b*2)
[[ 4. 0.]
[ 0. 4.]]
>>> print b/(a*2)
[[ 0.5 0. ]
[ 0. 0.5]]
>>> print (a*2)**4
[[ 16. 16.]
[ 16. 16.]]
使用数组对象自带的方法:
>>> a.sum()
4.0
>>> a.sum(axis=0) #计算每一列(二维数组中类似于矩阵的列)的和
array([ 2., 2.])
>>> a.min()
1.0
>>> a.max()
1.0
使用numpy下的方法:
>>> np.sin(a)
array([[ 0.84147098, 0.84147098],
[ 0.84147098, 0.84147098]])
>>> np.max(a)
1.0
>>> np.floor(a)
array([[ 1., 1.],
[ 1., 1.]])
>>> np.exp(a)
array([[ 2.71828183, 2.71828183],
[ 2.71828183, 2.71828183]])
>>> np.dot(a,a) ##矩阵乘法
array([[ 2., 2.],
[ 2., 2.]])
合并数组
使用numpy下的vstack和hstack函数:
>>> a = np.ones((2,2))
>>> b = np.eye(2)
>>> print np.vstack((a,b))
[[ 1. 1.]
[ 1. 1.]
[ 1. 0.]
[ 0. 1.]]
>>> print np.hstack((a,b))
[[ 1. 1. 1. 0.]
[ 1. 1. 0. 1.]]
看一下这两个函数有没有涉及到浅拷贝这种问题:
>>> c = np.hstack((a,b))
>>> print c
[[ 1. 1. 1. 0.]
[ 1. 1. 0. 1.]]
>>> a[1,1] = 5
>>> b[1,1] = 5
>>> print c
[[ 1. 1. 1. 0.]
[ 1. 1. 0. 1.]]
可以看到,a、b中元素的改变并未影响c。
深拷贝数组
数组对象自带了浅拷贝和深拷贝的方法,但是一般用深拷贝多一些:
>>> a = np.ones((2,2))
>>> b = a
>>> b is a
True
>>> c = a.copy() #深拷贝
>>> c is a
False
基本的矩阵运算
转置:
>>> a = np.array([[1,0],[2,3]])
>>> print a
[[1 0]
[2 3]]
>>> print a.transpose()
[[1 2]
[0 3]]
迹:
>>> print np.trace(a)
4
numpy.linalg模块中有很多关于矩阵运算的方法:
>>> import numpy.linalg as nplg
特征值、特征向量:
>>> print nplg.eig(a)
(array([ 3., 1.]), array([[ 0. , 0.70710678],
[ 1. , -0.70710678]]))
http://blog.csdn.net/hickai/article/details/23431843
1、Numpy是什么
很简单,Numpy是Python的一个科学计算的库,提供了矩阵运算的功能,其一般与Scipy、matplotlib一起使用。其实,list已经提供了类似于矩阵的表示形式,不过numpy为我们提供了更多的函数。如果接触过matlab、scilab,那么numpy很好入手。 在以下的代码示例中,总是先导入了numpy:
>>> import numpy as np
>>> print np.version.version
1.6.2
2、多维数组
多维数组的类型是:numpy.ndarray。
使用numpy.array方法
以list或tuple变量为参数产生一维数组:
[1 2 3 4]
>>> print np.array((1.2,2,3,4))
[ 1.2 2. 3. 4. ]
>>> print type(np.array((1.2,2,3,4)))
<type 'numpy.ndarray'>
以list或tuple变量为元素产生二维数组:
>>> print np.array([[1,2],[3,4]])
[[1 2]
[3 4]]
生成数组的时候,可以指定数据类型,例如numpy.int32, numpy.int16, and numpy.float64等:
>>> print np.array((1.2,2,3,4), dtype=np.int32)
[1 2 3 4]
使用numpy.arange方法
>>> print np.arange(15)
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
>>> print type(np.arange(15))
<type 'numpy.ndarray'>
>>> print np.arange(15).reshape(3,5)
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
>>> print type(np.arange(15).reshape(3,5))
<type 'numpy.ndarray'>
使用numpy.linspace方法
例如,在从1到3中产生9个数:
>>> print np.linspace(1,3,9)
[ 1. 1.25 1.5 1.75 2. 2.25 2.5 2.75 3. ]
使用numpy.zeros,numpy.ones,numpy.eye等方法可以构造特定的矩阵
例如:
>>> print np.zeros((3,4))
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
>>> print np.ones((3,4))
[[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]]
>>> print np.eye(3)
[[ 1. 0. 0.]
[ 0. 1. 0.]
[ 0. 0. 1.]]
创建一个三维数组:
>>> print np.zeros((2,2,2))
[[[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]]]
获取数组的属性:
>>> a = np.zeros((2,2,2))
>>> print a.ndim #数组的维数
3
>>> print a.shape #数组每一维的大小
(2, 2, 2)
>>> print a.size #数组的元素数
8
>>> print a.dtype #元素类型
float64
>>> print a.itemsize #每个元素所占的字节数
8
数组索引,切片,赋值
示例:
>>> a = np.array( [[2,3,4],[5,6,7]] )
>>> print a
[[2 3 4]
[5 6 7]]
>>> print a[1,2]
7
>>> print a[1,:]
[5 6 7]
>>> print a[1,1:2]
[6]
>>> a[1,:] = [8,9,10]
>>> print a
[[ 2 3 4]
[ 8 9 10]]
使用for操作元素
>>> for x in np.linspace(1,3,3):
... print x
...
1.0
2.0
3.0
基本的数组运算
先构造数组a、b:
>>> a = np.ones((2,2))
>>> b = np.eye(2)
>>> print a
[[ 1. 1.]
[ 1. 1.]]
>>> print b
[[ 1. 0.]
[ 0. 1.]]
数组的加减乘除:
>>> print a > 2
[[False False]
[False False]]
>>> print a+b
[[ 2. 1.]
[ 1. 2.]]
>>> print a-b
[[ 0. 1.]
[ 1. 0.]]
>>> print b*2
[[ 2. 0.]
[ 0. 2.]]
>>> print (a*2)*(b*2)
[[ 4. 0.]
[ 0. 4.]]
>>> print b/(a*2)
[[ 0.5 0. ]
[ 0. 0.5]]
>>> print (a*2)**4
[[ 16. 16.]
[ 16. 16.]]
使用数组对象自带的方法:
>>> a.sum()
4.0
>>> a.sum(axis=0) #计算每一列(二维数组中类似于矩阵的列)的和
array([ 2., 2.])
>>> a.min()
1.0
>>> a.max()
1.0
使用numpy下的方法:
>>> np.sin(a)
array([[ 0.84147098, 0.84147098],
[ 0.84147098, 0.84147098]])
>>> np.max(a)
1.0
>>> np.floor(a)
array([[ 1., 1.],
[ 1., 1.]])
>>> np.exp(a)
array([[ 2.71828183, 2.71828183],
[ 2.71828183, 2.71828183]])
>>> np.dot(a,a) ##矩阵乘法
array([[ 2., 2.],
[ 2., 2.]])
合并数组
使用numpy下的vstack和hstack函数:
>>> a = np.ones((2,2))
>>> b = np.eye(2)
>>> print np.vstack((a,b))
[[ 1. 1.]
[ 1. 1.]
[ 1. 0.]
[ 0. 1.]]
>>> print np.hstack((a,b))
[[ 1. 1. 1. 0.]
[ 1. 1. 0. 1.]]
看一下这两个函数有没有涉及到浅拷贝这种问题:
>>> c = np.hstack((a,b))
>>> print c
[[ 1. 1. 1. 0.]
[ 1. 1. 0. 1.]]
>>> a[1,1] = 5
>>> b[1,1] = 5
>>> print c
[[ 1. 1. 1. 0.]
[ 1. 1. 0. 1.]]
可以看到,a、b中元素的改变并未影响c。
深拷贝数组
数组对象自带了浅拷贝和深拷贝的方法,但是一般用深拷贝多一些:
>>> b = a
>>> b is a
True
>>> c = a.copy() #深拷贝
>>> c is a
False
基本的矩阵运算
转置:
>>> a = np.array([[1,0],[2,3]])
>>> print a
[[1 0]
[2 3]]
>>> print a.transpose()
[[1 2]
[0 3]]
迹:
4
numpy.linalg模块中有很多关于矩阵运算的方法:
>>> import numpy.linalg as nplg
特征值、特征向量:
>>> print nplg.eig(a)
(array([ 3., 1.]), array([[ 0. , 0.70710678],
[ 1. , -0.70710678]]))
3、矩阵
numpy也可以构造矩阵对象,这里不做讨论。
Numpy简介
Numpy(Numerical Python的简称)是高性能科学计算和数据分析的基础包。其部分功能如下:
①ndarray,一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组。②用于对整组数据进行快速运算的标准数学函数(无需编写循环)。
③用于读写磁盘数据的工具以及用于操作内存映射文件的工具。
④线性代数、随机数生成以及傅里叶变换功能。
⑤用于集成由C、C++、Fortran等语言编写的代码的工具。
创建数组
创建数组最简单的办法是使用array函数。它接受一切序列型的对象(包括其他数组),然后产生一个新的含有传入数据的NumPy数组。以一个列表的转换为例:
- data1=[6,7.5,8,0,1] #创建列表
- arr1=np.array(data1) #转换为数组
- arr1.dtype #数据类型保存在dtype对象中
- data2=[[1,2,3,4],[5,6,7,8]] #创建嵌套序列(由等长列表组成的列表)
- arr2=np.array(data2) #转换为多维数组
- np.zeros(10) #创建指定长度(10)的全0数组
- np.ones((3,6)) #创建指定长度的(3行6列二维)的全1数组
- range(10) #创建指定数量的顺序列表(内置函数,默认0开始)
- arange(10) #创建指定数量的顺序数组
- eye(10) #创建一个正方的N×N单位矩阵
- arr1=np.array([1,2,3],dtype=np.float64) #解释为特定数据类型
data1=[6,7.5,8,0,1] #创建列表
arr1=np.array(data1) #转换为数组
arr1.dtype #数据类型保存在dtype对象中
data2=[[1,2,3,4],[5,6,7,8]] #创建嵌套序列(由等长列表组成的列表)
arr2=np.array(data2) #转换为多维数组
np.zeros(10) #创建指定长度(10)的全0数组
np.ones((3,6)) #创建指定长度的(3行6列二维)的全1数组
range(10) #创建指定数量的顺序列表(内置函数,默认0开始)
arange(10) #创建指定数量的顺序数组
eye(10) #创建一个正方的N×N单位矩阵
arr1=np.array([1,2,3],dtype=np.float64) #解释为特定数据类型
数组和标量之间的运算
arr=np.array([[1.,2.,3.],[4.,5.,6.]]) #创建二维数组
arr*arr #行列号相同的数组元素间运算
arr-arr
1/arr
arr*0.5
基本的索引与切片
- arr=np.arange(10)
- arr[5] #索引第6个元素
- arr[5:8] #索引第6到第9个元素作为数组
- arr[5:8]=12 #令第6到第9个元素等于12
- arr_slice=arr[5:8] #数组切片是原始数据的视图,视图上的任何修改都会反映到原数组
- arr_slice[:]=64 #将数组切片的全部元素改为64
- arr[5:8].copy() #得到数组切片的一份副本
- arr2d=np.array([[1,2,3],[4,5,6],[7,8,9]])
- arr2d[2] #索引二维数组第3行
- arr2d[0][2] arr2d[0,2] #等价索引1行3列元素
- arr2d[:2] #索引第1行和第2行(不含第3行)
- arr2d[:,:1] #索引第1列
- arr2d[:-2] #使用负数索引将从尾部开始选取行
arr=np.arange(10)
arr[5] #索引第6个元素
arr[5:8] #索引第6到第9个元素作为数组
arr[5:8]=12 #令第6到第9个元素等于12
arr_slice=arr[5:8] #数组切片是原始数据的视图,视图上的任何修改都会反映到原数组
arr_slice[:]=64 #将数组切片的全部元素改为64
arr[5:8].copy() #得到数组切片的一份副本
arr2d=np.array([[1,2,3],[4,5,6],[7,8,9]])
arr2d[2] #索引二维数组第3行
arr2d[0][2] arr2d[0,2] #等价索引1行3列元素
arr2d[:2] #索引第1行和第2行(不含第3行)
arr2d[:,:1] #索引第1列
arr2d[:-2] #使用负数索引将从尾部开始选取行
数组转置和轴对换
转置(transpose)是重塑的一种特殊形式,它返回的是源数据的视图(不会进行复制操作)。
- arr=np.arange(15).reshape((3,5)) #生成顺序数组,后整形为3行5列
- arr.T #转置
- arr=np.random.randn(6,3) #randn函数生成一些正态分布的随机数组(6行3列)
- np.dot(arr.T,arr) #利用np.dot计算矩阵内积XTX
arr=np.arange(15).reshape((3,5)) #生成顺序数组,后整形为3行5列
arr.T #转置
arr=np.random.randn(6,3) #randn函数生成一些正态分布的随机数组(6行3列)
np.dot(arr.T,arr) #利用np.dot计算矩阵内积XTX
通用函数:快速的元素级数组函数
通用函数(即ufunc)是一种对ndarray中的数据执行元素级运算的函数。
- arr=np.arange(10)
- np.sqrt(arr) #计算各元素的平方根(arr**0.5)
- exp #计算各元素指数ex; abs #绝对值;
- np.add(x,y) #x、y数组中对应元素相加; subtract #相减; multiply #相乘; divide #相除;
arr=np.arange(10)
np.sqrt(arr) #计算各元素的平方根(arr**0.5)
exp #计算各元素指数ex; abs #绝对值;
np.add(x,y) #x、y数组中对应元素相加; subtract #相减; multiply #相乘; divide #相除;
利用数组进行数据处理
用数组表达式代替循环的做法,通常称为矢量化
将条件逻辑表述为数组运算
Numpy.where函数是三元表达式x if condition else y的矢量化版本
- xarr=np.array([1.1,1.2,1.3,1.4,1.5]) #两个数值数组
- yarr=np.array([2.1,2.2,2.3,2.4,2.5])
- cond=np.array([True,False,True,True,False]) #一个布尔数组
- result=np.where(cond,xarr,yarr) #三元表达式
xarr=np.array([1.1,1.2,1.3,1.4,1.5]) #两个数值数组
yarr=np.array([2.1,2.2,2.3,2.4,2.5])
cond=np.array([True,False,True,True,False]) #一个布尔数组
result=np.where(cond,xarr,yarr) #三元表达式
数学和统计方法
可以通过数组上的一组数学函数对整个数组或某个轴向的数据进行统计计算。Sum、mean以及标准差std等聚合计算(aggregation,通常叫做约简(reduction))既可以当做数组的实例方法调用,也可以当做顶级NumPy函数使用:
arr=np.random.randn(5,4)
arr.mean(); np.mean(arr); arr.sum();
arr.mean(axis=1) #计算该轴上的统计值(0为列,1为行)
用于布尔型数组的方法
布尔值会被强制转换为1(True)和0(False)。因此,sum经常被用来对布尔型数组中的True值计数:
- arr=randn(100)
- (arr>0).sum() #正值的数量
- bools.any() #用于测试数组中是否存在一个或多个True
- bools.all() #用于测试数组中所有值是否都是True
arr=randn(100)
(arr>0).sum() #正值的数量
bools.any() #用于测试数组中是否存在一个或多个True
bools.all() #用于测试数组中所有值是否都是True
排序
跟Python内置的列表类型一样,NumPy数组也可以通过sort方法就地排序(修改数组本身)。
arr=randn(8)
arr.sort()
arr=randn(5,3)
arr.sort(0) #二维数组按列排序; arr.sort(1) #二维数组按行排序;
唯一化
ints=np.array([3,3,3,2,2,1,1,4,4])
np.unique(names) #找出数组中的唯一值并返回已排序的结果
用于数组的文件输入输出
Numpy能够读写磁盘上的文本数据或二进制数据。
- arr=np.arange(10)
- np.save(‘some_array’,arr) #数组以未压缩的原始二进制格式保存在.npy文件中
- np.load(‘some_array’) #通过np.load读取磁盘上的数组
- np.savez(‘array_archive.npz’,a=arr,b=arr) #将多个数组以保存在一个压缩文件中
- a=np.arange(0,12,0.5).reshape(4,-1)
- np.savetxt(‘E:\\knakan\\a.txt’,a) #缺省按照’%.18e’格式保存数据,以空格分隔
- np.loadtxt(‘E:\\kankan\\a.txt’)
- np.savetxt(‘E:\\kankan\\a.txt’,a,fmt=”%d”,delimiter=”,”) #改为保存为整数,以逗号分隔
- np.loadtxt(‘E:\\kankan\\a.txt’,delimiter=”,”) #读入时也需指定逗号分隔
arr=np.arange(10)
np.save(‘some_array’,arr) #数组以未压缩的原始二进制格式保存在.npy文件中
np.load(‘some_array’) #通过np.load读取磁盘上的数组
np.savez(‘array_archive.npz’,a=arr,b=arr) #将多个数组以保存在一个压缩文件中
a=np.arange(0,12,0.5).reshape(4,-1)
np.savetxt(‘E:\\knakan\\a.txt’,a) #缺省按照’%.18e’格式保存数据,以空格分隔
np.loadtxt(‘E:\\kankan\\a.txt’)
np.savetxt(‘E:\\kankan\\a.txt’,a,fmt=”%d”,delimiter=”,”) #改为保存为整数,以逗号分隔
np.loadtxt(‘E:\\kankan\\a.txt’,delimiter=”,”) #读入时也需指定逗号分隔
线性代数
- x=np.array([[1.,2.,3.],[4.,5.,6.]])
- y=np.array([[6.,23.],[-1,7],[8,9]])
- x.dot(y) #矩阵乘法,相当于np.dot(x,y)
来源:http://book.51cto.com/art/201406/441434.htm
1.4.4 学习NumPy(1)
让我们引入NumPy,并小试一下。对此,需要打开Python交互界面。
- >>> import numpy
- >>> numpy.version.full_version
- 1.6.2
由于我们并不想破坏命名空间,所以肯定不能做下面这样的事情:
- >>> from numpy import *
这个numpy.array数组很可能会遮挡住标准Python中包含的数组模块。相反,我们将会采用下面这种便捷方式:
- >>> import numpy as np
- >>> a = np.array([0,1,2,3,4,5])
- >>> a
- array([0, 1, 2, 3, 4, 5])
- >>> a.ndim
- 1
- >>> a.shape
- (6,)
这里只是采用了与在Python中创建列表相类似的方法来创建数组。不过,NumPy数组还包含更多关于数组形状的信息。在这个例子中,它是一个含有5个元素的一维数组。到目前为止,并没有什么令人惊奇的。
现在我们将这个数组转换到一个2D矩阵中:
- >>> b = a.reshape((3,2))
- >>> b
- array([[0, 1],
- [2, 3],
- [4, 5]])
- >>> b.ndim
- 2
- >>> b.shape
- (3, 2)
当我们意识到NumPy包优化到什么程度时,有趣的事情发生了。比如,它在所有可能之处都避免复制操作。
- >>> b[1][0]=77
- >>> b
- array([[ 0, 1],
- [77, 3],
- [ 4, 5]])
- >>> a
- array([ 0, 1, 77, 3, 4, 5])
在这个例子中,我们把b的值从2改成77,然后立刻就会发现相同的改动已经反映在a中。当你需要一个真正的副本时,请记住这个。
- >>> c = a.reshape((3,2)).copy()
- >>> c
- array([[ 0, 1],
- [77, 3],
- [ 4, 5]])
- >>> c[0][0] = -99
- >>> a
- array([ 0, 1, 77, 3, 4, 5])
- >>> c
- array([[-99, 1],
- [ 77, 3],
- [ 4, 5]])
这里,c和a是完全独立的副本。
NumPy数组还有一大优势,即对数组的操作可以传递到每个元素上。
- >>> a*2
- array([ 2, 4, 6, 8, 10])
- >>> a**2
- array([ 1, 4, 9, 16, 25])
- Contrast that to ordinary Python lists:
- >>> [1,2,3,4,5]*2
- [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
- >>> [1,2,3,4,5]**2
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- TypeError: unsupported operand type(s) for ** or pow(): 'list' and
- 'int'
当然,我们在使用NumPy数组的时候会牺牲Python列表所提供的一些敏捷性。像相加、删除这样的简单操作在NumPy数组中会有一点麻烦。幸运的是,这两种方式都可以使用。我们可以根据手头上的任务来选择最适合的那种。
1. 索引
NumPy的部分威力来自于它的通用数组访问方式。
除了正常的列表索引方式,它还允许我们将数组本身当做索引使用。
- >>> a[np.array([2,3,4])]
- array([77, 3, 4])
- >>> a>4
- array([False, False, True, False, False, True], dtype=bool)
- >>> a[a>4]
- array([77, 5])
这还可用于修剪异常值。
- >>> a[a>4] = 4
- >>> a
- array([0, 1, 4, 3, 4, 4])
鉴于这是一个经常碰到的情况,所以这里有一个专门的修剪函数来处理它。如下面的函数调用所示,它将数组值超出某个区间边界的部分修剪掉。
- >>> a.clip(0,4)
- array([0, 1, 4, 3, 4, 4])
2. 处理不存在的值
当我们预处理刚从文本文件中读出的数据时,NumPy的索引能力就派上用场了。这些数据中很可能包含不合法的值,我们像下面这样用numpy.NAN做标记,来表示它不是真实数值。
- c = np.array([1, 2, np.NAN, 3, 4]) # 假设已经从文本文件中读取了数据
- >>> c
- array([ 1., 2., nan, 3., 4.])
- >>> np.isnan(c)
- array([False, False, True, False, False], dtype=bool)
- >>> c[~np.isnan(c)]
- array([ 1., 2., 3., 4.])
- >>> np.mean(c[~np.isnan(c)])
- 2.5
3. 运行时行为比较
让我们比较一下NumPy和标准Python列表的运行时行为。在下面这些代码中,我们将会计算从1到1000的所有数的平方和,并观察这些计算花费了多少时间。为了使评估足够准确,我们重复做了10 000次,并记录下总时间。
- import timeit
- normal_py_sec = timeit.timeit('sum(x*x for x in xrange(1000))',
- number=10000)
- naive_np_sec = timeit.timeit('sum(na*na)',
- setup="import numpy as np; na=np.arange(1000)",
- number=10000)
- good_np_sec = timeit.timeit('na.dot(na)',
- setup="import numpy as np; na=np.arange(1000)",
- number=10000)
- print("Normal Python: %f sec"%normal_py_sec)
- print("Naive NumPy: %f sec"%naive_np_sec)
- print("Good NumPy: %f sec"%good_np_sec)
- Normal Python: 1.157467 sec
- Naive NumPy: 4.061293 sec
- Good NumPy: 0.033419 sec
我们观察到两个有趣的现象。首先,仅用NumPy作为数据存储(原始NumPy)时,花费的时间竟然是标准Python列表的3.5倍。这让我们感到非常惊奇,因为我们原本以为既然它是C扩展,那肯定要快得多。对此,一个解释是,在Python中访问个体数组元素是相当耗时的。只有当我们在优化后的扩展代码中使用一些算法之后,才能获得速度上的提升。一个巨大的提升是:当使用NumPy的dot()函数之后,可以得到25倍的加速。总而言之,在要实现的算法中,应该时常考虑如何将数组元素的循环处理从Python中移到一些高度优化的NumPy或SciPy扩展函数中。
然而,速度也是有代价的。当使用NumPy数组时,我们不再拥有像Python列表那样基本上可以装下任何数据的不可思议的灵活性。NumPy数组中只有一个数据类型。
- >>> a = np.array([1,2,3])
- >>> a.dtype
- dtype('int64')
如果尝试使用不同类型的元素,NumPy会尽量把它们强制转换为最合理的常用数据类型:
- >>> np.array([1, "stringy"])
- array(['1', 'stringy'], dtype='|S8')
- >>> np.array([1, "stringy", set([1,2,3])])
- array([1, stringy, set([1, 2, 3])], dtype=object)
- >>> a>4
- array([False, False, True, False, False, True], dtype=bool)
- >>> a[a>4]
- array([77, 5])
这还可用于修剪异常值。
- >>> a[a>4] = 4
- >>> a
- array([0, 1, 4, 3, 4, 4])
鉴于这是一个经常碰到的情况,所以这里有一个专门的修剪函数来处理它。如下面的函数调用所示,它将数组值超出某个区间边界的部分修剪掉。
- >>> a.clip(0,4)
- array([0, 1, 4, 3, 4, 4])
2. 处理不存在的值
当我们预处理刚从文本文件中读出的数据时,NumPy的索引能力就派上用场了。这些数据中很可能包含不合法的值,我们像下面这样用numpy.NAN做标记,来表示它不是真实数值。
- c = np.array([1, 2, np.NAN, 3, 4]) # 假设已经从文本文件中读取了数据
- >>> c
- array([ 1., 2., nan, 3., 4.])
- >>> np.isnan(c)
- array([False, False, True, False, False], dtype=bool)
- >>> c[~np.isnan(c)]
- array([ 1., 2., 3., 4.])
- >>> np.mean(c[~np.isnan(c)])
- 2.5
3. 运行时行为比较
让我们比较一下NumPy和标准Python列表的运行时行为。在下面这些代码中,我们将会计算从1到1000的所有数的平方和,并观察这些计算花费了多少时间。为了使评估足够准确,我们重复做了10 000次,并记录下总时间。
- import timeit
- normal_py_sec = timeit.timeit('sum(x*x for x in xrange(1000))',
- number=10000)
- naive_np_sec = timeit.timeit('sum(na*na)',
- setup="import numpy as np; na=np.arange(1000)",
- number=10000)
- good_np_sec = timeit.timeit('na.dot(na)',
- setup="import numpy as np; na=np.arange(1000)",
- number=10000)
- print("Normal Python: %f sec"%normal_py_sec)
- print("Naive NumPy: %f sec"%naive_np_sec)
- print("Good NumPy: %f sec"%good_np_sec)
- Normal Python: 1.157467 sec
- Naive NumPy: 4.061293 sec
- Good NumPy: 0.033419 sec
我们观察到两个有趣的现象。首先,仅用NumPy作为数据存储(原始NumPy)时,花费的时间竟然是标准Python列表的3.5倍。这让我们感到非常惊奇,因为我们原本以为既然它是C扩展,那肯定要快得多。对此,一个解释是,在Python中访问个体数组元素是相当耗时的。只有当我们在优化后的扩展代码中使用一些算法之后,才能获得速度上的提升。一个巨大的提升是:当使用NumPy的dot()函数之后,可以得到25倍的加速。总而言之,在要实现的算法中,应该时常考虑如何将数组元素的循环处理从Python中移到一些高度优化的NumPy或SciPy扩展函数中。
然而,速度也是有代价的。当使用NumPy数组时,我们不再拥有像Python列表那样基本上可以装下任何数据的不可思议的灵活性。NumPy数组中只有一个数据类型。
- >>> a = np.array([1,2,3])
- >>> a.dtype
- dtype('int64')
如果尝试使用不同类型的元素,NumPy会尽量把它们强制转换为最合理的常用数据类型:
- >>> np.array([1, "stringy"])
- array(['1', 'stringy'], dtype='|S8')
- >>> np.array([1, "stringy", set([1,2,3])])
- array([1, stringy, set([1, 2, 3])], dtype=object)