最近看到同事用sckit-learn的统计n-gram的库省去了好多麻烦,决定从基础开始看sckit-learn,从numpy基础重新开始复习,尽量每天一篇,内容会同步到https://github.com/pangdaxing/sckit-learn-notebook中
narray基础
概念
- axes(轴)-相当于矩阵的维度,轴的总数等于矩阵的秩
- eg: 一个3d点如果表示为[1,2,1],那么他的axis数量是1,axis0的长度是3
- ndarray-是存放array的类,array可以看作是narray的别名
- ps:np.array和python标准库中的array不是一回事,array.array是只有一维的
- ndarray.ndim
- axis的数量,也就是矩阵的秩
- ndarray.shape
- 矩阵每个维度的长度,即ndim中顺序遍历每个axis返回的length
- ndarray.size
- 矩阵元素的总量,相当于ndarray.shape中所有值的乘积
- ndarray.dtype
- 矩阵中每个元素的类型,可选的有numpy.int32, numpy.int16, and numpy.float64,如果不指定,会在初始化的时候根据传入list类型自动转型
- ps:注意如果np.array([1,3])这种会认为是int类型,要进行float相关需要强制指定类型
- ndarray.itemsize
- 矩阵中每个元素所占的字节数,和ndarray.dtype.itemsize是一回事
- float64 has itemsize 8 (=64/8)
- complex32 has itemsize 4 (=32/8).
- ndarray.data
- 存放了具体的矩阵数据的数据buffer,我们用矩阵的index的操作的时候会用到
import numpy as np
a = np.arange(15).reshape(3, 5)
print("a:")
print(a)
print("a.shape:")
print(a.shape)
print("a.dim:")
print(a.ndim)
print("a.type")
print(a.dtype.name)
print("a.itemsize")
print(a.itemsize)
print("a.size")
print(a.size)
print("type(a):")
print(type(a))
数组的创建
- 通过python的tuple或者list来创建
- 通过numpy的各种函数创建
import numpy as np
## 通过python的list创建
a = np.array([2, 3, 4])
print("a:")
print(a)
print("a.type:")
print(a.dtype)
print("a.itemsize:")
print(a.itemsize)
b = np.array([(1.5, 2, 3), (4, 5, 6)])
print("b:")
print(b)
print("b.type:")
print(b.dtype)
print("a.itemsize:")
print(b.itemsize)
c = np.array([[1, 2], [3, 4]], dtype=complex)
print("c:")
print(c)
print("c.type:")
print(c.dtype)
print("c.itemsize:")
print(c.itemsize)
## 通过numpy的函数创建
print("np.zeros(3,4):")
print(np.zeros((3, 4)))
#调用函数的时候同样可以指定dtype
print("np.ones((2,3,5),dtype=np.int64")
print(np.ones((2, 3, 5), dtype=np.int64))
#返回一个没有初始化的矩阵,初始值是任意的
print("np.empty((3,4), dtype=np.int32):")
print(np.empty((3, 4), dtype=np.int32))
#可以用类似range的arange创建list,不同的是返回的是np.narray
print("np.arrage(1,3,0.3):")
print(np.arange(1, 3, 0.3))
#因为arrange采用浮点步长的时候,表示精度会带来误差,返回数组长度无法完全可控,更好的生成序列的方式是用linespace
#注意linespace的最后一个参数是区间数,而arrange是步长
print("np.linespace(0, 2*pi, 100)")
print(np.linspace(0, 2.*pi, 100))
numpy的基本算数运算
- 普通的算数运算都是返回新的空间
import numpy as np
a = np.array([20,30,40,50])
print("a:")
print(a)
b = np.arange(4)
print("b:")
print(b)
print("a-b:")
print(a-b)
print("b**2")
print(b**2)
print("10*np.sin(a)")
print(10*np.sin(a))
print("a<35")
print(a<35)
#注意在numpy中*是叉乘,*.dot是按位相乘(相当于多维的点乘法)
print("a*b")
print(a*b)
print("np.dot(a,b.transpose()")
print(np.dot(a,b.transpose()))
print("np.dot(a.transpose(),b")
print(np.dot(a.transpose(),b))
import numpy as np
a = np.ones((2,3), dtype=int)
print("a")
print(a)
b = np.random.random((2,3))
print("b")
print(b)
a *= 3
print("a=a*3:")
print(a)
b += a
print("b+=a")
print(b)
#不能被隐式转换
#a += b
- numpy还提供了一些统计类型的操作
import numpy as np
a = np.random.random((2, 3))
print("a:")
print(a)
# 不指定坐标轴默认全局统计
print("a.sum:")
print(a.sum())
print("a.min:")
print(a.min)
print("a.max:")
print(a.max)
#指定坐标轴就会沿着轴向统计
print("a.sum(axis=1)")
print(a.sum(axis=1))
print("a.sum(axis=0):")
print(a.sum(axis=0))
- numpy有很多函数是element-wise的
- 除了例子可以参考官网all, any, apply_along_axis, argmax, argmin, argsort, average, bincount, ceil, clip, conj, corrcoef, cov, cross, cumprod, cumsum, diff, dot, floor, inner, inv, lexsort, max, maximum, mean, median, min, minimum, nonzero, outer, prod, re, round, sort, std, sum, trace, transpose, var, vdot, vectorize, where的说明
import numpy as np
B = np.random.random((4,5))
print("B:")
print(B)
print("np.exp(B):")
print(np.exp(B))
print("np.sqrt(B)")
print(np.sqrt(B))
矩阵的遍历和分割
- 一维矩阵的遍历和list基本一致
- 多维矩阵的每一个轴向都可以有索引,不同维度的索引用逗号分隔的tuple表示
- 多维矩阵的可推测维度可以省略为…
- eg: x的rank=5, 则x[1,2,…] 相当于x[1,2,:,:,:], x[…,3]相当于x[:,:,:,:,3]
- 矩阵可以按照行和flat成元素进行遍历
import numpy as np
##一维矩阵的索引方法
a = np.arange(10)**3
print("a:")
print(a)
print("a[2]:")
print(a[2])
print("a[2:5]:")
print(a[2:5])
a[:6:2] = -1000
print("a[:6:2] = -1000") #相当于a[0:6:2]
print(a)
print("a[::-1]:") #相当于把a反转
print(a[::-1])
##多维矩阵的索引方法
def f(x,y):
return 10*x+y
#fromfuction相当于传入函数句柄和矩阵的索引,返回函数计算值到索引位置
b = np.fromfunction(f,(5,4),dtype=int)
print("b")
print(b)
print("b[2,3]:")
print(b[2,3])
print("b[0:5,1]")
print(b[0:5,1])
print("b[:,1]")
print(b[:,1])
print("b[1:3,2:3]:")
print(b[1:3,2:3])
print("b[-1]") #相当于b[-1,:]
print(b[-1])
print("b[:,-1]")
print(b[:,-1])
# ...的使用
c = np.empty([2,3,4],dtype=int)
print("c:")
print(c)
print("c.shape:")
print(c.shape)
print("c[1,...]")
print(c[1,...])
#只能有一个...出现在索引中
#print("c[...,2,...]:")
#print(c[...,2 ,...])
# 矩阵按照行和元素遍历
print("for row in c:")
for row in c:
print(row)
print("for elem in c.flat:")
for elem in c.flat:
print(elem)
数组的stacking
- 可以纵向或者横向stacking
- 一维数组的column_stack就相当于vstack
- 多维的stack可以用axis来指定轴向
import numpy as np
b = np.array(range(0,3,1))
print("b:")
print(b)
c = np.array(range(5,8,1))
print("c:")
print(c)
cstack_bc = np.column_stack((b,c))
print("cstack_bc:")
print(cstack_bc)
rstack_bc = + np.hstack((b,c))
print("rstack_bc:")
print(rstack_bc)
#注意这里newaxis的使用,相当于增加了一个维度
print("np.vstack((b[:,newaxis],[:,newaxis])":)
print(np.vstack((b[:,newaxis],[:,newaxis])))
npr = np.r_[1:4,0,9]
print("npr:")
print(npr)
npc = np.c_[np.array([[1,2,3]]), 0, 0, np.array([[4,5,6]])]
print("npc:")
print(npc)
broadcast
前提
- 执行的操作是element-wise的,因为只有这种按位操作才能容许矩阵size不匹配
- 当操作的是两个array时,numpy会比较它们的shape,其必须满足如下情况
- 相等
- 其中一个为1,(可以看做常数)
目标
让不同shape的array能够进行数学运算
维度举例
- 可以进行broadcase的维度
- 最后一维匹配
image (3d array): 256 x 256 x 3
cale (1d array): 3
Result (3d array): 256 x 256 x 3
- 任意一个维度为1(可扩展)
A (4d array): 8 x 1 x 6 x 1
B (3d array): 7 x 1 x 5
Result (4d array): 8 x 7 x 6 x 5
- 最后一维匹配
- boardcast不能进行
- 一维矩阵维度不匹配
A (1d array): 3
B (1d array): 4 # trailing dimensions do not match
- 第二维不匹配
A (2d array): 2 x 1
B (3d array): 8 x 4 x 3 # second from last dimensions mismatched
- 一维矩阵维度不匹配
import numpy as np
x = np.arange(4)
print("x:")
print(x)
xx = x.reshape(4, 1)
print("xx:")
print(xx)
y = np.ones(5)
print("y:")
print(y)
z = np.ones((3, 4))
print("z:")
print(z)
# 可行的broadcast操作
tmp = x + xx
print("x+xx:")
print(tmp)
tmp = x * xx
print("x*xx:")
print(tmp)
# error size
#x+y
# 可行的多维矩阵操作
print("x shape")
print(x.shape)
print("z shape")
print(z.shape)
tmp = x - z
print("x-z:")
print(tmp)
Indexing操作技巧
- 可以通过index返回值构建新的维度的数组
- 多维数组的index默认取第一维
- 可以给出多维的index,但是每个维度的index的size必须要一样
import numpy as np
a = np.arange(12) ** 2 # 0到12 的平方构成的array
print("a:")
print(a)
i = np.array([1, 1, 3, 8, 5]) # index的array
print("a[i]:")
print(a[i])
j = np.array([[3, 4], [9, 7]]) # 多维索引
print("a[j]:") # 返回的数组维度和索引数组的维度一样
print(a[j])
#设置一个调色盘
palette = np.array([[0, 0, 0], # black
[255, 0, 0], # red
[0, 255, 0], # green
[0, 0, 255], # blue
[255, 255, 255]]) # white
print("palette:")
print(palette)
#使用调色盘的颜色绘制一副简单的图像
image_idx = np.array([[0, 1, 2, 0],
[0, 3, 4, 0]])
print("image_idx:")
print(image_idx)
# 图像的size为 (2,4,3)
image = palette[image_idx]
print("image_shape:")
print(image.shape)
print("image:")
print(image)
##多维index例子
a = np.arange(12).reshape(3, 4)
print("a:")
print(a)
i = np.array([[0, 1], # 索引a的第一维
[1, 2]])
print("i:")
print(i)
j = np.array([[2, 1], # 索引a的第二维
[3, 3]])
print("j:")
print(j)
print("a[i]:")
print(a[i])
print("a[i,j]:")
print(a[i, j]) #i和j的维度要相同
print("a[i,2]:")
print(a[i, 2])
print("a[:]:")
print(a[:])
print("a[:,j]:")
print(a[:, j])
l = [i, j] #也可以合并成一个数组取值,效果同a[i,j]
print("a[l]:")
print(a[l])
#注意不能把index的tuple作为array传入,这样会认为是要做第一维的索引
#s = np.array( [i,j] )
#a[s]
- 使用index解决时间序列的问题
如何在有时序依赖的多维数据中找到最大值的index
import numpy as np
time = np.linspace(20, 145, 5) # 时间轴是一个5维的向量
print("time:")
print(time)
data = np.sin(np.arange(20)).reshape(5, 4) # 时间轴上面抽样了4个序列
print("data:")
print(data)
ind = data.argmax(axis=0) # 找到每个序列的最大值对应的index
print("ind:")
print(ind)
time_max = time[ind] # 最大值对应的时间序列的值
print("time_max:")
print(time_max)
data_max = data[ind, range(data.shape[1])] #通过index取得每个序列的最大值成为一个向量,注意range的用法
print("data_max:")
print(data_max)
print("data_max==data.max(axit=0):")
print([data_max==data.max(axis=0)])
print("np.all(data_max == data.max(axis=0)")
print(np.all(data_max == data.max(axis=0)))
- 也可以使用序列赋值
import numpy as np
a = np.arange(5)
print("a:")
print(a)
a[[1, 3, 4]] = 0
print("After a[[1,3,4]] = 0:")
print(a)
a[[0, 0, 2]] = [1, 2, 3]
print("After a[[0,0,2]]=[1,2,3]:")
print(a)
a[[0, 0, 2]] += 1
print("After a[[0,0,2]]+=1:")
print(a)
a = np.arange(12).reshape(3, 4)
b = a > 4 #b最后就是a形状的shape
print("After a > 4:")
print(b)
print("a[b]:")
print(a[b])
#bool 型的index还可以用来作为行和列的选择
a = np.arange(12).reshape(3,4)
b1 = np.array([False,True,True]) # 选择第一维度
b2 = np.array([True,False,True,False]) # 选择第二维
# 选择满足条件的行
print("a[b1,:]:")
print(a[b1,:])
print("a[b1]:")
print(a[b1])
a[:,b2] # 选择满足条件的列
print("a[:,b2]:")
print(a[b])
# 选择满足条件的行和列
print("a[b1,b2] :")
print(a[b])
- 矩阵的几何操作
import numpy as np
a = np.array([[1.0, 2.0], [3.0, 4.0]])
print("a")
print(a)
#矩阵转秩
print("transpose:")
print(a.transpose())
#矩阵求逆
print('inverse:')
print(np.linalg.inv(a))
#得到单位方阵
print("I:")
print(np.eye(2))
#矩阵叉乘
j = np.array([[0.0, -1.0], [1.0, 0.0]])
print("j:")
print(j)
print("np.dot(j,j):")
print(np.dot (j, j))# matrix product
#求方阵的迹
print("trace of a :")
print(np.trace(a))# trace
#解方程
x = np.array([[2.,3.],[4.,5.]])
y = np.array([[5.], [7.]])
print("x:")
print(x)
print("y:")
print(y)
print("solve wx=y, w:")
print(np.linalg.solve(x, y))
#求特征向量
print("eig of a")
print(np.linalg.eig(a))