<<机器学习实战>>一书非常注重实践,对每个算法的实现和使用示例都提供了python实现。在阅读代码的过程中,发现对NumPy有一定的了解有助于理解代码。特别是NumPy中的数组和矩阵,对于初次使用者而言,有点难以理解。下面就总结一下NumPy基础知识。
NumPy和SciPy、Scikit-learn、pandas等库一样,是数据科学领域不可或缺的库,它提供了比python list更好的数组数据结构:更紧凑、读写速度更快、更加方便和高效。NumpPy包含两种基本的数据类型:数组和矩阵,二者在处理上稍有不同。
与标准的python不同,使用NumPy处理数组中的数据可以省去循环语句。比如:
>>> import numpy as np
>>> mm = np.array([1, 1, 1])
>>> pp = np.array([1, 2, 3])
>>> mm + pp
array([2, 3, 4])
不需要循环,就像两个平常的两个数,做加法就可以完成数组的相加。
另外还有一些操作,在NumPy中能够简单的完成,比如在每个元素上乘以常量2,可以写成:
>>> pp * 2
array([2, 4, 6])
对每个元素平方,这在K-近邻算法中用到:
>>> pp ** 2
array([1, 4, 9])
两个数组相乘,即两个数组(数组维度必须相同)的元素对应相乘:
>>> a1 = np.array([1, 2, 3])
>>> a2 = np.array([0.3, 0.2, 0.3])
>>> a1 * a2
array([0.3, 0.4, 0.9])
一个numpy数组是一个由不同数值组成的网格,网格中的数据都是同一种数据类型,可以通过非负整型数的元组来访问。
>>> my_2d_array = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=np.int64)
>>> print(my_2d_array.data)
0x7fdd8c0e4480>
>>> print(my_2d_array.shape)
(2, 4)
>>> print(my_2d_array.dtype)
int64
>>> print(my_2d_array.strides)
(32, 8)
NumPy中也支持多维数组,多维数组中的元素也可以像列表中一样访问:
>>> jj = np.array([[1, 2, 3], [1, 1, 1]])
>>> jj[0]
array([1, 2, 3])
>>> jj[0][1]
2
也可以用矩阵方式访问:
>>> jj[0, 1]
2
我们可以从列表,通过np.array()函数创建数组,然后利用方括号访问其中的元素,array()函数还可以增加一个可选的参数,指明数组元素的数据类型:
import numpy as np
a = np.array([1,2,3,4], dtype=np.int64)
print a
b = np.array([[1,2,3],[4,5,6]]) # Create a rank 2 array
print b
print b.shape # Prints "(2, 3)"
print b[0, 0], b[0, 1], b[1, 0] # Prints "1 2 4"
结果:
[1 2 3 4]
[[1 2 3]
[4 5 6]]
(2, 3)
1 2 4
Numpy还提供了很多其他创建数组的方法:
import numpy as np
a = np.zeros((2,2)) # Create an array of all zeros
print a # Prints "[[ 0. 0.]
# [ 0. 0.]]"
b = np.ones((1,2)) # Create an array of all ones
print b # Prints "[[ 1. 1.]]"
c = np.full((2,2), 7) # Create a constant array
print c # Prints "[[ 7. 7.]
# [ 7. 7.]]"
d = np.eye(2) # Create a 2x2 identity matrix
print d # Prints "[[ 1. 0.]
# [ 0. 1.]]"
e = np.random.random((2,2)) # Create an array filled with random values
print e # Might print "[[ 0.91940167 0.08143941]
# [ 0.68744134 0.87236687]]"
注意,np.eye()和np.identity()函数用于创建单位矩阵,所谓单位矩阵,就是矩阵的主对角线上的元素都为1, 而其它元素都为0,矩阵和单位矩阵相乘,积不变。
在<<机器学习实战>>中还使用到了np.tile函数,其定义如下:
numpy.tile(A, reps)
重复reps次A,形成一个数组。这里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]]])
注意多维数组,经过多维的扩充:
>>> b = np.array([[1, 2], [3, 4]])
>>> np.tile(b, 2)
array([[1, 2, 1, 2],
[3, 4, 3, 4]])
>>> np.tile(b, (2, 1))
array([[1, 2],
[3, 4],
[1, 2],
[3, 4]])
是不是结果有点出乎意料,多尝试一下就可以理解其中的扩充逻辑了。
矩阵的关键字matrix也可以简写为mat:
>>> ss = np.mat([1, 2, 3])
>>> ss
matrix([[1, 2, 3]])
>>> mm = np.matrix([1, 2, 3])
>>> mm
matrix([[1, 2, 3]])
访问矩阵中的单个元素:
>>> mm[0, 1]
2
注意矩阵的乘法含义,比如1x3的矩阵是不能与1x3的矩阵相乘的。比如ss乘以mm,会出现如下错误,必须将其中一个转置:
>>> mm * ss
Traceback (most recent call last):
File "/home/alex/anaconda3/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2910, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "" , line 1, in <module>
mm * ss
File "/home/alex/anaconda3/lib/python3.6/site-packages/numpy/matrixlib/defmatrix.py", line 309, in __mul__
return N.dot(self, asmatrix(other))
ValueError: shapes (1,3) and (1,3) not aligned: 3 (dim 1) != 1 (dim 0)
>>> mm * ss.T
matrix([[14]])
其中.T方法完成了ss的转置。
要实现数组那样的相乘,可以通过multiply函数实现:
>>> np.multiply(mm, ss)
matrix([[1, 4, 9]])
sort()方法用于排序,在原地进行,这意味着排序后的结果占用原始的存储空间,如果希望保留数据的原序,必须事先做一份拷贝。
argsort()方法得到矩阵中每个元素的排序序号:
>>> dd = np.mat([4, 5, 1])
>>> dd.argsort()
matrix([[2, 0, 1]])
>>> dd.sort()
>>> dd
matrix([[4, 5, 1]])
对于矩阵,如果想取出其中一行的元素,可以使用:操作符和行号来完成:
>>> jj = np.mat([[1, 2, 3], [8, 8, 8]])
>>> jj[1, :]
matrix([[8, 8, 8]])
也可以指定范围:
>>> jj[1, 0:2]
matrix([[8, 8]])
注意,这个范围是前闭后开,比如0:2并不包括索引值为2的元素,索引值也可以超过该维度的大小,比如:
>>> jj[1, 0:3]
matrix([[8, 8, 8]])
>>> jj[1, 0:4]
matrix([[8, 8, 8]])