目录

Numpy基础复习

模式识别课要写一些矩阵运算的代码,因为比较喜欢Python,且最近常在Ubuntu下,不打算再安Matlab,于是复习一下Numpy,主要参考官网

[TOC]

简介

Python的矩阵运算库

为什么快呢 ?因为如果用numpyic的方式写针对矩阵的整体操作(而不是用Python的循环),会被解析成C代码预先编译

数据类型

Ndarray,即n维数组,有以下属性

  • dtype 数据类型
  • shape 数组每个维度依次的长度
  • ndim 数组有几个维度

数组创建

  1. 最普通的方法是通过list创建,使用np.array([1, 2, 3, 4, 5])

  2. np.arrange(start, end, interval),生成指定间隔

  3. np.linspace(start, end, number),生成指定数量,一般用来生成坐标轴横轴

索引

切片 a[1:3, :],如果不写后面的维度,都默认是“:”,也就是等价于a[1:3],也可以写...

另外,是前闭后开区间

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
>>> a
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])
>>> a[1:3]
array([[3, 4, 5],
       [6, 7, 8]])
>>> a[1:3, :]
array([[3, 4, 5],
       [6, 7, 8]])
>>> a[1:3, ...]
array([[3, 4, 5],
       [6, 7, 8]])

“多维”索引

  • 当索引是多维的,返回的结果就是把索引数组中每个数(index)替换成被索引的数组中的那个东西(可能是元素,也可能是array),注意索引的是a的第一个维度
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
>>> palette = np.array([[0, 0, 0],         # black
                    [255, 0, 0],       # red
                    [0, 255, 0],       # green
                    [0, 0, 255],       # blue
                    [255, 255, 255]])  # white
>>> image = np.array([[0, 1, 2, 0], # each value corresponds to a color in the palette
                  [0, 3, 4, 0]])
>>> palette[image]  # the (2, 4, 3) color image
array([[[  0,   0,   0],
        [255,   0,   0],
        [  0, 255,   0],
        [  0,   0,   0]],

       [[  0,   0,   0],
        [  0,   0, 255],
        [255, 255, 255],
        [  0,   0,   0]]])

数组操作

基本操作

  1. 加减乘除

  2. 求和,注意求和可以按不同的axis,默认是按第一个(axis0

  3. ufunc:对整个矩阵调用,但可以逐元素地对数组进行操作的函数,比如np.sin,乘法等

  • 注意乘法默认是element-wise的,而矩阵乘法是@,或者np.dot

改变形状

  • a.reshape(n, m),注意返回的是view,并不会直接改变原数组,但是A.resize会改变原数组

  • a.ravel,返回扁平化的数组(一维),也是视图;但是flatten返回的不是视图,是副本

  • 切片:和list类似

  • 拼接:hstackvstack,但是待拼接维度必须维数相同。不过np.concatenate((a, b), axis=0)更快

  • 切割:hsplitvsplit

算术运算:广播

实际上,与标量的运算、比较等被扩展到整个矩阵是广播的一种特例

何时会发生广播?

  • 两个array进行运算的时候,numpy会先比较它们的维度(从最“右下角”的维度开始比),如果维度相等或者其中某个为1,就是compatible的=>可以运算。然后,如果是某个为1的情况,就会广播

广播做了什么?

  • 其实就是把那个1应用到那个n,注意并不会发生内存中实际的copy,实际是通过C语言预编译的循环实现

注意,两个数组的ndim不必相等

以下是一些可以广播的例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
A      (2d array):  5 x 4
B      (1d array):      1
Result (2d array):  5 x 4

A      (2d array):  5 x 4
B      (1d array):      4
Result (2d array):  5 x 4

A      (3d array):  15 x 3 x 5
B      (3d array):  15 x 1 x 5
Result (3d array):  15 x 3 x 5

A      (3d array):  15 x 3 x 5
B      (2d array):       3 x 5
Result (3d array):  15 x 3 x 5

A      (3d array):  15 x 3 x 5
B      (2d array):       3 x 1
Result (3d array):  15 x 3 x 5

实例:协方差计算

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
>>> x
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])
>>> demeaned = x - x.mean(axis=1).reshape(4,1)
>>> demeaned
array([[-1.,  0.,  1.],
       [-1.,  0.,  1.],
       [-1.,  0.,  1.],
       [-1.,  0.,  1.]])
>>> 1/(4-1)*np.dot(demeaned, demeaned.T)
array([[0.66666667, 0.66666667, 0.66666667, 0.66666667],
       [0.66666667, 0.66666667, 0.66666667, 0.66666667],
       [0.66666667, 0.66666667, 0.66666667, 0.66666667],
       [0.66666667, 0.66666667, 0.66666667, 0.66666667]])

view和copy

  • 这一篇文章 理解概念
  • 简单来说,视图是指针,对视图操作会改变原数据;复制是副本,不会改变原数据

https://yulizi123.github.io/static/results/np-pd/4-1-5.png

三种情况

  • 完全不复制
    • a = b,此时a is b,另外,不可变(unmutable)对象在传参的时候也是如此
  • 视图(浅拷贝)
    • 几乎所有情况,比如reshape,切片,转置等等,可以默认为都是view
  • 复制(深拷贝)
    • flatten()返回是副本
    • 显式调用a.copy()时才产生复制
1
2
3
a = np.arange(int(1e8))
b = a[:100].copy()
del a  # the memory of ``a`` can be released.

内部机制探讨

  • python的list可能不是连续存储的,但是ndarray一定是