numpy arrays 基础和操作

python中的数据操作基本都用numpy来做,在做深度学习的过程一定也绕不过numpy。这篇分几个部分介绍numpy
· numpy array 的基本属性,包括 shape, size, dim, data type
· 通过 index 获取 numpy array 的数据
· 分割 numpy array,获取 sub array
· 变换 numpy array 的维度
· 合并 numpy array,合并多个数组

numpy array 属性

numpy array 有几个基本属性,分别是

shape, size, dim, data type

这里通过几个不同维度的数组来了解这几个属性。首先我们先随机生成几个不同维度的numpy array

import numpy as np
np.random.seed(0)  # seed for reproducibility

x1 = np.random.randint(10, size=6)  # One-dimensional array
x2 = np.random.randint(10, size=(3, 4))  # Two-dimensional array
x3 = np.random.randint(10, size=(3, 4, 5))  # Three-dimensional array

数组的三个属性分别表示的含义
ndim: 维度数量
shape: 每个维度的数量
size: 数组的总数量

print("x3 ndim: ", x3.ndim)
print("x3 shape:", x3.shape)
print("x3 size: ", x3.size)

得到
x3 ndim: 3
x3 shape: (3, 4, 5)
x3 size: 60

另一个比较有用的属性是 dtype,代表数据的类型

print("dtype:", x3.dtype)

dtype: int64

数组下标

numpy的数组下标和其他语言的下标语法差不多,取对应index的值可以用过中括号来获取。
假设 array([5, 0, 3, 3, 7, 9]) 为 x1

x1[0]

得到 5

numpy提供了一种方便的逆序index,用负值来获取从后往前的Index的数据

x1[-1]

得到 9.
需要注意逆序的起始位置不是0(这个很明显)

对于二维数组的情况,假设我们有个 x2,

array([[3, 5, 2, 4],
       [7, 6, 8, 8],
       [1, 6, 7, 7]])

[0, 0] 位置的值是3,通过

x2[0, 0]

可以获得。

x2[2, -1]

得到 7

修改数组的值也可以通过下标来操作

x2[0, 0] = 2
print(x2)

得到

array([[12,  5,  2,  4],
       [ 7,  6,  8,  8],
       [ 1,  6,  7,  7]])

但numpy的数据类型在初始化的时候就确定了,意味着当你想给它赋值不同的数据类型,numpy会自动静默转换。比如我们想把一个浮点类型赋值给 int 类型的 numpy

x1[0] = 3.14159
print(x1)

此时的 x1是

array([3, 0, 3, 3, 7, 9])
切割array,获取子串

中括号指定下标的方式可以获取某个下标对应的值,获取子串也可以通过这种方式,通过指定[起始点:终点:步进]可以得到对应子串,(😃 冒号符是用来分割起始点和终点和步进的。下面是具体的语法

x[start:stop:step]

这三个的默认值是
start = 0
stop = 维度对应的size
step = 1

一维数组子串

先定义一个一维数组

x = np.arange(10)

现在x是

array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

想获取前5个元素

x[:5] -> array([0, 1, 2, 3, 4])

获取从5到最后的元素

x[5:] -> array([5, 6, 7, 8, 9])

获取index 4 到 7 的元素,不包含[7]这个元素

x[4:7] -> array([4, 5, 6])

按步进为2获取元素

x[::2] -> array([0, 2, 4, 6, 8])

步进2,获取奇数元素

x[1::2] -> array([1, 3, 5, 7, 9])

除此之外,Numpy的子串操作还可以进行逆序操作,如从后向前步进n步取子串

x[::-1] -> array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])

这是取逆序

x[5::-2] -> array([5, 3, 1])
二维数组子串操作

二维数组的子串操作类似,下面举几个例子
首先定义个二维数组

x2 -> array([[12,  5,  2,  4],
       [ 7,  6,  8,  8],
       [ 1,  6,  7,  7]])

取第一维的前两个维度,每个维度取前三个元素做子串

x2[:2, :3] -> array([[12,  5,  2],
       [ 7,  6,  8]])

取第一维度前三个,每个维度步进2取子串

x2[:3, ::2] -> array([[12,  2],
       [ 7,  8],
       [ 1,  7]])

二维数组同样也可以反转

x2[::-1, ::-1] -> array([[ 7,  7,  6,  1],
       [ 8,  8,  6,  7],
       [ 4,  2,  5, 12]])
修改子串

通过子串操作拿到的子串实际上元素还处于原始数据维度中,如果对子串的数据进行修改,同样也会影响到原来的数据

x2 ->  [[12  5  2  4]
 [ 7  6  8  8]
 [ 1  6  7  7]]

现在取个子串

x2_sub = x2[:2, :2] -> [[12  5]
 [ 7  6]]

然后修改子串的值

x2_sub[0, 0] = 99
x2_sub -> [[99  5]
 [ 7  6]]

此时原始数组的数据也会发生改变

x2 -> [[99  5  2  4]
 [ 7  6  8  8]
 [ 1  6  7  7]]

那么如何在不影响原始数据的情况下生成一个新的子串来修改呢

创建数组副本

我们先创建一个原始二维数据

x2 ->  [[99  5  2  4]
 [ 7  6  8  8]
 [ 1  6  7  7]]

现在还是取 [:2, :2] 作为子串,但这里用 copy 的方式生成一个独立副本

x2_sub_copy = x2[:2, :2].copy()
x2_sub_copy -> [[99  5]
 [ 7  6]]

然后对它进行修改,

x2_sub_copy[0, 0] = 42
x2_sub_copy ->[[42  5]
 [ 7  6]]

现在查看原始数据,

x2 -> [[99  5  2  4]
 [ 7  6  8  8]
 [ 1  6  7  7]]

x2的[0, 0]并没有发生改变,还是99

维度变换

维度变换是 numpy 数组中用的最多的一个操作,经常用来对输入数据进行维度转换,比如我们有一个三通道的5x5图片,用numpy表示是

image.shape = (5, 5, 3)

如果想把三个通道合并为一个,可以通过reshape进行操作

image.reshape((15, 5, 1))

结果会把三通道的数据压缩成单通道。

再一个例子,先定义个3x3的1~9数组

grid = np.arange(1, 10)
grid -> array([1, 2, 3, 4, 5, 6, 7, 8, 9])

grid = grid.reshape((3, 3))
grid -> [[1 2 3]
 [4 5 6]
 [7 8 9]]

定义的时候数组长度也就是size,必须能够塞进所定义的维度里也就是3x3,
不然reshape的时候会失败。

另一种转换维度的方法是用上面切割子串的 (😃 操作符,
比如我们有一个一维数组,想转换成二维数组,

x = np.array([1,2,3])

numpy提供了个关键词 newaxis,可以在进行子串切割的时候指定新增维度,如使用reshape可以这么写

x = x.reshape((1,3))
x.shape -> (1, 3)

使用 newaxis 可以这么写,也有一样的效果

x = x[np.newaxis, :]
x.shape -> (1, 3)
数组拼接

数组拼接也是常见操作之一,一般有两种情况,同样维度的数组合并,和维度不一样的数组合并。
对于这两种情况,有两种不同的合并操作
· np.concatenate
· np.vstack , np.hstack
vstack和hstack分别表示 vertical和 horizontal,在两个不同维度上合并。

合并相同维度数组
grid = np.arange(0, 6)
grid = grid.reshape((2,3))
grid -> array([[0, 1, 2],
       [3, 4, 5]])

用concatenate合并

grid = np.concatenate([grid,grid])
grid -> array([[0, 1, 2],
       [3, 4, 5],
       [0, 1, 2],
       [3, 4, 5]])
       
grid.shape = (4,3)
合并不同维度数组

合并一个一维数组和一个二维数组,

x = np.array([1, 2, 3])
grid = np.array([[9, 8, 7],
                 [6, 5, 4]])

合并不同维度数组的前提是在长度一样的维度上进行合并,上面这个需要在 vstack上合并(有点别扭,verticale是垂直方向,跟数组的书写方向习惯不一样)

merge = np.vstack([x, grid])
merge -> array([[1, 2, 3],
       [9, 8, 7],
       [6, 5, 4]])

在hstack方向合并

y = np.array([[99],[99]])
merge = np.hstack([grid, y])
merge -> array([[ 9,  8,  7, 99],
       [ 6,  5,  4, 99]])
拆分数组

既然能合并数组,那么数组也可以拆分,以一个一维数组为例

 x = np.arange(0,7)
 x -> array([0, 1, 2, 3, 4, 5, 6])

在index为3和5进行拆分

 x1,x2,x3 = np.split(x, [3,5])
 print(x1,x2,x3) 

会得到

>>> x1
array([0, 1, 2])
>>> x2
array([3, 4])
>>> x3
array([5, 6])

同样也可以对多维数组在不同的维度上拆分,

grid = np.arange(16).reshape((4, 4))
grid -> array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])

用 vsplit 拆分

upper, lower = np.vsplit(grid, [2])
upper -> [[0 1 2 3]
 [4 5 6 7]]
 
lower -> [[ 8  9 10 11]
 [12 13 14 15]]

用 hstack 进行拆分

left, right = np.hsplit(grid, [2])
left -> [[ 0  1]
 [ 4  5]
 [ 8  9]
 [12 13]]
 
right -> [[ 2  3]
 [ 6  7]
 [10 11]
 [14 15]]
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值