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]