numpy学习笔记2
之前一直有个疑惑,为什么要使用numpy?更本质的说,为什么要使用矩阵?矩阵是什么?意味着什么?关于关于矩阵的问题,这里推荐一个系列视频,讲的非常非常好。至于为什么用numpy,从程序的角度来讲,我认为最大的好处就是减少代码量以及提高效率(恩,写此文的时候觉得这是一句废话,但确实困扰了我一阵……)
比如,在学习KNN算法时需要计算欧式距离,公式如下:
$$d=\sqrt{ {({A_0}-{B_0})^2}+{({A_1}-{B_1})^2}+{({A_2}-{B_2})^2}+{({A_3}-{B_3})^2}+… }$$
这里用2维为例,公式变成:
$$d=\sqrt{ {({A_0}-{B_0})^2}+{({A_1}-{B_1})^2} }$$
这货貌似是已知直角三角形直角边求斜边长啊?
假设有2个已知点(0,0)和(2,2),求点(1,1)到这2个点的距离。
如果不使用矩阵,计算欧式距离的代码为:
a = [(0,0),(2,2)]
b = (1,1)
result = []
for o in a:
tmp = 0
for i in range(len(b)):
tmp += (b[i] - o[i]) ** 2
result.append(tmp ** 0.5)
而使用矩阵呢?代码则变成:
from numpy import *
a = array([[0,0],[2,2]])
b = [1,1]
result = (((tile(b,(a.shape[0],1)) - a) ** 2).sum(axis=1)) ** 0.5
使用矩阵1行代码解决了一个原来复杂度为 \(O(n^2)\) 的算法,这对大量数据时候是非常有用的。
这里,继续上一篇文章来看numpy的常用函数。
引入numpy包:
import numpy as np
生成随机数组
arr = np.random.rand(4,4)
print(arr)
print(type(arr))
[[ 0.2315333 0.84604056 0.64167686 0.44570765]
[ 0.36795508 0.60307855 0.79436951 0.563711 ]
[ 0.58187498 0.79001508 0.80846423 0.30307415]
[ 0.11054066 0.0864696 0.28637939 0.8327235 ]]
<class 'numpy.ndarray'>
将数组转换为矩阵
arr_mat = np.mat(arr)
print(arr_mat)
print(type(arr_mat))
[[ 0.2315333 0.84604056 0.64167686 0.44570765]
[ 0.36795508 0.60307855 0.79436951 0.563711 ]
[ 0.58187498 0.79001508 0.80846423 0.30307415]
[ 0.11054066 0.0864696 0.28637939 0.8327235 ]]
<class 'numpy.matrixlib.defmatrix.matrix'>
逆矩阵
arr_mat_i = arr_mat.I
print(arr_mat_i)
[[-1.5270842 -4.08677263 4.54386593 1.93012868]
[ 2.5195223 -3.03511915 0.84074721 0.4000739 ]
[-1.5393072 6.41241092 -2.98039392 -2.4322422 ]
[ 0.47046671 -1.34760492 0.33449566 1.73958357]]
矩阵乘法
arr_mat * arr_mat_i
matrix([[ 1.00000000e+00, -5.65692771e-17, 5.05172371e-17,
-1.18514985e-16],
[ -1.14978095e-16, 1.00000000e+00, 1.08559905e-17,
-1.74632936e-16],
[ 1.15042834e-16, 1.03538359e-16, 1.00000000e+00,
-2.49909228e-16],
[ 1.10902216e-16, -6.74225888e-17, 4.88343657e-17,
1.00000000e+00]])
矩阵和逆矩阵相乘结果应该为单位矩阵(对角线为1,其他为0),但这里产生了一些极小的误差。
eye函数
eye()函数可以用来生成单位矩阵
np.eye(4)
array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]])
shape属性
返回矩阵的形状
arr.shape
(4, 4)
第一个是行,第二个是列
tile函数
将第一个参数重复第二个参数次,第二个参数可以为整形或者元祖。
range_arr = np.arange(0,40,10) # 可以参考range函数,从0开始,到40停止,步长10
print(range_arr)
[ 0 10 20 30]
np.tile(range_arr,3) # 将range_arr列重复3次,等同于np.tile(range_arr,(1,3))
array([ 0, 10, 20, 30, 0, 10, 20, 30, 0, 10, 20, 30])
np.tile(range_arr,(3,1)) # 将range_arr行重复3次,列1次
array([[ 0, 10, 20, 30],
[ 0, 10, 20, 30],
[ 0, 10, 20, 30]])
np.tile(range_arr,(0,3)) # 将range_arr压缩为0行12列,没什么意义
array([], shape=(0, 12), dtype=int64)
np.tile(range_arr,(3,0)) # 将range_arr压缩为3行0列,没什么意义
array([], shape=(3, 0), dtype=int64)
np.tile(range_arr,(2,3)) # 将range_arr行重复2次,列重复3次
array([[ 0, 10, 20, 30, 0, 10, 20, 30, 0, 10, 20, 30],
[ 0, 10, 20, 30, 0, 10, 20, 30, 0, 10, 20, 30]])
argsort函数
将数组从小到大排序,并返回排序后原来元素的索引
print(arr)
print(arr.argsort())
[[ 0.2315333 0.84604056 0.64167686 0.44570765]
[ 0.36795508 0.60307855 0.79436951 0.563711 ]
[ 0.58187498 0.79001508 0.80846423 0.30307415]
[ 0.11054066 0.0864696 0.28637939 0.8327235 ]]
[[0 3 2 1]
[0 3 1 2]
[3 0 1 2]
[1 0 2 3]]
以第一行为例,0.23最小,然后是0.44,0.64,0.84,所以结果是他们的索引[0,3,2,1]