Numpy 科学计算库介绍

󰃭 2017-03-02

安装 Numpy

pip install numpy

基本概念

NumPy提供了两种基本的对象:ndarray, ufunc

  • ndarray 是存储单一数据类型的多维数组
  • ufunc 是对数组进行处理的函数

基本使用

创建数组

多维 数组可以每个轴有一个索引。这些索引由一个逗号分割的元组给出

# 通过给array函数传递 Python 序列对象创建数组
# 如果传递的是多层嵌套的序列,将创建多维数组
>>> a = np.array([1,2,3,4,5,6])

>>> b = np.array([7,8,9,10])

>>> c = np.array([[1, 2, 3, 4],[4, 5, 6, 7], [7, 8, 9, 10]])

>>> c.dtype
dtype('int64')

# 数组元素的个数
>>> c.size
12

# 数组类型可以在创建时显示指定
>>> d = np.array( [ [1,2], [3,4] ], dtype=np.int)

# 使用索引访问数据
>>> d[0,0]
1

数组的纬度大小可以通过其shape属性获得

>>> a.shape
(6,)
>>> c.shape
(3, 4)
>>> c
array([[ 1,  2,  3,  4],
       [ 4,  5,  6,  7],
       [ 7,  8,  9, 10]])

还可以通过修改数组的shape属性,在保持数组元素个数不变的情况下,改变数组每个轴的长度

# c 的shape改为(4,3),从(3,4)改为(4,3)不是对数组进行转置,只是改变每个轴的大小
# 数组元素在内存中的位置并没有改变
>>> c.shape = 4, 3
array([[ 1,  2,  3],
       [ 4,  4,  5],
       [ 6,  7,  7],
       [ 8,  9, 10]])

# 当某个轴的元素为-1时,根据数组元素的个数自动计算此轴的长度
# 因此下面的程序将数组 c 的shape改为了(2,6)
>>> c
array([[ 1,  2,  3,  4,  4,  5],
       [ 6,  7,  7,  8,  9, 10]])
>>> c.shape
(2, 6)

使用数组的reshape方法,可以创建一个改变了尺寸的新数组,原数组的shape保持不变

>>> d = a.reshape((2,3))
>>> d
array([[1, 2, 3],
       [4, 5, 6]])
>>> a
array([1, 2, 3, 4, 5, 6])

数组a和d其实共享数据存储内存区域,此修改其中一个数组的元素两个数组都会变

>>> a[1] = 100
>>> d
array([[  1, 100,   3],
       [  4,   5,   6]])

其他创建数组的函数

# 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])


# linspace函数通过指定开始值、终值和元素个数来创建一维数组,可以通过endpoint关键字指定是否包括终值,缺省设置是包括终值:
>>> np.linspace(0, 1, 12)
array([ 0.        ,  0.09090909,  0.18181818,  0.27272727,  0.36363636,
0.45454545,  0.54545455,  0.63636364,  0.72727273,  0.81818182,
0.90909091,  1.        ])


# logspace函数和linspace类似,不过它创建等比数列,下面的例子产生1(10^0)到100(10^2)、有20个元素的等比数列:
>>> np.logspace(0, 2, 20)
array([   1.        ,    1.27427499,    1.62377674,    2.06913808,
2.6366509 ,    3.35981829,    4.2813324 ,    5.45559478,
6.95192796,    8.8586679 ,   11.28837892,   14.38449888,
18.32980711,   23.35721469,   29.76351442,   37.92690191,
48.32930239,   61.58482111,   78.47599704,  100.        ])
# 创建 0 的多维数组
>>> np.zeros( (3,4) )
array([[ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.]])

# 创建 1 的数组
>>> a = np.ones(3, dtype=np.int32)
array([1, 1, 1], dtype=int32)

元素的存取

>>> a = np.arange(10)

# 用整数作为下标可以获取数组中的某个元素
>>> a[3]
3

# 用范围作为下标获取数组的一个切片,包括a[3]不包括a[5]
>>> a[3:5]
array([3, 4])

# 下标还可以用来修改元素的值
>>> a[2:4] = 100,101

使用下标范围获取的新的数组,得到的是原是数组的一个视图

它与原始数组共享同一块数据空间

# 通过下标范围产生一个新的数组b,b和a共享同一块数据空间
>>> b = a[3:7]
>>> b
array([101,   4,   5,   6])

# 将b的第2个元素修改为 -8
>>> b[2] = -8
>>> b
array([101,   4, -8,   6])

# a的第5个元素也被修改为 -8
>>> a
array([  0,   1, 100, 101,   4, -8,   6,   7,   8,   9])

使用整数序列

当使用整数序列对数组元素进行存取时,将使用整数序列中的每个元素作为下标, 整数序列可以是列表或者数组。使用整数序列作为下标获得的数组不和原始数组共享数据空间

>>> x = np.arange(10,1,-1)
>>> x
array([10,  9,  8,  7,  6,  5,  4,  3,  2])

# 获取x中的下标为3, 3, 1, 8的4个元素,组成一个新的数组
>>> x[[3, 3, 1, 8]]
array([7, 7, 9, 2])

#下标可以是负数
>>> b = x[np.array([3,3,-3,8])]
>>> b[2] = 100
>>> b
array([7, 7, 100, 2])

# 由于b和x不共享数据空间,因此x中的值并没有改变
>>> x
array([10,  9,  8,  7,  6,  5,  4,  3,  2])

# 整数序列下标也可以用来修改元素的值
>>> x[[3,5,1]] = -1, -2, -3
>>> x
array([10, -3,  8, -1,  6, -2,  4,  3,  2])

使用布尔数组

使用布尔数组作为下标存取数组中的元素,获得的数组不和原始数组共享数据空间

>>> x = np.arange(5,0,-1)
>>> x
array([5, 4, 3, 2, 1])

# 布尔数组中下标为0,2的元素为True,因此获取x中下标为0,2的元素
>>> x[np.array([True, False, True, False, False])]
array([5, 3])

# 如果是布尔列表,则把True当作1, False当作0,按照整数序列方式获取x中的元素
>>> x[[True, False, True, False, False]]
array([4, 5, 4, 5, 5])

# 布尔数组的长度不够时,不够的部分都当作False
>>> x[np.array([True, False, True, True])]
array([5, 3, 2])

# 布尔数组下标也可以用来修改元素
>>> x[np.array([True, False, True, True])] = -1, -2, -3
>>> x
array([-1,  4, -2, -3,  1])

ufunc 函数运算

一种能对数组的每个元素进行操作的函数,NumPy内置的许多ufunc函数都是在C语言级别实现的, 因此它们的计算速度非常快,例如:

import time
import math
import numpy as np

x = [i * 0.001 for i in xrange(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 xrange(1000000)]
x = np.array(x)
start = time.clock()
np.sin(x,x)
print "numpy.sin:", time.clock() - start

# 速度差10倍
# math.sin: 0.0008650000000000047
# numpy.sin: 8.500000000000174e-05

reduce 函数

# 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9
>>> np.add.reduce(range(10))
45

# 沿着 axis 1 累加
>>> np.add.reduce([range(10),range(10)], axis=1)
array([45, 45])

基本计算

>>> b = np.arange(12).reshape(3,4)
>>> b
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

# 计算每一列和
>>> b.sum(axis=0)
array([12, 15, 18, 21])

# 每一行最小值
>>> b.min(axis=1)
array([0, 4, 8])

# 计算每一行累加和
>>> b.cumsum(axis=1)
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]])