前言

对于数组的操作大致分为2大类:

  • 单一数组操作
  • 多个数组共同操作

其中,单一数组操作可分为:

  • 修改数组形状
  • 翻转数组
  • 修改数组维度
  • 数组元素的添加与删除

多个数组共同操作可分为:

  • 数组组合
  • 数组拆分

1.修改数组形状

修改数组形状相关的方法有如下四种:

函数

描述

reshape

不改变数据的条件下修改形状

flat

数组元素迭代器

flatten

返回一份数组拷贝,对拷贝所做的修改不会影响原始数组

ravel

返回展开数组

1)reshape方法

numpy.reshape 函数可以在不改变数据的条件下修改形状,格式如下:

python 改变数组中的值 numpy数组修改_python

a:要修改形状的数组
newshape:整数或者整数数组,新的形状应当兼容原有形状
order:‘C’ – 按照行顺序,‘F’ – 按照列顺序,‘A’ – 按照数据在内存中存储的顺序

【例1-1】reshape方法实例

>>> a = np.arange(8)
>>> print(a,a.shape) 
[0 1 2 3 4 5 6 7] (8,)
>>> b = np.reshape(a,[2,4],'C')
>>> print(b,b.shape)
[[0 1 2 3]
 [4 5 6 7]] (2, 4)
>>> b = np.reshape(a,[2,4],'F')
>>> print(b,b.shape)
[[0 2 4 6]
 [1 3 5 7]] (2, 4)
>>> b = np.reshape(a,[2,4],'A')
>>> print(b,b.shape)
[[0 1 2 3]
 [4 5 6 7]] (2, 4)
>>> b[0][0] = 100
>>> print(a)
[100   1   2   3   4   5   6   7]

我们可以看到改变b的数据,a是跟随变动的。按行和按列排序比较好理解,但是对于‘A’要结合Fortran,C 数组内存分布来看,有兴趣的可以自行去了解,这里不展开讨论。

2)flat方法

【例1-2】flat方法实例

>>> a = np.arange(5)
>>> b = a.flat
>>> print(b,type(b))
<numpy.flatiter object at 0x7fe1033cb200> <class 'numpy.flatiter'>
>>> for x in a.flat:
>>>     print(x)
0
1
2
3
4
>>> a = np.random.randint(0,10,(3,3))
>>> print(a)
>>> for x in a.flat:
>>>     print(x)
[[7 1 6]
 [4 9 2]
 [0 7 7]]
7
1
6
4
9
2
0
7
7

flat方法比较好理解,可以用于迭代数组,对于多维数组来说也是一样的,默认按行遍历数组。

3)flatten方法

numpy.ndarray.flatten 返回一份数组展开后的拷贝,对拷贝所做的修改不会影响原始数组。

python 改变数组中的值 numpy数组修改_数据分析_02


其中order与上面reshape中的order参数作用是相同的,不加赘述。

【例1-3】flatten方法实例

>>> a = np.random.randint(0,10,(3,4))
>>> print(a)
[[4 3 1 9]
 [1 4 5 3]
 [7 5 4 6]]
>>> b = np.flatten(a)
>>> print(b)
[4 3 1 9 1 4 5 3 7 5 4 6]
>>> b[0]=100
>>> print(a)
[[4 3 1 9]
 [1 4 5 3]
 [7 5 4 6]]

可以看到flatten()确实可以按行展开数组,并且对展开后的数据进行修改不会影响原来的数组。

4)ravel方法

numpy.ravel() 展平的数组元素,返回的是数组视图(view),在第6章视图的部分我们详细讲过,修改会影响原始数组。其中order与上面reshape中的order参数作用是相同的,不加赘述。

python 改变数组中的值 numpy数组修改_机器学习_03

【例1-4】ravel方法实例

>>> a = np.random.randint(0,10,(3,4))
>>> print(a)
[[4 4 6 3]
 [9 7 5 7]
 [2 0 7 9]]
>>> b = np.ravel(a)
>>> print(b)
[4 4 6 3 9 7 5 7 2 0 7 9]
>>> b[0]=100
>>> print(a)
[[100   4   6   3]
 [  9   7   5   7]
 [  2   0   7   9]]

我们可以看到,修改数组b确实可以影响原始数组a。

2.翻转数组

函数

描述

transpose

对换数组的维度

T

和 self.transpose() 相同

rollaxis

向后滚动指定的轴

swapaxes

对换数组的两个轴

1)transpose方法

python 改变数组中的值 numpy数组修改_numpy_04


axes是可选参数,我们可以用来翻转指定的数据,让我们来举例说明transpose()的普通用法和加参用法:

【例2-1】transpose方法实例

>>> a = np.random.randint(0,10,(3,3))
>>> print(a)
[[4 6 1]
 [7 2 4]
 [7 4 7]]
>>> b = np.transpose(a)
>>> print(b)
[[4 7 7]
 [6 2 4]
 [1 4 7]]
>>> c = np.random.randint(0,10,(3,2,1))
>>> d = np.transpose(c,(1,0,2))
>>> print(d.shape)
(2, 3, 1)

从a到b就是transpose的普通用法,从c到d是加参用法。np.transpose(c,(1,0,2))的含义是让第一维度和第二维度互相交换,而第三维度保持不变。

2)T方法

python 改变数组中的值 numpy数组修改_numpy_05

ndarray.Tndarray.transpose类似,不同的是ndarray.T并没有形参,举例如下:

【例2-2】T方法实例

>>> a = np.random.randint(0,10,(3,3))
>>> print(a)
[[9 1 2]
 [9 2 4]
 [4 4 0]]
>>> b=a.T
>>> print(b)
[[9 9 4]
 [1 2 4]
 [2 4 0]]

3)rollaxis方法

python 改变数组中的值 numpy数组修改_python_06

numpy.rollaxis 函数向后滚动特定的轴到一个特定位置,第二个参数是要滚动的轴,第三个参数是被滚动的轴索引,默认是0。

【例2-3】rollaxis方法实例

>>> a = np.random.randint(0,10,(3,4,5,6))
>>> print (a.shape)
(3, 4, 5, 6)
>>> b = np.rollaxis(a,2,0)
>>> print (b.shape)
(5, 3, 4, 6)

4)swapaxes方法

python 改变数组中的值 numpy数组修改_机器学习_07

numpy.swapaxes 函数用于交换数组的两个轴,第二个参数和第三个参数分别是交换双方的索引。

【例2-4】swapaxes方法实例

>>> a = np.random.randint(0,10,(3,4,5))
>>> print (a.shape)
(3, 4, 5)
>>> b = np.swapaxes(a,0,1)
>>> print (b.shape)
(4, 3, 5)

3.修改数组维度

1)用ndarray.newaxis增加数组维度

这个我们在第一章常数的最后一节讲过,ndarray.newaxis == None ,可以用来增加数组维度:

【例3-1】用ndarray.newaxis增加数组维度

>>> a = np.random.randint(0,10,(6))
>>> print(a,a.shape)
[7 5 2 5 5 7]
>>> b = a[np.newaxis,...]
>>> print(b,b.shape)
[[7 5 2 5 5 7]] (1, 6)
>>> b = a[...,np.newaxis]
>>> print(b,b.shape)
[[7]
 [5]
 [2]
 [5]
 [5]
 [7]] (6, 1)

2)用squeeze方法减少数组维度

numpy.squeeze 函数从给定数组的形状中删除一维的条目,注意所要删去的维度长度必须是1,不然会报错,原因是因为如果长度不等于1,那么squeeze会使其他维度的结构被破坏【TODO】

【例3-2】squeeze方法实例

>>> a = np.random.randint(0,10,(1,5,1,2,1))
>>> b = np.squeeze(a)
>>> print(b.shape)
(5, 2)
>>> b = np.squeeze(a,0)
>>> print(b.shape)
(5, 1, 2, 1)
>>> b = np.squeeze(a,2)
>>> print(b.shape)
(1, 5, 2, 1)
>>> b = np.squeeze(a,4)
>>> print(b.shape)
(1, 5, 1, 2)
>>> b = np.squeeze(a,1)
>>> print(b.shape)
ValueError: cannot select an axis to squeeze out which has size not equal to one

注,np.squeeze(a)表示去除a中所有维度为1的维度,感觉跟压缩无用信息有点类似。

4.数组元素的添加与删除

1)用insert添加数组元素

python 改变数组中的值 numpy数组修改_numpy_08

【例4-1】insert方法实例

>>> a = np.array([[1, 1], [2, 2], [3, 3]])
>>> print(a)
[[1 1]
 [2 2]
 [3 3]]
>>> b = np.insert(a, 2, 6)
>>> print(b)
[1 1 6 2 2 3 3]
>>> b = np.insert(a, 2, 6, axis=1)
>>> print(b)
[[1 1 6]
 [2 2 6]
 [3 3 6]]

可以看到,如果不指定axis的值,那么原始数组会被扁平化。

2)用delete删除数组元素

python 改变数组中的值 numpy数组修改_python 改变数组中的值_09

【例4-2】delete方法实例

>>> a = np.random.randint(0,10,(3,3))
>>> print(a)
[[7 1 8]
 [7 2 6]
 [8 3 1]]
>>> b = np.delete(a, 1, axis=0)
>>> print(b)
[[7 1 8]
 [8 3 1]]
>>> b = np.delete(a,[1])
>>> print(b)
[7 8 7 2 6 8 3 1]

可以看到,同insert方法一样,如果不指定axis的值,那么原始数组会被扁平化。

5.数组组合

函数

描述

concatenate

连接沿现有轴的数组序列

stack

沿着新的轴加入一系列数组。

hstack

水平堆叠序列中的数组(列方向)

vstack

竖直堆叠序列中的数组(行方向)

1)concatenate方法

python 改变数组中的值 numpy数组修改_numpy_10

【例5-1】concatenate方法实例

#一维操作
>>> x = np.arange(3,6)
>>> y = np.arange(6,9)
>>> print(x.shape,y.shape)
(3,) (3,)
>>> z = np.concatenate([x,y])
>>> print(z,z.shape)
[3 4 5 6 7 8] (6,)
#二维操作
>>> x = np.random.randint(0,10,(3,3))
>>> y = np.random.randint(0,10,(3,3))
>>> print(x)
[[2 3 9]
 [8 8 8]
 [8 4 2]]
>>> print(y)
[[9 1 3]
 [9 2 0]
 [1 0 3]]
>>> z = np.concatenate([x,y])
>>> print(z,z.shape)
[[2 3 9]
 [8 8 8]
 [8 4 2]
 [9 1 3]
 [9 2 0]
 [1 0 3]] (6, 3)
>>> z = np.concatenate([x,y],axis=0)
>>> print(z,z.shape)
[[2 3 9]
 [8 8 8]
 [8 4 2]
 [9 1 3]
 [9 2 0]
 [1 0 3]] (6, 3)
>>> z = np.concatenate([x,y],axis=1)
>>> print(z,z.shape)
[[2 3 9 9 1 3]
 [8 8 8 9 2 0]
 [8 4 2 1 0 3]] (3, 6)

我们可以把concatenate方法想做一款胶水,它在不改变拼接原材料数组的前提下,对指定的位置(axis)进行粘合。

举例:

  • shape为(3,3)的两个数组沿axis=0粘合,结果数组shape为(6,3)
  • shape为(3,3)的两个数组沿axis=1粘合,结果数组shape为(3,6)

注:axis默认为0,若设成None,则原数组在使用前会被扁平化。

2)stack方法

python 改变数组中的值 numpy数组修改_python 改变数组中的值_11

【例5-2】stack方法实例

#一维操作
>>> x = np.arange(3,6)
>>> y = np.arange(6,9)
>>> print(x.shape,y.shape)
(3,) (3,)
>>> z = np.stack([x,y])
>>> print(z,z.shape)
[[3 4 5]
 [6 7 8]] (2, 3)
#二维操作
>>> x = np.random.randint(0,10,(3,3))
>>> y = np.random.randint(0,10,(3,3))
>>> print(x)
[[6 6 5]
 [5 3 7]
 [8 3 7]]
>>> print(y)
[[4 7 1]
 [7 4 7]
 [9 1 3]]
>>> z = np.stack([x,y])
>>> print(z,z.shape)
[[[6 6 5]
  [5 3 7]
  [8 3 7]]

 [[4 7 1]
  [7 4 7]
  [9 1 3]]] (2, 3, 3)
>>> z = np.stack([x,y],axis=0)
>>> print(z,z.shape)
[[[6 6 5]
  [5 3 7]
  [8 3 7]]

 [[4 7 1]
  [7 4 7]
  [9 1 3]]] (2, 3, 3)
>>> z = np.stack([x,y],axis=1)
>>> print(z,z.shape)
[[[6 6 5]
  [4 7 1]]

 [[5 3 7]
  [7 4 7]]

 [[8 3 7]
  [9 1 3]]] (3, 2, 3)
>>> z = np.stack([x,y],axis=2)
>>> print(z,z.shape)
 [[[3 6]
  [1 8]
  [6 9]]

 [[7 4]
  [1 3]
  [9 2]]

 [[8 0]
  [9 9]
  [7 0]]] (3, 3, 2)

我们注意到,与concatenate方法不同的是,stack方法生成的数组比原始数组维度多1,且多的维度的长度等于原始数组的长度:

  • 两个shape为(3,3)的原始数组,axis=0,结果数组shape为(2,3,3)
  • 两个shape为(3,3)的原始数组,axis=1,结果数组shape为(3,2,3)
  • 两个shape为(3,3)的原始数组,axis=2,结果数组shape为(3,3,2)

且位置正是axis。

注:axis默认为0,且只能为不超过原始数组长度的整数:

>>> z = np.stack([x,y],None)
>>> print(z,z.shape)
TypeError: an integer is required (got type NoneType)

3)hstack方法

numpy.hstacknumpy.stack 函数的变体,它通过水平堆叠来生成数组。

python 改变数组中的值 numpy数组修改_机器学习_12

【例5-3】hstack方法实例

#一维操作
>>> x = np.arange(3,6)
>>> y = np.arange(6,9)
>>> print(x.shape,y.shape)
(3,) (3,)
>>> z = np.hstack([x,y])
>>> print(z,z.shape)
[3 4 5 6 7 8] (6,)
#二维操作
>>> x = np.random.randint(0,10,(3,3))
>>> y = np.random.randint(0,10,(3,3))
>>> print(x)
[[8 7 7]
 [5 7 5]
 [8 0 0]]
>>> print(y)
[[3 2 8]
 [0 0 7]
 [6 3 4]]
>>> z = np.hstack([x,y])
>>> print(z,z.shape)
[[8 7 7 3 2 8]
 [5 7 5 0 0 7]
 [8 0 0 6 3 4]] (3, 6)

以2个2维(3,3)数组为例,尝试带大家理解一下hstack的合并原理:

python 改变数组中的值 numpy数组修改_python 改变数组中的值_13

第一、二维就是原始数组的第一、二维,其中第橙色、蓝色分别代表x和y,由于采用水平堆叠,所以x,y水平排列在一起。那么显而易见,结果数组shape为(3,6)。

在这里,我们无需计较后面可能存在的更高维数据,因为它们都可以被包裹进前面的数据中,可以对用户保持透明。

注:hstack并不可以指定axis,并且生成的结果数组的维度与之前保持一致。

4)vstack方法

numpy.vstacknumpy.stack 函数的变体,它通过垂直堆叠来生成数组。

python 改变数组中的值 numpy数组修改_python 改变数组中的值_14

【例5-4】vstack方法实例

#一维操作
>>> x = np.arange(3,6)
>>> y = np.arange(6,9)
>>> print(x.shape,y.shape)
(3,) (3,)
>>> z = np.vstack([x,y])
>>> print(z,z.shape)
[[3 4 5]
 [6 7 8]] (2, 3)
#二维操作
>>> x = np.random.randint(0,10,(3,3))
>>> y = np.random.randint(0,10,(3,3))
>>> print(x)
[[6 5 2]
 [4 1 4]
 [2 1 4]]
>>> print(y)
[[7 4 8]
 [8 2 0]
 [2 5 0]]
>>> z = np.vstack([x,y])
>>> print(z,z.shape)
[[6 5 2]
 [4 1 4]
 [2 1 4]
 [7 4 8]
 [8 2 0]
 [2 5 0]] (6, 3)

hstack的合并原理类似,vstack合并原理的示意图如下:

python 改变数组中的值 numpy数组修改_python_15


hstack不同的是数据之间的堆叠方式,其他一切保持一致。

6.数组拆分

函数

描述

split

将一个数组分割为多个子数组

hsplit

将一个数组水平分割为多个子数组(按列)

vsplit

将一个数组垂直分割为多个子数组(按行)

1)split方法

python 改变数组中的值 numpy数组修改_numpy_16

【例6-1】split方法实例

>>> x = np.random.randint(0,10,(3,4))
>>> print(x)
[[7 7 9 4]
 [1 3 7 1]
 [2 8 3 1]]
>>> y = np.split(x,[1,3])
>>> print(y,type(y),len(y))
[array([[7, 7, 9, 4]]), array([[1, 3, 7, 1],
       [2, 8, 3, 1]]), array([], shape=(0, 4), dtype=int64)] <class 'list'> 3
>>> y = np.split(x,[1,2])
>>> print(y,type(y),len(y))
[array([[7, 7, 9, 4]]), array([[1, 3, 7, 1]]), array([[2, 8, 3, 1]])] <class 'list'> 3

又到了我们熟悉的切蛋糕环节,np.split(x,[1,3])里面的[1,3]代表着下刀的位置,注意此处的整数指索引,而落刀位置在索引前,如下图:

python 改变数组中的值 numpy数组修改_数据分析_17


其中索引3是我们虚拟出来的,另外结果y是一个List型的数据类型,它的长度是3,等于[1,3]长度+1,这更加贴近实际,也就是蛋糕不交叉地切2刀,会出现三块蛋糕,如果最后一刀在原始数组尾,那么会补一个同样shape的空ndarray类型。

注:axis默认为0,代表沿着第一维度移动“刀”。

2)vsplit方法

python 改变数组中的值 numpy数组修改_python_18


vsplit方法顾名思义,是垂直切的意思,但是这个水平是指“刀”移动的方向,不要误以为是刀切的方向!我们做一下对比:

【例6-2】vsplit方法实例

>>> x = np.random.randint(0,10,(3,4))
>>> print(x)
[[5 9 5 6]
 [2 3 0 0]
 [5 0 1 3]]
>>> y = np.split(x,[1,3])
>>> print(y,type(y),len(y))
[array([[5, 9, 5, 6]]), array([[2, 3, 0, 0],
       [5, 0, 1, 3]]), array([], shape=(0, 4), dtype=int64)] <class 'list'> 3
>>> y = np.split(x,[1,2])
>>> print(y,type(y),len(y))
[array([[5, 9, 5, 6]]), array([[2, 3, 0, 0]]), array([[5, 0, 1, 3]])] <class 'list'> 3
>>> y = np.vsplit(x,[1,2])
>>> print(y,type(y),len(y))
[array([[5, 9, 5, 6]]), array([[2, 3, 0, 0]]), array([[5, 0, 1, 3]])] <class 'list'> 3

我们可以看到vsplit的刀确实是水平切的,而且其与np.split(x,[1,3])结果相同。

3)hsplit方法

python 改变数组中的值 numpy数组修改_机器学习_19

【例6-3】hsplit方法实例

x = np.random.randint(0,10,(3,4))
print(x)
[[2 7 2 4]
 [8 8 5 0]
 [6 0 8 4]]
y = np.split(x,[1,3],axis=1)
print(y,type(y),len(y))
[array([[2],
       [8],
       [6]]), array([[7, 2],
       [8, 5],
       [0, 8]]), array([[4],
       [0],
       [4]])] <class 'list'> 3
y = np.hsplit(x,[1,3])
print(y,type(y),len(y))
[array([[2],
       [8],
       [6]]), array([[7, 2],
       [8, 5],
       [0, 8]]), array([[4],
       [0],
       [4]])] <class 'list'> 3

切割示意图如下:

python 改变数组中的值 numpy数组修改_python_20