目录
- 数组简介和数组的构造(ndarray)
- 数组取值与赋值
- 数学运算
- Broadcasting(广播)
- 逻辑运算
- 数组高级操作
- 文件输入输出
- 随堂练习:用numpy写一个softmax
数组简介和数组的构造(ndarray)
ndarray = n dimensional array
import numpy as np
b = np.array([[1,2,3], [2,3,4]])
print(b)
[[1 2 3]
[2 3 4]]
print(b.shape)
(2, 3)
a = np.zeros((2,3))
print(a)
[[ 0. 0. 0.]
[ 0. 0. 0.]]
b = np.ones((1,2))
print(b)
[[ 1. 1.]]
c = np.full((2,2), 8)
print(c)
[[8 8]
[8 8]]
d = np.eye(3)
print(d)
[[ 1. 0. 0.]
[ 0. 1. 0.]
[ 0. 0. 1.]]
g = np.arange(15)
print(g)
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
arr = np.array([1,2,3])
print(arr.dtype)
int32
arr = np.array([1,2,3], dtype=np.float64)
print(arr.dtype)
float64
int_arr = np.array([1,2,3,4,5])
print(int_arr, int_arr.dtype)
[1 2 3 4 5] int32
float_arr = int_arr.astype(np.float64)
print(float_arr.dtype, float_arr)
float64 [ 1. 2. 3. 4. 5.]
int_arr = np.arange(10)
float_arr = np.array([2.3,4.6,9.8])
print(float_arr.dtype, int_arr.dtype)
float64 int32
int_arr.astype(dtype=float_arr.dtype)
array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
数组取值与赋值
import numpy as np
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
b = a[1, :2] # [行, 列]
print(b)
[5 6]
b = a[0:2,2:4]
print(b)
[[3 4]
[7 8]]
b[0,0] = 111111
print(b)
[[111111 4]
[ 7 8]]
print(a) # a也会变!! 因为numpy是引用
[[ 1 2 111111 4]
[ 5 6 7 8]
[ 9 10 11 12]]
# 最好切片的时候 b = a[0:2,2:4].copy()
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
row_r1 = a[0, ]
print(row_r1, row_r1.shape)
[1 2 3 4] (4,)
row_r2 = a[0:1] # X到X会多内嵌一维
print(row_r2, row_r2.shape)
[[1 2 3 4]] (1, 4)
row_r3 = a[[0], :]
print(row_r3, row_r3.shape)
[[1 2 3 4]] (1, 4)
col_r1 = a[:, 1]
print(col_r1, col_r1.shape)
[ 2 6 10] (3,)
col_r2 = a[:, 1:2]
print(col_r2, col_r2.shape)
[[ 2]
[ 6]
[10]] (3, 1)
a = np.array([[1,2], [3, 4], [5, 6]])
b = a[[0,1,2], [0,1,0]] # 取出[0, 0], [1, 1], [2, 0]
print(a)
[[1 2]
[3 4]
[5 6]]
print(b, b.shape)
[1 4 5] (3,)
print(np.array([a[0, 0], a[1, 1], a[2, 0]]))# 先取出这三个数,构成list,再变为ndarray
[1 4 5]
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
print(a)
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
b = np.array([0, 2, 0, 1])
print(a[np.arange(4), b]) # 行0-3,列[0, 2, 0, 1],坐标[0, 0], [1, 2], [2, 0], [3, 1]
[ 1, 6, 7, 11]
a[np.arange(4), b] += 10 # 元素操作
print(a)
[[11 2 3]
[ 4 5 16]
[17 8 9]
[10 21 12]]
# 用条件判定取值
a = np.array([[1,2], [3, 4], [5, 6]])
print(a)
[[1 2]
[3 4]
[5 6]]
bool_index = (a > 2)
print(bool_index)
[[False False]
[ True True]
[ True True]]
# 用布尔型数组作为下标就可以取出符合条件的元素了
print(a[bool_index])
[3 4 5 6]
# 其实一句话就行
print(a[a>2])
[3 4 5 6]
数学运算
import numpy as np
x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)
print(x) print(y)
[[ 1. 2.] [[ 5. 6.]
[ 3. 4.]] [ 7. 8.]]
# 加法
(1) x+y
(2) np.add(x,y)
array([[ 6., 8.],
[ 10., 12.]])
# 减法
(1) x-y
(2) np.subtract(x,y)
array([[-4., -4.],
[-4., -4.]])
# 乘法
(1) x*y
(2) np.multiply(x,y)
array([[ 5., 12.],
[ 21., 32.]])
# 除法
(1) x/y
(2) np.divide(x, y)
array([[ 0.2 , 0.33333333],
[ 0.42857143, 0.5 ]])
# 平方根
np.sqrt(x)
array([[ 1. , 1.41421356],
[ 1.73205081, 2. ]])
# 向量内积
v = np.array([9,10])
w = np.array([10,11])
(1) v.dot(w)
(2) np.dot(v,w)
200
# 矩阵乘法
x = np.array([[1,2], [3,4]])
y = np.array([[5,6], [7,8]])
(1) x.dot(y)
(2) np.dot(x,y)
array([[19, 22],
[43, 50]])
# v = np.array([9,10]) # 一维可看成行向量又可以看成列向量,此处为满足矩阵乘法为列向量(2x1)
(1) x.dot(v)
(2) np.dot(x, v)
array([29, 67])
# 转置(与数学相同)
x.T
array([[1, 3],
[2, 4]])
# 一维向量转置就是本身
v.T
array([9, 10])
# 二维不同
w = np.array([[1,2,3]])
print(w, w.shape)
[[1 2 3]] (1, 3)
print(w.T)
[[1]
[2]
[3]]
# 高维数组(tensor)
# 例:
f = np.random.randn(2,3,4) # 总共两大块,每大块里三小块,每小块四元素
print(f)
[[[ 0.03866615 -1.07901707 0.16366115 -0.53048756]
[-0.81813884 -0.53505294 0.82491683 -1.09155967]
[ 0.82251694 -0.05660042 -0.7786442 0.61981324]]
[[ 1.41040236 -1.04999785 -0.36338812 -0.4984866 ]
[-0.56534221 -0.56177563 0.78985078 -1.47727231]
[-1.28708395 -0.33997327 0.63821361 -0.52293797]]]
# (1) transpose()
arr = np.arange(16).reshape(2,2,4)
print(arr)
[[[ 0 1 2 3]
[ 4 5 6 7]]
[[ 8 9 10 11]
[12 13 14 15]]]
print(arr.transpose((1,0,2))) # 还是(2, 2, 4)的矩阵
'''
transpose()将索引改变了,以数字9为例,9原本的索引是(1, 0, 1),
即第1大块中第0小块的第1个元素,经过transpose(1, 0, 2)后,
索引变为(0, 1, 1),即第0大块中第1小块的第1个元素,
如下所示,其他数字同理
'''
[[[ 0 1 2 3]
[ 8 9 10 11]]
[[ 4 5 6 7]
[12 13 14 15]]]
print(arr.transpose((0,2,1))) # (2, 4, 2)的矩阵
'''
以数字6为例,原本索引为(0, 1, 2),变为(0, 2, 1),
即第0大块,第2小块,第1个元素
'''
[[[ 0 4]
[ 1 5]
[ 2 6]
[ 3 7]]
[[ 8 12]
[ 9 13]
[10 14]
[11 15]]]
print(arr.transpose((0,1,2))) # (0, 1, 2)不变,索引就为(0, 1, 2),即第0维第1维第2维
[[[ 0 1 2 3]
[ 4 5 6 7]]
[[ 8 9 10 11]
[12 13 14 15]]]
# (2) swapaxes()
print(arr.swapaxes(1,2)) # 和transpose(0, 2, 1)相同,即第1维与第2维互换
[[[ 0 4]
[ 1 5]
[ 2 6]
[ 3 7]]
[[ 8 12]
[ 9 13]
[10 14]
[11 15]]]
# 张量乘法
x = np.arange(24).reshape(2,3,4)
y = np.arange(8).reshape(4,2)
print(np.matmul(x,y).shape)
(2, 3, 2) # 即2x3x4 x 4x2,与矩阵乘法类似,最后一维消掉得2x3x2
print(np.dot(x,y).shape)
(2, 3, 2)
# matmul()与dot()区别
x = np.arange(24).reshape(2,3,4)
y = np.arange(16).reshape(2,4,2)
print(x.dot(y).shape)
(2, 3, 2, 2) # 将2x3x4中的4与2x4x2中的4消掉,得2x3x2x2
print(np.matmul(x,y).shape)
(2, 3, 2)
# 矩阵内运算
# sum
x= np.array([[1,2], [3,4]])
[[1 2]
[3 4]]
(1) np.sum(x
(2) x.sum()
10
print(np.sum(x, axis=0)) # 对第0维求和
[4 6]
print(np.sum(x, axis=1)) # 对第1维求和
[3, 7]
print(x.cumsum(axis=0)) print(x.cumsum(axis=1))
[[1 2] [[1 3]
[4 6]] [3 7]]
# mean(平均)
print(np.mean(x))
print(np.mean(x, axis=0))
print(np.mean(x, axis=1))
2.5
[ 2. 3.]
[ 1.5 3.5]
# 找出排序后5%的数字
large_arr = np.random.randn(1000)
large_arr.sort()
print(large_arr[int(0.05 * len(large_arr))])
-1.71556330464
Broadcasting(广播)
如果要用小矩阵去和大矩阵做一些操作,但是希望小矩阵能循环和大矩阵的那些块做一样的操作,那就需要用broadcasting
# 给x的每一行都逐元素加上一个向量,然后生成y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = np.empty_like(x)
# (1) for循环
for i in range(4):
y[i,:] = x[i,:] + v # y的i行等于x的i行加上v
print(y)
[[ 2 2 4]
[ 5 5 7]
[ 8 8 10]
[11 11 13]]
# 直接加
print(x + v)
[[ 2, 2, 4],
[ 5, 5, 7],
[ 8, 8, 10],
[11, 11, 13]]
'''
当操作两个array时,numpy会逐个比较它们的shape,
在下述情况下,两arrays会兼容和输出broadcasting结果:
1. 相等
2. 其中一个为1,(进而可进行拷贝拓展已至,shape匹配)
比如求和的时候有:
'''
Image (3d array): 256 x 256 x 3
Scale (1d array): 3
Result (3d array): 256 x 256 x 3
# 3相等,只要把3拓展成256x256x3即可
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
# 其中一个为1,取最大值即可
A (2d array): 5 x 4
B (1d array): 1
Result (2d array): 5 x 4
A (2d array): 15 x 3 x 5
B (1d array): 15 x 1 x 5
Result (2d array): 15 x 3 x 5
# 例子:
v = np.array([1,2,3])
w = np.array([4,5])
v = v.reshape(3,1)
v + w
array([[5, 6], [[1+4, 1+5],
[6, 7], [2+4, 2+5],
[7, 8]]) [3+4, 3+5]]
x = np.array([[1,2,3], [4,5,6]]) # 2x3的
w = np.array([4,5]) # 2
(x.T + w).T # x=3x2
array([[ 5, 6, 7],
[ 9, 10, 11]])
x + np.reshape(w, (2,1)) # w=2x1
array([[ 5, 6, 7],
[ 9, 10, 11]])
broadcasting总结:
逻辑运算
x_arr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
y_arr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])
print(np.where(cond, x_arr, y_arr)) # True取x_arr,False取y_arr
[ 1.1 2.2 1.3 1.4 2.5]
arr = np.random.randn(4,4)
print(np.where(arr > 0, 1,-1)) # arr>0为True取1,否则为False取-1
[[ 1 1 1 1]
[-1 -1 1 -1]
[ 1 -1 1 -1]
[-1 -1 -1 1]]
数组高级操作
arr = np.arange(15)
print(arr.reshape(5,3).shape)
print(arr.reshape(5,-1).shape) # 如果我们在某一个维度上写上-1,numpy会帮我们自动推导出正确的维度
(5, 3)
# 高维数组可以用ravel来拉平
arr.ravel().shape
(15,)
# 连接两个数组
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([[7, 8, 9], [10, 11, 12]])
np.concatenate([arr1, arr2], axis=0) # 先把arr1和arr2拼成一个list,再指定在第0维上拼到一起
array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]])
np.concatenate([arr1, arr2], axis=1)
array([[ 1, 2, 3, 7, 8, 9],
[ 4, 5, 6, 10, 11, 12]])
np.vstack((arr1, arr2)) # vertical(垂直)
array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]])
np.hstack((arr1, arr2)) # horizontal
array([[ 1, 2, 3, 7, 8, 9],
[ 4, 5, 6, 10, 11, 12]])
# 拆分数组
arr = np.random.rand(5,5)
print(arr)
[[ 0.80642843 0.43253953 0.24511404 0.21328645 0.50991311]
[ 0.19373378 0.72169396 0.05192132 0.1746048 0.69771988]
[ 0.59689743 0.82253158 0.03346062 0.9002945 0.03960687]
[ 0.06061257 0.27390675 0.19740262 0.76815388 0.02035703]
[ 0.58031701 0.63341072 0.75286027 0.82066801 0.24301514]]
first, second, third = np.split(arr, [1,3], axis=0) # 在第1个位置和第3个位置上截
print(first, '\n\n', second, '\n\n', third)
[[ 0.80642843 0.43253953 0.24511404 0.21328645 0.50991311]]
[[ 0.19373378 0.72169396 0.05192132 0.1746048 0.69771988]
[ 0.59689743 0.82253158 0.03346062 0.9002945 0.03960687]]
[[ 0.06061257 0.27390675 0.19740262 0.76815388 0.02035703]
[ 0.58031701 0.63341072 0.75286027 0.82066801 0.24301514]]
# 堆叠的一些方法
arr = np.arange(6)
arr1 = arr.reshape((3, 2))
arr2 = np.random.randn(3, 2)
# r_用于按行堆叠
print(np.r_[arr1, arr2])
[[ 0. 1. ]
[ 2. 3. ]
[ 4. 5. ]
[-0.60392123 -0.1769936 ]
[ 0.46523138 0.71963034]
[-0.51733042 1.50108329]]
# c_用于按列堆叠
print(np.c_[np.r_[arr1, arr2], arr])
[[ 0. 1. 0. ]
[ 2. 3. 1. ]
[ 4. 5. 2. ]
[-0.60392123 -0.1769936 3. ]
[ 0.46523138 0.71963034 4. ]
[-0.51733042 1.50108329 5. ]]
# 使用repeat来重复
arr = np.arange(3)
print(arr)
[0 1 2]
print(arr.repeat(3))
[0 0 0 1 1 1 2 2 2]
print(arr.repeat([2,3,5]))
[0 0 1 1 1 2 2 2 2 2]
# 指定axis来重复
arr = np.random.rand(2,2)
print(arr.repeat(2, axis=0))
[[ 0.90063544 0.36862431 0.46734451]
[ 0.90063544 0.36862431 0.46734451]
[ 0.61467785 0.63962631 0.61288228]
[ 0.61467785 0.63962631 0.61288228]]
print(arr.repeat(2, axis=1))
[[ 0.90063544 0.90063544 0.36862431 0.36862431 0.46734451 0.46734451]
[ 0.61467785 0.61467785 0.63962631 0.63962631 0.61288228 0.61288228]]
# Tile: 贴瓷砖
print(np.tile(arr, 2))
[[ 0.9682022 0.99265567 0.9682022 0.99265567]
[ 0.62174828 0.12614083 0.62174828 0.12614083]]
print(np.tile(arr, (2,3)))
[[ 0.9682022 0.99265567 0.9682022 0.99265567 0.9682022 0.99265567]
[ 0.62174828 0.12614083 0.62174828 0.12614083 0.62174828 0.12614083]
[ 0.9682022 0.99265567 0.9682022 0.99265567 0.9682022 0.99265567]
[ 0.62174828 0.12614083 0.62174828 0.12614083 0.62174828 0.12614083]]
文件输入输出
# 读取csv文件作为数组
arr = np.loadtxt('array_ex.txt', delimiter=',')
print(arr)
[[ 0.580052 0.18673 1.040717 1.134411]
[ 0.194163 -0.636917 -0.938659 0.124094]
[-0.12641 0.268607 -0.695724 0.047428]
[-1.484413 0.004176 -0.744203 0.005487]
[ 2.302869 0.200131 1.670238 -1.88109 ]
[-0.19323 1.047233 0.482803 0.960334]]
# 数组文件读写
arr = np.arange(50).reshape(2,5,5)
np.save('some_array', arr)
arr2 = np.load('some_array.npy')
# 多个数组打包
arr3 = np.arange(15).reshape(3,5)
np.savez("array_archive.npz", a=arr, b=arr2, c=arr3)
arch = np.load('array_archive.npz')
print(arch['a'])
print(arch['b'])
print(arch['c'])
用numpy做一个softmax
- 计算exponential
- 按行求和
- 每一行都要除以计算的和
# 计算exponential
m = np.random.rand(10,10) * 10 + 1000
# np.exp(m)太大了,变成了inf
m_row_max = m.max(axis=1).reshape(10,1) # 取出每一行最大的数
m = m - m_row_max
m_exp = np.exp(m)
# 按行求和
m_exp_row_sum = m_exp.sum(axis=1).reshape(10,1)
# 每一行都要除以计算的和
m_softmax = m_exp / m_exp_row_sum
print(m_softmax)
# 验证
print(m_softmax.sum(axis=1))
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]