NumPy-矩阵部分

NumPy-矩阵部分

NumPy 简介

numpy可用来存储和处理大型矩阵,比Python自身的嵌套列表(nested list structure)结构要高效的多。

安装NumPy

pip install numpy

导入 NumPy

在导入 NumPy 库时,大多数情况下你会看到的一个约定,是将其命名为 np

import numpy as np

数据类型和形状

NumPy 中处理数字的最常见方式是通过 ndarray 对象。它们与 Python 列表相似,但是可以有任意数量的维度。而且,ndarray 支持快速的数学运算。

NumPy里面的数据类型比Python的多。python只有intfloat。在NumPy中除了 Python 的 int,你可以使用 uint8int8uint16int16 等类型。ndarray中的每一项必须具有相同的类型,和c类似。

创建包含一个标量的 NumPy 数组:

s=np.array(5)

可以通过检查数组的 shape 属性来查看数组的形状。

s.shape

它会打印出结果,即一对空括号 ()。这表示它的维度为零。

即使标量位于数组中,你仍然可以像正常标量一样使用它们。你可以键入:

x = s + 3

x 现在将等于 8。如果你检查 x 的类型,会发现它可能是 numpy.int64,因为它在使用 NumPy 类型,而不是 Python 类型。

创建一个向量:

v=np.array([1,2,3])

检查向量的 shape 属性,它将返回表示向量的一维长度的单个数字。在上面的示例中,v.shape 会返回 (3,) 。

现在有了数字,你可以看到 shape 是一个元组,其中包含每个 ndarray 的维度的大小。对于标量,它只是一个空的元组,但是向量有一个维度,所以元组包含一个数字和一个逗号。(Python 不能将 (3) 理解为具有一个项的元组,所以它需要逗号。

你可以使用索引访问向量中的元素,如下所示:

x = v[1]

现在 x 等于 2

NumPy 还支持高级索引技术。例如,要访问第二个元素及其后面的项,你可以这样写:

v[1:]

然后它会返回数组 [2, 3]

创建矩阵

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

创建了一个包含数字 1 到 9 的 3x3 矩阵。

它的 shape 属性将返回元组 (3, 3)

所以要在上面的矩阵中找到数字 6,你可以访问 m[1][2]

张量

张量可以有更多的维度。

如,要创建一个 3x3x2x1 的张量

t = np.array([[[[1],[2]],[[3],[4]],[[5],[6]]],[[[7],[8]],[[9],[10]],[[11],[12]]],[[[13],[14]],[[15],[16]],[[17],[17]]]])

t[2][1][1][0] 将返回 16

更改形状

更改数据的形状,而不实际更改其内容。例如,你可能有一个一维的向量,但是需要一个二维的矩阵。实现它的方式有两种。

假设你有以下向量:

v = np.array([1,2,3,4])

调用 v.shape 会返回 (4,)。但如果你想要一个 1x4 矩阵呢?你可以使用 reshape 函数,就像这样:

x = v.reshape(1,4)

调用 x.shape 会返回 (1,4)。如果你想要一个 4x1 矩阵,可以这样做:

x = v.reshape(4,1)

reshape 函数不只是添加大小为 1 的维度。

关于更改 NumPy 数组的形状还有一点:如果你看到经验丰富的 NumPy 使用者的代码,经常会看到他们使用一种特殊的切片语法,而不是调用 reshape。使用该语法,前面的两个示例会是这样的:

x = v[None, :]

或者

x = v[:, None]

NumPy里面的矩阵运算

将矩阵元素都加一个数

values = [1,2,3,4,5]
values = np.array(values) + 5
# 现在 values 是包含 [6,7,8,9,10] 的一个 ndarray

NumPy 实际上有用于加法、乘法等运算的函数。

以下两行是等价的:

x = np.multiply(some_array, 5)
x = some_array * 5

矩阵归零:

m *= 0

# 现在 m 中的每个元素都是 0,无论它有多少维度

矩阵的平方值:

x = m * m(或者如果你要将值赋值回 m,则是 m *= m
示例:

a = np.array([[1,3],[5,7]])
a
# 显示以下结果:
# array([[1, 3],
#        [5, 7]])

b = np.array([[2,4],[6,8]])
b
# 显示以下结果:
# array([[2, 4],
#        [6, 8]])

a + b
# 显示以下结果:
#      array([[ 3,  7],
#             [11, 15]])

不兼容的形状,会收到一个错误:

a = np.array([[1,3],[5,7]])
a
# 显示以下结果:
# array([[1, 3],
#        [5, 7]])
c = np.array([[2,3,6],[4,5,9],[1,8,7]])
c
# 显示以下结果:
# array([[2, 3, 6],
#        [4, 5, 9],
#        [1, 8, 7]])

a.shape
# 显示以下结果:
#  (2, 2)

c.shape
# 显示以下结果:
#  (3, 3)

a + c
# 显示以下结果:
# ValueError: operands could not be broadcast together with shapes (2,2) (3,3)

要获得矩阵乘积,可以使用 NumPy 的 matmul 函数。

如果你有兼容的形状,那就像这样简单:

a = np.array([[1,2,3,4],[5,6,7,8]])
a
# 显示以下结果:
# array([[1, 2, 3, 4],
#        [5, 6, 7, 8]])
a.shape
# 显示以下结果:
# (2, 4)

b = np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]])
b
# 显示以下结果:
# array([[ 1,  2,  3],
#        [ 4,  5,  6],
#        [ 7,  8,  9],
#        [10, 11, 12]])
b.shape
# 显示以下结果:
# (4, 3)

c = np.matmul(a, b)
c
# 显示以下结果:
# array([[ 70,  80,  90],
#        [158, 184, 210]])
c.shape
# 显示以下结果:
# (2, 3)

如果你的矩阵具有不兼容的形状,则会出现以下错误:

np.matmul(b, a)
# 显示以下错误:
# ValueError: shapes (4,3) and (2,4) not aligned: 3 (dim 1) != 2 (dim 0)

tf.multiply是点乘,tf.matmul是矩阵乘法.

转置

NumPy 中获得矩阵的转置,可以直接访问其 T 属性,还有一个 transpose() 函数也可以返回同样的结果。

例如:

m = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
m
# 显示以下结果:
# array([[ 1,  2,  3,  4],
#        [ 5,  6,  7,  8],
#        [ 9, 10, 11, 12]])

m.T
# 显示以下结果:
# array([[ 1,  5,  9],
#        [ 2,  6, 10],
#        [ 3,  7, 11],
#        [ 4,  8, 12]])

NumPy 在进行转置时不会实际移动内存中的任何数据 - 只是改变对原始矩阵的索引方式 - 所以是非常高效的。

但是,这也意味着你要特别注意修改对象的方式,因为它们共享相同的数据。例如,对于上面同一个矩阵 m,我们来创建一个新的变量 m_t 来存储 m 的转置。然后看看如果我们修改 m_t 中的值,会发生什么:

m_t = m.T
m_t[3][1] = 200
m_t
# 显示以下结果:
# array([[ 1,   5, 9],
#        [ 2,   6, 10],
#        [ 3,   7, 11],
#        [ 4, 200, 12]])

m
# 显示以下结果:
# array([[ 1,  2,  3,   4],
#        [ 5,  6,  7, 200],
#        [ 9, 10, 11,  12]])

注意它是如何同时修改转置和原始矩阵的!这是因为它们共享相同的数据副本。所以记住,将转置视为矩阵的不同视图,而不是完全不同的矩阵。

posted @ 2018-01-30 16:57  philhuan  阅读(766)  评论(0编辑  收藏  举报