Python-Numpy中的矩阵和数组运算

内容

〇 、前言

一 、数组(Array)与矩阵(Matrix)

*谈一维数据(一行或一列数据)

Example1

Example2

numpy.matrix()

2.各种操作

0、数组或矩阵的每个元素都乘(加减除···)某个数

1、矩阵的点积(加减)运算

2、数组间对应位元素的运算

①、两数组的shape完全一样

②、不同shape的就broadcast

3. 后记

〇 、前言

最近这段时间开始了我的机器学习的python踩坑之旅,毕竟之前主要在matlab上coding的,而matlab对矩阵的处理那是非常非常方便的,导致我被惯坏了,在转到用python写框架时还保持着matlab时的思维,全线飘红,不过主要是自己太菜,对numpy的一些机制不了解,经过不断search后,写下这篇笔记。

一 、数组(Array)与矩阵(Matrix)

首先我们得弄清楚numpy中数组与矩阵的区别:Matrix必须是2维的,但是Array可以是多维的,一维二维到N维,Matrix是Array的一个小的分支,包含于Array。所以Matrix 拥有Array的所有特性。对于刚接触机器学习的我们很容易会被迷惑住双眼,因为我们平时接触到的数据维度基本停留在二维,又由于Matrix 拥有Array的所有特性,两者也都都可以进行加减乘除的运算,当我们在处理其他维度的数据时就很容易混用,导致出错。

*谈一维数据(一行或一列数据)

import numpy as np

coding经常出错的地方是对一维数据的处理,我将给出几个例子,大家很容易就能理解。

Example1

# Input:
a = np.ones((1, 5)) #要有括号括起来,这就是它的shape
print(a)
print(a.shape)

b = np.zeros(5)
print(b)
print(b.shape)
# Output:
a:
[[1. 1. 1. 1. 1.]]
a.shape:
(1, 5)
b:
[0. 0. 0. 0. 0.]
b.shape:
(5,)

可以看到,我们都只是想构造一个可以存储5个数据的容器,但两者的shape是不一样的。此时a是二维数组(也可以说他就是个Matrix,这种情况下Array和Matrix确实是没区别的),a是一个有1个数据“宽度”,有5个数据“长度”的“面”;而此时b是一维数组,通过shape也可以看出,b是一条只有5个数据的“长度”的“线”,没有“宽度”,因此它不是Matrix,是不能对其进行转置求逆等操作的。

特别提示:一维数组不是向量,一维数组不能转置! ! !

虽然在我们看来存的同样都是一个维度的数据,但两者的机制是不一样的,shape也不一样,numpy运算对容器之间的shape会有严格的要求,所以需要特别注意维度问题。

Example2

# Input:
d = np.ones((3, 5))
k = d[:, 3]   #取d的第4列
print(k)
print(k.shape)
# Output :
k:
[1. 1. 1.]
k.shape:
(3,)

这个例子是用冒号取d的第4列数据k,此时k的shape是(3,),k是一维数组,不是列向量,拿去做其他运算的时候shape会有很大问题。

不仅是这个例子,还有很多函数返回一维数组,也会造成很多纬度问题。您应该事先知道要使用的函数返回什么类型的数据。

numpy.matrix()

如果想让k是一个列向量,此时就得用numpy.matrix()来将数组转化为Matrix。

# Input :
d = np.ones((3, 5))
k_matrix = np.matrix(d[:, 3])
print(k_matrix)
print(k_matrix.shape)
# Output :
k_matrix:
[[1. 1. 1.]]
k_matrix.shape:
(1, 3)

可以看到转成Matrix后shape并不是我们想要的列向量的(3,1),虽然我们脑子里认为取的是一列,但电脑不这么认为,因为d[:, 3]返回的就是“一行数据”(一维数组),转成Matrix后是行向量,所以需要把它加一个转置变成我们想要的列向量。这一点也是很多freshman很容易忽略的。

# Input :
k_matrix = np.matrix(d[:, 3]).T

# 也可以用transpose
# np.transpose(k_matrix)
# Output :
k_matrix:
[[1.]
 [1.]
 [1.]]
k_matrix.shape:
(3, 1)

2.各种操作

下面我将从运算目的和数据维度将各种常用的运算分好类别,大家看菜吃饭。这里都是拿一维和二维的数据讲解,把这个弄懂,更高维度的也是很容易理解的。其他比较少用运算的大家要善用Google,看看文档。

0、数组或矩阵的每个元素都乘(加减除···)某个数

这里numpy会将这单个数广播(broadcast)成和前面那个数组或矩阵一样shape的数组或矩阵,再进行元素级别的运算

# Input :
e = np.ones((3, 5)) * 0.5
print(e)
# Output :
e:
[[0.5 0.5 0.5 0.5 0.5]
 [0.5 0.5 0.5 0.5 0.5]
 [0.5 0.5 0.5 0.5 0.5]]

1、矩阵的点积(加减)运算

维度要求就是按照线性代数的维度要求,点积要求“前列等于后行”,加减要求整个shape都一样。

# Input :
e = np.matrix(np.ones((3, 5)) + 0.5)
f = np.matrix(np.zeros((5, 2)) + 0.5)
print(e * f)
# Output :
e * f:
[[3.75 3.75]
 [3.75 3.75]
 [3.75 3.75]]

这里要注意如果直接用 “*” 来点积的话,e和f的类型必须至少有一个是Matrix类型,要用numpy.matrix(),或者用np.dot()。

g = np.ones((3, 5)) + 0.5
h = np.zeros((5, 2)) + 0.5
print(np.dot(g, h))

如果g(ndarray)*h(ndarray)的话numpy会认为你是在做数组对应位元素间的运算,会自动broadcast,但维度不符合broadcast规则就报错,就算维度刚刚好没问题,但做的也不是我们想要的点积运算。

容易出错的总结:

如果都是ndarray类型:“+” “-” “*” “/” “**” 等就是对应元素的运算。想要点积就np.dot()。

如果至少有一个是matrix类型:“+” “-” “*” “**”就是矩阵运算。

2、数组间对应位元素的运算

①、两数组的shape完全一样

# Input :
i = np.ones((5, 3)) + 0.5
j = np.zeros((5, 3)) + 0.5
print(i*j)
# Output :
i * j:
[[0.75 0.75 0.75]
 [0.75 0.75 0.75]
 [0.75 0.75 0.75]
 [0.75 0.75 0.75]
 [0.75 0.75 0.75]]

②、不同shape的就broadcast

我个人理解广播的操作就是通过对某个数组沿其长度为1的维度“拉伸复制”(有点像Excel拉单元格的右下角),使其shape和另一个数组原本或广播后的shape一样,那么就可以广播。

所以简单来讲要满足broadcast规则的必要条件(至少得满足)是:两数组中至少有一个是一维数组或shape是(1,n)或(n,1)的二维数组,否则肯定会错。

对于广播机制,用文字说的话感觉会越说越晕,毕竟情况还是很多的,建议大家还是走传送门看大佬讲,动手做几次就能feel到它是怎么操作的,其实还是很好理解的。

3. 后记

python处理矩阵和数组还是比matlab麻烦不少,但主要会出错搞乱的地方就是一维数组和(二、1)这里,会因为shape不匹配造成很多运算维度出错问题,只要自己清楚这个容器是什么类型,shape是多少,配合类型转换和转置等操作,就能解决问题了。

如果我说的有错误,希望大佬指出错误。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
扎眼的阳光的头像扎眼的阳光普通用户
上一篇 2022年3月16日 下午3:27
下一篇 2022年3月16日 下午3:44

相关推荐