前言

本文对于numpy模块具体各个函数细节不做过多说明,具体请参看文档。本文主要是就numpy的一些核心概念进行理清。

numpy模块里面最核心的概念就是 ndarray对象,请参看 这个问题 ,当时我也有疑问,numpy里面的array函数和ndarray对象有什么区别,答案就是:一般使用推荐使用 numpy.array 来创建 ndarray对象,其他还有 zeros ,empty等等其他的函数,他们都是很好的接口去创建一个 numpy.ndarray 对象,当然你也可以通过 numpy.ndarray 来创建一个ndarray对象,但这不是 numpy模块开发人员推荐的风格。

numpy ndarray对象和python的列表的区别

  1. numpy ndarray内部的item是固定内存size的,改变size将会重新创建一个ndarray。
  2. numpy ndarray内部的item是相同的data type的,因此是固定内存size的。
  3. numpy的ndarray有助于大型数据的高级数学运算或其他操作,比python的序列那些执行会更有效率。
  4. 很多科学和数学计算的python模块都是基于numpy的ndarray的,当然他们支持python的序列类型输入,但都是转变成为numpy的array之后再进行相关计算的,然后他们的输出也通常是numpy的ndarray对象。

ndarray对象

numpy模块中很核心的一个概念就是ndarray对象。ndarray对象按照numpy官方手册的绘图是这样一个数据结构:

img

ndarray有一个头header来控制所有接下来存储的数据类型(dtype),然后存储的数据则必然都是相同的数据类型,这是一个不同于列表的限定条件,这样约定将大大提高数据处理的效率。

你可以利用array函数简单将一个列表变成ndarray对象:

    >>> x = np.array([1,2,3,4,5])
    >>> x
    array([1, 2, 3, 4, 5])
    >>> type(x)
    <class 'numpy.ndarray'>
    >>> x.dtype
    dtype('int32')

在上面的例子中我们看到,每一个ndarray对象都有一个属性( dtype ),其存储的就是前面讲的ndarray对象后面一连串数据的数据类型,比如这里的数据类型是“int32”。

dtype

这个基本上讨论numpy的资料都会把这个清单列出来,这里也列出来吧。

  • bool_: True or False
  • int_: 相当于C语言的long,一般是int32或int64。整数型其内细分:
    • intc: 等于C语言的int,int32或int64
    • intp: 整数用于索引,和C语言的ssize_t相同,一般是int32或int64。
    • int8: Byte(-128 ~ 127)
    • int16: Integer(-32769 ~ 32767)
    • int32: Integer
    • int64: Integer
    • uint8: Unsigned Integer(0 ~ 255)
    • uint16: Unsigned Integer(0 ~ 65535)
    • uint32: Unsigned Integer
    • uint64: Unsigned Integer
  • float_: 具体为float64。浮点型细分为:
    • float16: 半精度浮点型
    • float32: 单精度浮点型
    • float64: 双精度浮点型
  • complex_: 就是complex128。 复数型细分为:
    • complex64: 复数型,由32位浮点型组成
    • complex128: 复数形,由64位浮点型组成

具体使用声明如下:

>>> t = np.array([1,2,3],dtype='int32')
>>> type(t)
<class 'numpy.ndarray'>
>>> t.dtype
dtype('int32')
>>>

在实际使用的时候,dtype若指定为int,则实际就是对应的 np.int_

>>> t = np.array([1,2,3],dtype='int')
>>> t.dtype
dtype('int64')

类似的 float 对应 np.float_ ; bool 对应 np.bool_ ; complex 对应 np.complex_

ndarray的dtype变换

还可以通过调用ndarray的 astype 方法来实现。注意这个方法是 非破坏型 方法,具体使用如下面例子所示:

    >>> t = np.array([1,2,3],dtype='int8')
    >>> t.astype('int32')
    array([1, 2, 3], dtype=int32)
    >>> t
    array([1, 2, 3], dtype=int8)

dtype对象的从属关系

np.issubdtype 函数来判断某个ndarray的dtype对象是不是整型的子集。

>>> t
array([1, 2, 3], dtype=int8)
>>> t.dtype
dtype('int8')
>>> np.issubdtype(t.dtype,'int')
True
>>> np.issubdtype(t.dtype,'float')
False

shape属性

此外,每一个ndarray对象都有 shape 属性,用于控制后面跟着的这些数据的维度。请看下面的例子:

>>> x
array([1, 2, 3, 4, 5, 6])
>>> x.shape
(6,)
>>> x.shape = (2,3)
>>> x
array([[1, 2, 3],
       [4, 5, 6]])

shape 属性用来控制对于后面数据维度的理解,一个数字表示一维,二个数字表示二维几行几列(也就是数学中我们常见的概念矩阵),三个数字表示三维等。这里直接修改ndarray对象的shape属性将直接影响程序对于该对象数据的理解,此外更常用的是用 reshape 方法,其并不原地修改某个ndarray对象的shape,而是返回一个被修改shape属性的新的ndarray对象。

reshape

ndarray可以调用reshape来改变本ndarray的shape属性,其并不原地修改某个ndarray对象的shape,而是返回一个被修改shape属性的新的ndarray对象。

你可以只指定一个维度,然后另外一个维度填上 -1 ,这样改维度的shape将会自动计算出来。

比如 4*5的矩阵,你reshape为 (-1,4) ,那么出来的该矩阵的row=5。

创建一个ndarray对象

从python数据结构中创建

这个就是前面接触过的 np.array 函数,用来接受一个python list 或 tuple ,从而返回一个ndarray对象。

>>> x = np.array([[1+2j,2+3j],[3+4j,4+5j]])
>>> x
array([[ 1.+2.j,  2.+3.j],
       [ 3.+4.j,  4.+5.j]])
>>> x.dtype
dtype('complex128')
>>>

生成一系列的随机数

这个经常在各个例子中看到:

np.random.randn(2,3)

array([[-0.26670745,  1.09572856, -0.38875728],
       [ 1.04339429,  0.06330302,  1.35696512]])

填充一个2行3列的随机数,randn后面的n是normal,也就是正态分布的意思。

arrange函数

arange(start,end,step) 参数类似range函数。生成一个数据递增(减)的ndarray对象:

>>> x = np.arange(5)
>>> x
array([0, 1, 2, 3, 4])
>>> x = np.arange(1,10,0.5)
>>> type(x)
<class 'numpy.ndarray'>
>>> x
array([ 1. ,  1.5,  2. ,  2.5,  3. ,  3.5,  4. ,  4.5,  5. ,  5.5,  6. ,
        6.5,  7. ,  7.5,  8. ,  8.5,  9. ,  9.5])

其是一维的,但通过reshape操作可以生成二维的ndarray对象,其可以接受 dtype 对象来控制dtype属性。

linspace函数

linspace函数可以看作上面 arange函数的补充,arange函数虽然指定了start和stop,最后的数值是不被包含的,然后具体生成了多少个item是不易知的,而linspace可以接受这样三个参数: start end number ,其中start和end一定是在ndarray中包含的,然后number给定了具体生成了多少个item。

>>> np.linspace(1,10,6)
array([  1. ,   2.8,   4.6,   6.4,   8.2,  10. ])

结束元素包不包含倒不是很重要,关键是某些情况下你需要控制具体生成了多少个item,那么就需要使用 linspace 函数。

zeros函数

zeros函数用于快速创建一个ndarray对象,其内数据都填充的是 0. ,默认dtype是 float64 。其接受的一个参数你可以简单看作就是shape属性参数,如下所示:

>>> np.zeros((10,))
array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])
>>> np.zeros(10)
array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])
>>> np.zeros((5,5))
array([[ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.]])

ones函数

ones函数类似于zeros函数,不同的是填充的数据是1。就不做例子演示了。

empty函数

empty函数和前面谈论的 zeros ones 函数类似,除了各个item都是原内存的随机数值,并不做任何修改。

>>> np.empty((2,3))
array([[  0.00000000e+000,   4.99297208e-317,   4.94026911e-317],
       [  6.94094003e-310,   1.03878549e-013,   0.00000000e+000]])
>>>

索引值

ndarray对于值的索引操作和python中列表索引值的操作非常相似,即方括号语法索引 [index] :

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

此外你还可以用这种语法:

>>> x
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
>>> x[0,0]
1
>>> x[1,1]
5
>>>

通过上面描述的索引值语法可以直接修改该ndarray对象的这个元素的值。此外numpy还提供了另外一种表示语法: [a,b] ,对于ndarray对象其和 [a][b] 的意思是一样的。但是矩阵 支持 [a][b] 这种索引语法,而只支持 [a,b] 这种表示语法,推荐对于矩阵都用带逗号的这种索引方法,表示矩阵的a行b列。

>>> A = np.matrix([[1,2,3],[4,5,6],[7,8,9]])
>>> A[0]
matrix([[1, 2, 3]])
>>> A[0][0]#并没有索引下去
matrix([[1, 2, 3]])
>>> A[0,0]
1

索引多个值或说view

同样ndarray对象也有在上面谈及的索引规则下 [start:end:step] :

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

支持索引多个值,但注意上面不是说切片,而是 view 视图。因为python的list如果你索引多个值,切片了,则等于制造了一个新的列表,如:

>>> lst = [1,2,3,4,5]
>>> lst[0:2]
[1, 2]
>>> x = lst[0:2]
>>> x[0] = 12
>>> x
[12, 2]
>>> lst
[1, 2, 3, 4, 5]

在调用 lst[0:2] 时,python程序是制造一个新的子列表,然后赋值给x,但是我们看ndarray对象不是这样的:

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

这就是ndarray对象索引多个值称之为 视图 的原因,其返回的还是指向原处的那个片段!

最后对于索引多个值的视图赋值操作,是所有元素都赋值为那个值:

>>> x[:] = 99
>>> array
array([99, 99,  3,  4,  5])

多维切片

上面的 [start:end:step] 语法只是第一个维度上的切片,numpy支持下面的语法,可以灵活地在多个维度进行切片 [d1, d2, d3] ,上面的d1是具体在第一个维度上的索引值,也就是对于每个维度都可以进一步使用 [start:end:step] 这样的进一步切片操作。

import numpy as np
arr = np.array([[[5, 10, 15], [20, 25, 30], [35, 40, 45]], [[1,2,4], [3,4,2], [1,2,4]]] )
arr
Out[5]: 
array([[[ 5, 10, 15],
        [20, 25, 30],
        [35, 40, 45]],
       [[ 1,  2,  4],
        [ 3,  4,  2],
        [ 1,  2,  4]]])
arr[0,:]
Out[6]: 
array([[ 5, 10, 15],
       [20, 25, 30],
       [35, 40, 45]])
arr[0]
Out[7]: 
array([[ 5, 10, 15],
       [20, 25, 30],
       [35, 40, 45]])
arr[:,0,:]
Out[8]: 
array([[ 5, 10, 15],
       [ 1,  2,  4]])

注意看最后一个例子,含义是第一维度所有元素,第二维度选择索引值0,第三维度所有元素。

copy方法

如果你希望达到原python的那种索引多个值的效果而不影响原ndarray对象,你可以调用ndarrary对象的 copy 方法:

array[:2].copy()

布尔值索引

布尔值索引是基于 ndarray对象进行布尔值判断操作,如 == > < 等等之类的时候,将输出一个原维度的bool值ndarray对象。然后将这个ndarray对象送入array的索引输入框中,其将返回bool值为True的那些值。

>>> array
array([0, 0, 3, 4, 5])
>>> array == 0
array([ True,  True, False, False, False], dtype=bool)
>>> array[array == 0]
array([0, 0])
>>> array[array == 0] = 99
>>> array
array([99, 99,  3,  4,  5])

布尔值索引返回的也是 视图 ,对齐操作将改变原ndarray对象。

你还可以用 &| 来形成组合逻辑,但不能使用 and 和 or 。

一大用法就是利用某个item各个属性的映射关系,利用其他属性来过滤另外某个data:

>>> data = np.random.randn(7,3)
>>> data
array([[-0.82117767,  1.02481308,  0.50908019],
       [ 0.79851282,  0.37692996, -1.0129145 ],
       [-1.30120201,  1.71270027,  0.2113716 ],
       [-1.33386207,  0.02978504, -0.58061781],
       [ 0.72466458,  1.94170572,  2.09521622],
       [-1.24241997, -1.20557331, -0.66292731],
       [-0.66145326,  0.28330579,  0.2803069 ]])
>>> names = np.array(['a','b','c','a','b','d','a'])
>>> data[names == 'a']
array([[-0.82117767,  1.02481308,  0.50908019],
       [-1.33386207,  0.02978504, -0.58061781],
       [-0.66145326,  0.28330579,  0.2803069 ]])

这里将索引的是每一行,其行对应的name是'a'的值。

基本的运算

两个ndarray对象之间进行基本的数学运算,如果两个ndarray维度是相同的,则称之为 vectorization ,矢量化操作。大致意思就是 加减乘除幂 具体操作都是 对应的元素和对应的元素进行加减乘除幂操作 :

>>> x = np.array([[4,0,5],[-1,3,2]])
>>> x
array([[ 4,  0,  5],
       [-1,  3,  2]])
>>> y = np.array([[1,1,1],[3,5,7]])
>>> y
array([[1, 1, 1],
       [3, 5, 7]])
>>> x + y
array([[5, 1, 6],
       [2, 8, 9]])
>>> x - y
array([[ 3, -1,  4],
       [-4, -2, -5]])
>>> x * 2
array([[ 8,  0, 10],
       [-2,  6,  4]])
>>> x ** 2
array([[16,  0, 25],
       [ 1,  9,  4]])

如果两个ndarray对象的维度(多维的情况不讨论了吧),如果 列维数目相同,则似乎也是可以的,但应该不推荐这么使用。而如果列维数目不同,则会抛出 ValueError

>>> z = np.array([1,2,3])
>>> x+z
array([[5, 2, 8],
       [0, 5, 5]])

我们看到这里z是重复应用到x的每一行了。

ndarray对象上的一些方法

flatten方法

flatten,拉平。flatten是ndarray对象(包括矩阵)的一个方法,可将其变为一维形式, 非破坏型 方法。

这里将flatten方法归到矩阵这里是因为多维数组必须各个维度所含元素数目相等(也就是必须要有类似矩阵的空间矩形排布感)才有意义。然后矩阵返回的是行矢量形式。

>>> x = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> x
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
>>> x.flatten()
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> x
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
>>> y = np.array([[1,2,3],[4,5,6,7]])
>>> y
array([[1, 2, 3], [4, 5, 6, 7]], dtype=object)
>>> y.flatten()
array([[1, 2, 3], [4, 5, 6, 7]], dtype=object)
>>> z
matrix([[1, 2, 3],
        [4, 5, 6]])
>>> z.flatten()
matrix([[1, 2, 3, 4, 5, 6]])

sort方法

sort方法虽然可以作用多维,但似乎对一维更显的有意义些,其是一个 破坏型 方法。

如下所示,注意看,每一行并没有变动,只在行内一维情况下排序。

>>> data
array([[ 0.68518059,  1.05271585,  1.00174264],
       [-1.44506879,  1.45532422,  1.30856608],
       [ 0.1121552 , -3.04487041, -0.03301996]])
>>> data.sort()
>>> data
array([[ 0.68518059,  1.00174264,  1.05271585],
       [-1.44506879,  1.30856608,  1.45532422],
       [-3.04487041, -0.03301996,  0.1121552 ]])

mean方法

计算给定维度下所有元素的值的的均值。

ndarray.mean(axis=None, dtype=None, out=None, keepdims=False)

在这里的难点在于理解按照维度扩展这个概念,如果是矩阵的话,竖向列是axis=0,横向行是axis=1。

numpy.mean(axis=0) 这里一般的理解是按照竖向列计算均值,更好的理解是行表示记录,列表示特征,一般第一维度表示样本维,第二维度表示特征维,这里axis=0,官方文档对于axis的解释是沿着某个维度或者轴进行计算,这里axis=0选择的实际上是样本维,然后沿着样本维每个特征计算得到一个均值。

std方法

计算给定维度下所有元素的值的标准差,具体使用类似于上面的mean方法。

一些通用函数

下面讲的一些通用函数,大多是numpy自带的,然后接受的参数一般是ndarray对象,一般也不会改变目标ndarray对象的shape(有些会稍微做一些改变),然后对各个元素进行一些函数操作。

sqrt函数

开个平方根

x = np.arange(10)

array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

np.sqrt(x)

array([0.        , 1.        , 1.41421356, 1.73205081, 2.        ,
       2.23606798, 2.44948974, 2.64575131, 2.82842712, 3.        ])

exp函数

算个指数函数 $e^{x}$

np.exp(x)

maximum函数

点对点返回最大值 【会自动进行广播操作】

x = np.random.randn(8)
y = np.random.randn(8)
np.maximum(x, y)

abs函数

x = np.random.randn(2,3)

array([[-0.11653471,  0.72362219,  0.93142213],
       [-2.03263166, -0.1941374 ,  1.23463108]])

np.abs(x)   

array([[0.11653471, 0.72362219, 0.93142213],
       [2.03263166, 0.1941374 , 1.23463108]])

unique函数

import numpy as np

list_dupes = [1, 5, 6, 2, 5, 6, 8, 3, 8, 3, 3, 7, 9]

res = np.unique(list_dupes)

>>> [1 2 3 5 6 7 8 9]

import numpy as np

list_dupes = [[1, 5, 6, 2, 5, 6, 8, 7, 9], [1, 1, 2, 2, 3, 3, 5, 6, 7]]

res = np.unique(np.array(list_dupes))

>>> [1 2 3 5 6 7 8 9]

将返回给定数据集的唯一元素集合。对于ndarray的多维对象,将会flatten还有再找出唯一值。

tile函数

np.tile(A, reps)

输入一个array,根据reps决定在那个维度重复数据:

>>> a = np.array([0, 1, 2])
>>> np.tile(a, 2)
array([0, 1, 2, 0, 1, 2])
>>> np.tile(a, (2, 2))
array([[0, 1, 2, 0, 1, 2],
       [0, 1, 2, 0, 1, 2]])
>>> np.tile(a, (2, 1, 2))
array([[[0, 1, 2, 0, 1, 2]],
       [[0, 1, 2, 0, 1, 2]]])

argsort函数

ndarray对象调用argsort函数将返回一个按照大小排序的索引值:

>>> x = np.array([3, 1, 2])
>>> np.argsort(x)
array([1, 2, 0])

上面的含义是排序后第一个值是 x[1] ,后面以此类推。

np.argpartition函数

以arg开头其返回的是索引值。

然后其默认调用的行为有点类似于快速排序中的选择一个点,左边都是比这个值小的点,右边都是比这个值大的点。在某些情况下,你可能指向要topk个结果,这样调用这个函数,你必须将排序操作进行完,有时会很高效的。

x = [9,8,7,5,4,6,1]
np.argpartition(x, 2)

array([6, 4, 3, 2, 1, 5, 0], dtype=int64)

上面这个例子的意思就是,结果输出的分区点是 2 哪里,也就是前面的2个就是整个内容中最小的两个。2对应的数字5,前面两个是 1 4,然后剩下的9 8 7 6 都是比5大的。大概就是这样子。

np.allclose

numpy.allclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)

类似于isclose,不过返回的True或者False

np.isclose

numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)

点对点的比较两个ndarray的值,rtol是相对容忍度,atol是绝对容忍度,这是一种近似的数值相近比较判断操作。

np.logical_and

点对点的逻辑and操作。

np.all

沿某个轴或者所有数值执行all操作。

ndarray对象转置

就是调用ndarray对象的 T 属性,这更接近于矩阵中的转置操作(但是对于一维ndarray并没有任何改变)。而之前提及的 data[::-1] 这么使用,只是把行翻转了一下,对于一维倒是整个array都翻转了。

>>> data = np.random.randn(4,3)
>>> data
array([[ 0.53700477, -1.30139712,  1.12184318],
       [-0.91918847,  1.52850268,  0.73218978],
       [-1.14840704, -0.0413753 ,  0.52820585],
       [ 1.84307255,  0.21356674,  0.23331023]])
>>> data.T
array([[ 0.53700477, -0.91918847, -1.14840704,  1.84307255],
       [-1.30139712,  1.52850268, -0.0413753 ,  0.21356674],
       [ 1.12184318,  0.73218978,  0.52820585,  0.23331023]])
>>> data[::-1]
array([[ 1.84307255,  0.21356674,  0.23331023],
       [-1.14840704, -0.0413753 ,  0.52820585],
       [-0.91918847,  1.52850268,  0.73218978],
       [ 0.53700477, -1.30139712,  1.12184318]])

广播(broadcasting)

广播一种操作,shape较小的张量和shape较大的张量进行点对点运算时,需要对shape较小的张量进行广播操作,使其在运算上shape兼容。

广播具体操作规则是:

  • shape较小的张量添加新的维度是的两个张量维度数相同

  • shape较小的张量在新的维度中的数据是重复的,相当于没有原维度的数据,即: y[1,j] = y[2,j] = y[3,j] =... y[j]

矩阵对象

矩阵对象是ndarray对象的子类,也就是说ndarray对象的一些属性和方法它都是可以使用的。行矢量和列矢量是属于矩阵中的特殊情况。矩阵这个概念在以后的数学运算中较为重要,然后对于一些概念,比如转置啊,点乘啊等,总之和矩阵的数学运算相关的,虽然ndarray对象也可以做,但推荐将其变成矩阵(matrix)对象之后再处理,这样容易理清概念。

matrix函数

用numpy的matrix函数可以创建一个矩阵对象:

>>> data = np.random.randn(3,3)
>>> data
array([[-0.79589206, -0.97535141,  1.05750453],
       [ 0.05051448,  0.19753523,  0.99618112],
       [ 2.09805081, -0.33623748,  0.26033154]])
>>> x = np.matrix(data)
>>> type(x)
<class 'numpy.matrixlib.defmatrix.matrix'>
>>> x
matrix([[-0.79589206, -0.97535141,  1.05750453],
        [ 0.05051448,  0.19753523,  0.99618112],
        [ 2.09805081, -0.33623748,  0.26033154]])

矩阵转置

transpose 方法,将矩阵转置过来。只返回结果, 非破坏型 方法。

>>> x = np.matrix([[1,2,3],[4,5,6],[7,8,9]])
>>> x
matrix([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]])
>>> x.transpose()
matrix([[1, 4, 7],
        [2, 5, 8],
        [3, 6, 9]])

行矢量和列矢量

行矢量和列矢量是矩阵的特殊情况,需要用matrix函数创建之。行矢量转置之后就是列矢量请注意看它的写法。

>>> x = np.matrix([1,2,3,4,5])
>>> x
matrix([[1, 2, 3, 4, 5]])
>>> x.transpose()
matrix([[1],
        [2],
        [3],
        [4],
        [5]])

矩阵的点乘

学过线性代数印像最深的可能就是矩阵那个怪异的乘法运算了。这里有了numpy模块的支持,就可以直接用 * 来执行两个矩阵的乘法,或者 np.dot 函数。

>>> A = np.matrix([[1,0,3,-1],[2,1,0,2]])
>>> B = np.matrix([[4,1,0],[-1,1,3],[2,0,1],[1,3,4]])
>>> A * B
matrix([[ 9, -2, -1],
        [ 9,  9, 11]])
>>> x = np.matrix([1,2,3])
>>> y = np.matrix([4,5,6]).transpose()
>>> x * y
matrix([[32]])
>>> y * x
matrix([[ 4,  8, 12],
        [ 5, 10, 15],
        [ 6, 12, 18]])
>>> np.dot(x,y)
matrix([[32]])
>>> np.dot(y,x)
matrix([[ 4,  8, 12],
        [ 5, 10, 15],
        [ 6, 12, 18]])
>>>