numpy的12个基本操作

BG07

Posted by Blue Geek on September 17, 2019

numpy的12个基本操作

By 青衣极客 Blue Geek In 2019-09-17

在使用python进行数据处理时,numpy已经是一个必不可少的第三方库了。掌握numpy的基本操作无论对于普通的数据处理还是应用深度学习框架都是有意义的。这里讨论numpy中最常用到的12个基本操作,为数据分析打下良好的基础。

import os
import sys
import numpy as np

1. 创建数组

numpy创建数组的方式非常多,比较常用的是从list数据或者numpy自带的函数创建数组。

(1) 从list数据创建

# 从list创建数组
print(np.array([1,2,3,4,5]))             # 一维数组
print(np.array([[1,2,3], [4,5,6]]))      # 二维数组
print(np.array([1,2,3], dtype=np.float)) # 指定元素数据类型
[1 2 3 4 5]
[[1 2 3]
 [4 5 6]]
[1. 2. 3.]

(2) 函数接口创建特殊0-1元素

print(np.zeros((1,3), dtype=np.int64))   # 创建全0的数组
print(np.ones((1,3), dtype=np.float))    # 创建全1的数组
print(np.eye(2, dtype=np.float))         # 创建单位矩阵
[[0 0 0]]
[[1. 1. 1.]]
[[1. 0.]
 [0. 1.]]

(3) 函数接口创建具有规律的数组

print(np.arange(1, 10, 2))               # 创建均匀的整数数组
print(np.linspace(1, 3, 4))              # 创建线性数组
print(np.random.random((1,3)))           # 创建随机数组
[1 3 5 7 9]
[1.         1.66666667 2.33333333 3.        ]
[[0.5003854  0.59875968 0.79207667]]

2. 数组索引

数组的索引是用于操作数组元素的,numpy提供了非常灵活的索引方式,使得代码极为简洁。

(1) 直接索引

a = np.random.random((3,3))
print(a[0][0])      # 直接索引
0.4059516560746701

(2) 条件蒙板

print(a>0.5)        # 条件蒙版
[[False False False]
 [ True False  True]
 [ True False  True]]

(3) 蒙板索引

print(a[a>0.5])     # 蒙版索引
[0.95266423 0.88453931 0.72445232 0.90560359]

(4) 切片索引

print(a[1, 2])      # 切片索引
0.8845393115697767

3. 扩展矩阵

将一个小矩阵复制若干次形成大矩阵的操作也是常用的,比如在生成三维坐标时使用的meshgrid。numpy提供tile和repeat这两个函数可以方便地完成矩阵扩展的任务。

a = np.array([[1,2,3]])
print(np.tile(a, [3,1]))
print(a.repeat(3, axis=0))
[[1 2 3]
 [1 2 3]
 [1 2 3]]
[[1 2 3]
 [1 2 3]
 [1 2 3]]

4. 改变形状

改变数组的形状以适应一些计算对形状的要求,numpy提供了与matlab相似的操作。

(1) 指定目标形状 reshape

a = np.array([1,2,3,4])
b = a.reshape((2,2))       # 指定目标形状
print(b)
[[1 2]
 [3 4]]

(2) 压平成一维数组 flatten

print(b.flatten())         # 压平成一维数组
[1 2 3 4]

(3) 直接修改形状 resize

a.resize(2,2)              # 直接修改
print(a)
[[1 2]
 [3 4]]

5. 转置类的操作

numpy提供了丰富的转置类型的操作,用于方便地改变元素的排列方式。

(1) 转置函数与转置属性成员

a = np.array([[1,2], [3,4]], dtype=np.float)
print('a.transpose() = ', a.transpose())    # 计算数组转置
print('a.T = ', a.T)                        # 同样是转置
a.transpose() =  [[1. 3.]
 [2. 4.]]
a.T =  [[1. 3.]
 [2. 4.]]

(2) 转换坐标轴到axis=0

b = np.array(list(range(16)))
b = b.reshape([2,2,4])
print('b = ', b)
c = np.rollaxis(b, 2)          # 将坐标轴axis=2转到axis=0
print('c = ', c)
b =  [[[ 0  1  2  3]
  [ 4  5  6  7]]

 [[ 8  9 10 11]
  [12 13 14 15]]]
c =  [[[ 0  4]
  [ 8 12]]

 [[ 1  5]
  [ 9 13]]

 [[ 2  6]
  [10 14]]

 [[ 3  7]
  [11 15]]]

转换坐标轴到底有什么用处呢?下面的例子告诉你。

print('np.mean(b, axis=2) = ', np.mean(b, axis=2))
# 对axis=2的坐标轴上所有元素减去该轴上的均值
print('c - np.mean(b, axis=2) = ', c - np.mean(b, axis=2))
np.mean(b, axis=2) =  [[ 1.5  5.5]
 [ 9.5 13.5]]
c - np.mean(b, axis=2) =  [[[-1.5 -1.5]
  [-1.5 -1.5]]

 [[-0.5 -0.5]
  [-0.5 -0.5]]

 [[ 0.5  0.5]
  [ 0.5  0.5]]

 [[ 1.5  1.5]
  [ 1.5  1.5]]]

(3) 交换任意坐标轴

d = np.swapaxes(b, 2, 1)
print('d = ', d)

d = [[[ 0 4] [ 1 5] [ 2 6] [ 3 7]]

 [[ 8 12]
  [ 9 13]
  [10 14]
  [11 15]]]

6. 改变维度

在有些计算中需要将维度为1的坐标轴删去,有时有需要扩展一下坐标轴。

(1) 删除维度为1的坐标轴

a = np.array([[1,2], [3,4]])
b = a.reshape((1, -1))
print('b.shape = ', b.shape)
c = b.squeeze()                # 去掉维度为1的坐标轴
print('c.shape = ', c.shape)

b.shape =  (1, 4)
c.shape =  (4,)

(2) 扩展维度等于1坐标轴

d = np.expand_dims(c, axis=1)  # 在扩展指定坐标轴的维度为1
print('d.shape = ', d.shape)
d.shape =  (4, 1)

7. 拼接数组

将多个数组拼接到一起,形成复杂的大数组来满足一些逻辑比较复杂的需求。

(1) 指定维度拼接

a = np.array([[1,2],[3,4]])
b = np.array([[5,6], [7,8]])
c = np.concatenate((a, b), axis=1)  # 在指定坐标轴上拼接数组
print('c = ', c)
c =  [[1 2 5 6]
 [3 4 7 8]]

(2) 新建axis=0拼接

d = np.stack([a,b])                 # 拼接数组到一个新的坐标轴
print(d)

[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]

8. 切分数组

有拼接的需求就有切分的需求,切分数组是指按照指定的方式将大数组切成若干个小数组。

a = np.arange(9)
print(np.split(a, [3,5,6,8]))  # 按照指定切分点对原数组进行切分
[array([0, 1, 2]), array([3, 4]), array([5]), array([6, 7]), array([8])]

9. 增加和移除元素

在现有的数组中指定的位置插入或者删除元素可以使用numpy提供的delete和insert函数。

(1) 移除元素 delete

a = np.arange(8)
a = a.reshape((2,4))

c = np.delete(a, [0,2], axis=1)  # 在指定坐标轴上删除指定切片
print('c = ', c)
c =  [[1 3]
 [5 7]]

(2) 增加元素 insert

d = np.insert(a, 1, 5, axis=1)   # 在指定坐标轴的指定切片处插入指定数值  
print('d = ', d)
d =  [[0 5 1 2 3]
 [4 5 5 6 7]]

10. 广播

广播这种原则的出现为代码编写者省去了很多的麻烦,numpy数组也支持广播规则。 (1). 坐标轴不足的向坐标轴最多的看齐 (2). 结果数组的形状由参与计算的各数组各坐标轴维度最大的确定 (3). 在对应坐标轴上,只有输入数组的维度为1,或者与输出数组相同才可计算 (4). 对坐标轴维度为1的数组进行扩展时,就是不断复制该维度

a = np.array([1,2,3])
b = np.array([[4],[5],[6]])
print(a+b)    # 相当于先调用repeat函数把两个输入数组变成同样形状,然后计算
[[5 6 7]
 [6 7 8]
 [7 8 9]]

11. 基本运算

numpy当然不只是存储数据的,我们常常需要用numpy的数组来进行数学计算。比如加减乘除,矩阵求逆等等。

(1) 加法

a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])

# 加法
print('a+b = ', a+b)
a+b =  [[ 6  8]
    [10 12]]

(2) 矩阵乘法

print(a.dot(b))
[[19 22]
 [43 50]]

(3) 元素乘法

print('a*b = ', a*b)

a*b = [[ 5 12] [21 32]]

(4) 矩阵求逆

print(np.linalg.inv(a))
[[-2.   1. ]
 [ 1.5 -0.5]]

我们来验证一下这个求逆的结果是否正确。

print(a.dot(np.linalg.inv(a)))
[[1.0000000e+00 0.0000000e+00]
 [8.8817842e-16 1.0000000e+00]]

可以发现求逆的结果是正确的。

12. save和load

有时免不了需要将一些数组dump到文件中,一来可以方便下一次使用,二来也可以在同行或朋友间分享中间数据。

(1) 保存数组到文件 save

a = np.arange(16)
print('a = ', a)
save_path = '../output/np_save.npy'
# 将数组写入到文件
np.save(save_path, a)
a =  [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15]

(2) 从文件载入数组 load

b = np.load(save_path)   # 从文件中载入
print('b = ', b)
b =  [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15]

以上就是numpy的12个常用基本操作,学会这些就可以在数据分析或者机器学习中熟练使用numpy。这里大多展示的是二维数组,事实上numpy的数组是任意维度的张量,与tensorflow或者pytorch中的张量有很好的兼容性。

CHANGELOG

  • 2020-04-07 添加解说文本

【青衣极客】公众号



COMMENT

博客评论区功能由Github Issue提供,提交Issue时请以本文标题为话题

"BG07-numpy的12个基本操作"