Python 机器学习基础(二)——Numpy 篇
本文是 Python 机器学习基础系列文章的第二篇——Numpy 篇。
Numpy
Numpy 是 Python 的一种开源数值计算扩展包,它可以用于存储和处理大型矩阵,比 Python 自带的嵌套列表结构要高效得多。
Numpy 数组(Numpy array)
数组(array)是 numpy 模块的一个主要类,可以表示向量(一维)、矩阵(二维)或高维数组,如声音、图像、视频等,并可以进行面向向量或矩阵的运算。
创建 array
用 array 构造函数创建一个 numpy 数组,可以是 1-D, 2-D, 3-D,…:
import numpy as np
a = np.array([0, 1, 2, 3])
print a.ndim, a.shape
b = np.array([[0, 1, 2], [3, 4, 5]])
print b.ndim, b.shape
c = np.array([[[1], [2]], [[3], [4]]])
print c.ndim, c.shape
其中 array() 函数的输入是一个 list 结构。
可以调用函数创建一些特殊的 array:
a = np.arange(10) # 序列数组
b = np.arange(1, 9, 2) # start, end (exclusive), step
c = np.linspace(0, 1, 6) # start, end, num-points
d = np.linspace(0, 1, 5, endpoint=False)
e = np.ones((3, 3)) # 用 tuple 作为输入
f = np.zeros((2, 2))
g = np.eye(3)
h = np.diag(np.array([1, 2, 3, 4]))
m = np.random.rand(4)
b = np.random.randn(4)
np.random.seed(1234) # 随机数种子
总结:创建 array 时,数据用 list 指定,维度用 tuple 指定。
基本数据类型
Numpy 中的基本数据类型包括:bool, int8~int64/int, uint8~uint64/uint, float16~float64/float, complex64, complex128/complex, S7(字符串)等。使用 a.dtype
可以查看数组的元素数据类型,在创建数组时指定 dtype
关键字可以指定数据类型。
a = np.array([1, 2, 3])
b = np.array([1, 2, 3], dtype=float)
c = np.array([1., 2., 3.])
d = np.array([1+2j, 3+4j, 5+6*1j])
e = np.array(['Bonjour', 'Hello', 'Hi'])
print a.dtype, b.dtype, c.dtype, d.dtype, e.type
np.array
创建的数组默认类型是 int64
,其他函数创建的 array 默认是 float
类型。可以使用 astype()
方法转换类型,如 b = a.astype('float')
。
索引和切片
array 的索引和切片与 Python 的序列容器(list, tuple 等)几乎完全一致,同样使用索引符 []
来索引,从 0 开始索引,冒号符 a[start:end:step]
来切片,a[::-1]
可以翻转一个一维数组。
a = np.arange(10)
print a[0], a[2], a[-1], a[::-1]
对于多维数组,可以使用逗号分隔的多个索引来取值:
a = np.diag(np.arange(3))
print a, a[1], a[1,1], a[0,2], a[:2, ::-1]
b = np.arange(10)
c = np.arange(5)
b[5:] = c[::-1]
需要注意的是,与 Python 序列容器不同,array 上的索引和切片只是原数据的一个视图(view)或引用,而非拷贝。因此对索引或切片的任何更改都会反映到原始数据上。如果需要复制,用 array 的 copy 方法。此外,可以用 np.may_share_memory
函数检查两个变量是否共享内存。
a = np.arange(10)
print a
b = a[::2]
b[0] = 12
print b, a
c = a[::2].copy()
c[0] = 12
print c, a
print np.may_share_memory(a, b) # True
print np.may_share_memory(a, c) # False
用数组索引
Numpy arrays 可以用数字或 slice 索引,但也可以使用布尔(boolean)或整数(integer)数组来索引(作为 mask)。这类索引叫 fancy indexing。
# 使用等维度 bool array 索引
np.random.seed(3)
a = np.random.random_integers(0, 20, 15) # [0,20] is the scope, 15 is num-element
b = a[a % 3 == 0]
print a, b
mask = np.array([1,0,1,0,0, 0,0,0,1,1, 1,1,0,1,1], dtype=bool)
a[mask] = 0
print a
# 使用整数 list 或 array 索引
a = np.arange(0, 100, 10)
print a[[2, 3, 2, 4, 2]]
a[[9, 7]] = -1
print a
idx = np.array([[3, 4], [9, 7]])
print a, a[idx]
Array 上的数值运算
点对点运算
Array 上所有的算术运算均为点对点(elementwise)运算。如下实例:
a = np.array([1, 2, 3, 4])
print a + 1, 2**a, 2^(3*a) - a
b = np.ones(4) + 1
print a - b, a + b
c = np.ones((3, 3))
print c * c
要想执行矩阵乘法,用 dot()
方法:
c = np.ones((3, 3))
print c * c, c.dot(c)
数组比较运算等:
a = np.array([1, 2, 3, 4])
b = np.array([4, 2, 2, 4])
print a == b, a > b # 点对点比较,输出布尔数组
print np.array_equal(a, b) # 数组比较,输出单个布尔值
a = np.array([1, 1, 0, 0])
b = np.array([1, 0, 1, 0])
print np.logical_or(a, b)
print np.logical_and(a, b)
print np.sin(a), np.log(a), np.exp(a)
a = np.triu(np.ones((3, 3)), 1)
print a, a.T, a + a.T
此外,np.allclose(a, b) 用于逐元素判断数组 a, b 的值是否足够接近(小于指定 tolerance)。
数组统计运算
包括求和、最大最小值、中值、平均值、标准差等。
x = np.array([[1, 1], [2, 2]])
print x.sum(axis=0), x[:,0].sum(), x[1,:].sum()
print x.min(), x.max(), x.argmax(), x.argmin()
print x.mean(), np.median(x), x.std()
a = np.zeros((100, 100))
print np.any(a != 0), np.all(a == a)
数值运算的传播
上面讲的点对点运算只针对等维度的数组。但是,我们同样可以在维度不等的数组之间进行数值运算,Numpy 会自动将它们转换为维度相等的数组。这个过程叫做数值运算的传播(broadcasting)。
a = np.tile(np.arange(0, 40, 10), (3, 1)).T
b = np.array([0, 1, 2])
print a + b
a = np.ones((4, 5))
a[0] = 2
array 传播的规则是,把低维数组通过复制转化为与高维数组同维度,再进行两两运算。如下图所示:
为数组增加一个维度:
a = np.arange(0, 40, 10)
print a.shape # (4,)
a = a[:, np.newaxis]
print a.shape # (4, 1)
b = np.array([0, 1, 2])
print a + b
数组变形
拉成向量(ravel 函数)与 reshape:
a = np.array([[1, 2, 3], [4, 5, 6]])
print a.ravel(), a.T, a.T.ravel()
b = a.revel().reshape((2, 3))
print b
高维数据会先将最后一个维度拉平。增加一个维度:
z = np.array([1, 2, 3])
print z
print z[:, np.newaxis], z[np.newaxis, :]
维度重新排序(transpose 函数):
a = np.arange(4*3*2).reshape(4, 3, 2)
print a.shape
b = a.transpose(1, 2, 0)
print b.shape
resize 与 reshape 不一样,resize 可以更改维度,并在缺省的地方补 0:
a = np.arange(4)
a.resize((8,))
print a # 0, 1, 2, 3, 0, 0, 0, 0
但是,当数据被其他变量名引用时是不能 resize 的:
b = a
a.resize((4,)) # 报错
数组相关函数
排序:
a = np.array([[4, 3, 5], [1, 2, 1]])
b = a.sort(axis=1) # 分别对每行排序
j = np.argsort(a)
print a, a[j]
j_max = np.argmax(a)
j_min = np.argmin(a)
print j_max, j_min
上一篇: 机器学习---Numpy入门