数据科学:从基础到实战

NumPy

Numpy 是 Python 中科学计算的核心库。它提供了一个高性能的多维数组对象,以及用于处理这些数组的工具。

版本

In [1]:
import numpy
numpy.__version__
Out[1]:
'1.15.2'

别名

遵循传统,使用np作为别名导入 NumPy :

In [2]:
import numpy as np

数组

NumPy的数组类被调用ndarray, 通常用别名array来表示。

属性

每个NumPy数组都拥有如下属性:

  • nidm:数组维度
  • shape:维度大小
  • size:数组大小
  • dtype:数据类型
  • itemsize:元素字节大小, 以bytes为单位
  • nbytes:数组字节大小, 以bytes为单位
In [3]:
# 创建一个3×3、由[0,10)均匀分布随机整数组成的数值
x = (np.random.randint(0, 10, (3, 3)))
print('x.ndim:',x.ndim)
print('x.shape:',x.shape)
print('x.size:',x.size)
print('x.dtype:',x.dtype)
print('x.itemsize:',x.itemsize)
print('x.nbytes:',x.nbytes)
x
x.ndim: 2
x.shape: (3, 3)
x.size: 9
x.dtype: int32
x.itemsize: 4
x.nbytes: 36
Out[3]:
array([[6, 9, 4],
       [2, 0, 9],
       [5, 5, 9]])

利用列表(list)生成数组

利用nd.array从 Pyhon 列表创建数值:

In [4]:
x = np.array([1,2,3,4])
x
Out[4]:
array([1, 2, 3, 4])

不同于Python列表, NumPy 要求数组必须包含同一类型的数据。如果类型不匹配, NumPy 将会向上转换(如果可行)。

In [5]:
x = np.array([1.0, 2, 3.0, 4])
x
Out[5]:
array([1., 2., 3., 4.])

如果希望明确设置数组的数据类型,可以用dtype变量:

In [6]:
x = np.array([1, 2, 3, 4], dtype=np.float32)
x
Out[6]:
array([1., 2., 3., 4.], dtype=float32)

利用list构建多维数组:

In [7]:
x = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
x
Out[7]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

利用NumPy内置方法创建数值

np.zeros():创建全 0 数值

In [8]:
# 创建一个长度为5的全0数组
x = np.zeros(5)
x
Out[8]:
array([0., 0., 0., 0., 0.])

np.ones():创建全 1 数组

In [9]:
# 创建一个3*3的q全1矩阵
x = np.ones((3,3), dtype=float)
x
Out[9]:
array([[1., 1., 1.],
       [1., 1., 1.],
       [1., 1., 1.]])

np.eye():创建一个单位矩阵

In [10]:
# 创建一个3*3的单位矩阵
x = np.eye(3)
x
Out[10]:
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

np.full(shape, fill_value):创建一个维数为shape、值为fill_value的数组

In [11]:
# 创建一个维数为3*3、值全为2.0的浮点数型数组
x = np.full((3,3), fill_value=2.0)
x
Out[11]:
array([[2., 2., 2.],
       [2., 2., 2.],
       [2., 2., 2.]])

序列数组:

  • np.arange(start, stop, step):创建一个从startstop,步长为step的序列数组。
  • np.linspace(start, stop, num=50):创建一个从startstop,元素个数为num的序列数组。
In [12]:
# 创建一个从0到10,步长为2的序列数组
x = np.arange(0, 10, 2)
x
Out[12]:
array([0, 2, 4, 6, 8])
In [13]:
# 创建一个从0到10,元素个数为5的序列数组
x = np.linspace(0, 10, 5)
x
Out[13]:
array([ 0. ,  2.5,  5. ,  7.5, 10. ])

随机分布数组:

  • np.random.random():创建一个由 0 ~ 1 均匀分布生成的随机数组成的数组
  • np.random.normal(loc=0.0, scale=1.0, size=None):创建一个由均值为loc、方差为scale的正态分布生成的随机数组成的数组
  • np.random.randint(low, high=None, size=None):创建一个由low~high均匀分布生成的随机整数组成的数值
In [14]:
# 创建一个3×3、由0~1均匀分布随机数组成的数组
x = np.random.random((3, 3))
x
Out[14]:
array([[0.15338635, 0.12742116, 0.95750969],
       [0.36620692, 0.18246738, 0.15248931],
       [0.22651305, 0.18201162, 0.39888777]])
In [15]:
# 创建一个3×3、由均值为0、方差为1的正态分布随机数组成的数组
x = np.random.normal(0, 1, (3, 3))
x
Out[15]:
array([[ 1.60544151,  1.53877914,  0.54658101],
       [ 0.29518817, -1.31794875, -0.75930664],
       [ 1.03449542, -0.53970085,  1.11143185]])
In [16]:
# 创建一个3×3、由[0,10)均匀分布随机整数组成的数值
x = (np.random.randint(0, 10, (3, 3)))
x
Out[16]:
array([[7, 4, 4],
       [1, 9, 2],
       [8, 0, 0]])

数组操作

基本运算

数组上的运算与 Python 类似,支持 Python 原生的算术运算符,标准的加、减、乘、除都可以使用。

In [17]:
x = np.arange(4)
print("x =", x)
print("x + 5 =", x + 5)
print("x * 2 =", x * 2)
print("x / 2 =", x / 2)
print("x // 2 =", x // 2)
print("-x = ", -x)
print("x ** 2 = ", x ** 2)
print("x % 2 = ", x % 2)
x = [0 1 2 3]
x + 5 = [5 6 7 8]
x * 2 = [0 2 4 6]
x / 2 = [0.  0.5 1.  1.5]
x // 2 = [0 0 1 1]
-x =  [ 0 -1 -2 -3]
x ** 2 =  [0 1 4 9]
x % 2 =  [0 1 0 1]

运算符与通用函数的对应关系如下表所示:

运算符 对应的通用函数 描述
np.add 加法运算
np.subtract 减法运算
np.negative 负数运算
* np.multipy 乘法运算
/ np.divide 除法运算
// np.floor_divide 取商除法运算
** np.power 指数运算
& np.mod 取模(余数)除法运算

索引与切片

  • 索引:获取某个元素
  • 切片:获取某些元素
In [18]:
# 创建一个3×3、由[0,10)均匀分布随机整数组成的数值
x = (np.random.randint(0, 10, (3, 3)))
x
Out[18]:
array([[6, 6, 1],
       [4, 8, 7],
       [2, 6, 5]])
In [19]:
# 索引
x[1,1]
Out[19]:
8
In [20]:
# 切片
x[1:,1:]
Out[20]:
array([[8, 7],
       [6, 5]])

数组排序

  • np.sort(a, axis=1):a表示要排序的数值,axis=0表示按列排序(axis=1表示按行排序)
In [21]:
# 创建一个4×6、由[0,10)均匀分布随机整数组成的数值
x = (np.random.randint(0, 10, (4, 6)))
x
Out[21]:
array([[7, 0, 1, 0, 9, 4],
       [5, 2, 3, 1, 7, 2],
       [1, 2, 7, 3, 5, 8],
       [0, 8, 9, 0, 4, 8]])
In [22]:
# 按列排序
np.sort(x, axis = 0)
Out[22]:
array([[0, 0, 1, 0, 4, 2],
       [1, 2, 3, 0, 5, 4],
       [5, 2, 7, 1, 7, 8],
       [7, 8, 9, 3, 9, 8]])
In [23]:
# 按列排序
np.sort(x, axis = 1)
Out[23]:
array([[0, 0, 1, 4, 7, 9],
       [1, 2, 2, 3, 5, 7],
       [1, 2, 3, 5, 7, 8],
       [0, 0, 4, 8, 8, 9]])

数组变形

  • reshape()方法
In [24]:
# 创建一个3×3、由[0,10)均匀分布随机整数组成的数值
x = (np.random.randint(0, 10, (3, 3)))
x
Out[24]:
array([[0, 0, 9],
       [6, 4, 5],
       [5, 6, 1]])
In [25]:
print('通过变形获得的行向量:\n', x.reshape((1, 9)))
print('通过变形获得的列向量:\n', x.reshape((9, 1)))
通过变形获得的行向量:
 [[0 0 9 6 4 5 5 6 1]]
通过变形获得的列向量:
 [[0]
 [0]
 [9]
 [6]
 [4]
 [5]
 [5]
 [6]
 [1]]

数组转置

In [26]:
x = (np.random.randint(0, 10, (2, 3)))
x
Out[26]:
array([[6, 5, 1],
       [1, 2, 4]])
In [27]:
x.T
Out[27]:
array([[6, 1],
       [5, 2],
       [1, 4]])

拼接与拆分

拼接方法

  • np.concatenate((a1, a2, ...), axis=0):按垂直(水平axis=1)拼接数组元组(a1, a2, ...)或数值列表[a1, a2, ...]
  • np.vstack((a1, a2, ...)):按垂直方向拼接数组元组(a1, a2, ...)或数值列表[a1, a2, ...]
  • np.hstack((a1, a2, ...)):按水平方向拼接数组元组(a1, a2, ...)或数值列表[a1, a2, ...]
In [28]:
x = np.array([[1,2,3,4],
                  [1,2,3,4]])
x
Out[28]:
array([[1, 2, 3, 4],
       [1, 2, 3, 4]])
In [29]:
# 按垂直方向拼接数组x和x
print('通过np.concatenate()方法拼接:\n',np.concatenate((x,x)))
print('通过np.vstack()方法拼接:\n',np.vstack((x,x)))
通过np.concatenate()方法拼接:
 [[1 2 3 4]
 [1 2 3 4]
 [1 2 3 4]
 [1 2 3 4]]
通过np.vstack()方法拼接:
 [[1 2 3 4]
 [1 2 3 4]
 [1 2 3 4]
 [1 2 3 4]]
In [30]:
# 按水平方向拼接数值x和x
print('通过np.concatenate()方法拼接:\n',np.concatenate((x,x),axis=1))
print('通过np.vstack()方法拼接:\n',np.hstack((x,x)))
通过np.concatenate()方法拼接:
 [[1 2 3 4 1 2 3 4]
 [1 2 3 4 1 2 3 4]]
通过np.vstack()方法拼接:
 [[1 2 3 4 1 2 3 4]
 [1 2 3 4 1 2 3 4]]

拆分方法

  • np.split(ary, indices_or_sections, axis=0)ary为要拆分的数值,indices_or_sections为拆分节点序列,axis=0表示按竖直方向拆分(axis=1表示按竖直方向拆分)
  • np.hsplit():按水平方向拆分
  • np.vsplit():按竖直方向拆分

一维数组:

In [31]:
x = np.arange(9)
print(x)
print(np.split(x,3))
print(np.split(x,[2,5,7]))
[0 1 2 3 4 5 6 7 8]
[array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]
[array([0, 1]), array([2, 3, 4]), array([5, 6]), array([7, 8])]

二维数组:

In [32]:
# 按竖直方向拆分
y = (np.random.randint(0, 10, (3, 3)))
print('通过np.split()方法拆分:\n',np.split(y, 3))
print('通过np.hsplit()方法拆分:\n',np.vsplit(y, 3))
通过np.split()方法拆分:
 [array([[8, 7, 4]]), array([[6, 7, 2]]), array([[9, 8, 0]])]
通过np.hsplit()方法拆分:
 [array([[8, 7, 4]]), array([[6, 7, 2]]), array([[9, 8, 0]])]
In [33]:
# 按水平方向拆分
print('通过np.split()方法拆分:\n',np.split(y, 3, axis=1))
print('通过np.hsplit()方法拆分:\n',np.hsplit(y, 3))
通过np.split()方法拆分:
 [array([[8],
       [6],
       [9]]), array([[7],
       [7],
       [8]]), array([[4],
       [2],
       [0]])]
通过np.hsplit()方法拆分:
 [array([[8],
       [6],
       [9]]), array([[7],
       [7],
       [8]]), array([[4],
       [2],
       [0]])]

通用函数

NumPy 提供熟悉的数学函数,例如sincosexp等,在 NumPy 中,这些被称为“通用函数”(ufunc)。

In [34]:
x = np.arange(3)
x
Out[34]:
array([0, 1, 2])
In [35]:
np.exp(x)
Out[35]:
array([1.        , 2.71828183, 7.3890561 ])
In [36]:
np.sqrt(x)
Out[36]:
array([0.        , 1.        , 1.41421356])
In [37]:
np.add(x,x)
Out[37]:
array([0, 2, 4])

NumPy提供了大量的通用函数,具体情况可上官网查看,这里就不一一介绍了。

广播

广播是一种强有力的机制,通过它 NumPy 可以使不同大小的矩阵在一起进行数学计算。

In [38]:
a = np.array([[ 0.0, 0.0, 0.0],
               [10.0,10.0,10.0],
               [20.0,20.0,20.0],
               [30.0,30.0,30.0]])
b = np.array([1.0,2.0,3.0])
a + b
Out[38]:
array([[ 1.,  2.,  3.],
       [11., 12., 13.],
       [21., 22., 23.],
       [31., 32., 33.]])

想深入了解广播,可以读一读文档和这个解释

以上内容参考了 NumPy 官方教程和《Python科学计算手册》一书

个人水平有限,文章中存在的任何问题请大家在评论中或私信我指正,我会认真修改或给出回馈。