本篇博客所有示例使用Jupyter NoteBook演示。
Python数据分析系列笔记基于:利用Python进行数据分析(第2版)
目录
1.数组转置和轴对换
2.数组重塑
3.数组扁平化
4.数组的合并和拆分
5.元素的重复操作:tile/repeat
转置是重塑的一种特殊形式,返回的是源数据的视图(不会进行任何复制操作).
2维数组转置不仅有transpose方法,还有一个特殊的T属性:
import numpy as np
arr = np.arange(15).reshape((3,5))
print(arr.T) #返回源数组arr的视图 arr没有任何改变 arr.T/arr.transpose()返回arr的视图
print(arr.transpose()) #如果赋值给一个新数组 对新数组进行修改 arr也会改变
print(arr)
进行矩阵运算时,经常要用到转置操作,比如利用np.dot计算矩阵内积时:
arr = np.random.randn(6,3)
print(arr)
print(np.dot(arr.T,arr)) #(3,6) (6,3)->(3,3)
对于高维数组,transpose函数需要得到一个由轴编号组成的元组才能对轴进行转置:
arr = np.arange(16).reshape((2,2,4))
print(arr)
print("---------------")
print(arr.transpose(1,0,2))
这里0轴和1轴互换,2轴不变。
2维数组简单的转置可以使用.T,他其实就是进行轴对换而已。ndarray还有一个swapaxes函数,需要接受一对轴编号:
print(arr)
print("--------------")
print(arr.swapaxes(1,2))
swapaxes函数和transpose,.T一样,也是返回源数据的视图(不会进行任何复制操作)
多数情况下,可以无需复制任何数据,就可以将数组从一个形状转换为另一个形状。只需要向数组的函数reshape传入一个表示新形状的元组即可。
将一个一维数组重新排列成一个矩阵(2维数组):
arr = np.arange(8)
print(arr)
print(arr.reshape((4,2))) #返回arr的视图
reshape函数还有一个order参数,两个取值:'C'表示C order,行优先顺序;'F'表示F order,列优先顺序。默认是C order。如下图所示:
多维数组也能被重塑:
print(arr.reshape((4,2)).reshape((2,4)))
作为参数的形状的其中一维可以是-1,表示该维度的大小由数据本身推断而来:
arr = np.arange(15)
print(arr.reshape((5,-1))) #-1让numpy自动计算 15/5=3
与reshape将一维数组转换为多维数组的运算相反的运算称为扁平化flattening或散开raveling:
arr = np.arange(15).reshape((5,3))
print(arr)
print(arr.ravel()) #返回源数组的视图
print(arr.flatten()) #效果和ravel相同 返回源数组的副本
C和Fortran顺序:
数组的重塑和散开可以按照两种不同的顺序。NumPy允许我们更为灵活地控制数据在内存中的布局。默认情况下NumPy数组是按行优先顺序创建的,重塑和散开也是默认为行优先顺序,即C顺序。在空间方面,意味着对于一个2维数组,每行中的数据项被存放在相邻的内存位置上。另一种顺序是列优先顺序,即F顺序,意味着每列中的数据项是被存放在相邻内存位置上的。
像reshape和reval/flatten这样的函数,都可以接受一个表示数组存放顺序的order参数。一般可以是'C'或'F'(还有'A','K'等不常用选项,具体参考NumPy文档):
arr = np.arange(12).reshape((3,4))
print(arr)
print(arr.ravel()) #默认为C顺序 行优先 返回数组视图
print(arr.ravel('F')) #可以设置为F顺序 列优先 返回数组视图
2维数组或高维数组的重塑过程比较令人费解。C和Fortran顺序的关键区别就是维度的行进顺序:
C/行优先顺序:先经过更高的维度(如,轴1会先于轴0被处理)
F/列优先顺序:后经过更高的维度(如,轴0会先于轴1被处理)
默认情况下,都是C顺序。
np.concatenate可以按指定轴将一个由数组组成的序列(如元组、列表等)连接在一起:
arr1 = np.array([[1,2,3],[4,5,6]])
arr2 = np.array([[7,8,9],[10,11,12]])
print(np.concatenate([arr1,arr2],axis=0)) #沿0轴合并 沿各个行(y轴方向) 默认情况下axis=0 返回副本
print(np.concatenate([arr1,arr2],axis=1)) #沿1轴合并 沿各个列(x轴方向) 返回副本
对于常见的连接操作,NumPy还提供一些比较方便的方法,如hstack和vstack:
print(np.vstack((arr1,arr2))) #沿轴0 沿各个行的方向(y轴方向,竖直方向) 返回副本
print(np.hstack((arr1,arr2))) #沿轴1 沿各个列的方向(x轴方向,水平方向) 返回副本
与此相反split函数用于将一个数组沿指定的轴在指定的位置拆分为多个数组:
arr = np.random.randn(5,2)
print(arr)
first,second,third = np.split(arr,[1,3],axis=0) #沿0轴 在索引1和3位置进行切割
print("-----------")
print(first)
print("-----------")
print(second)
print("-----------")
print(third)
print("------------")
first,second = np.split(arr,[1],axis=1) #沿1轴 在索引1位置进行切割
print("-----------")
print(first)
print("-----------")
print(second)
下表列出了所有有关数组连接和拆分的函数:
堆叠辅助类:r_和c_
NumPy命名空间中有两个特殊的对象r_和c_,他们可以使数组的堆叠操作更为简洁:
arr = np.arange(6)
arr1 = arr.reshape((3,2))
arr2 = np.random.randn(3,2)
print(np.r_[arr1,arr2]) #沿轴0 沿各个行的顺序(竖直,y方向) 面向各个行 返回副本
print(np.c_[np.r_[arr1,arr2],arr]) #沿轴1 沿各个列的顺序(水平,x方向) 面向各个列 返回副本
还可以把切片转换为数组:
print(np.c_[1:6,-10:-5])
np.c_堆叠数组时(一个2维数组和一个1维数组,或两个一维数组进行堆叠时),会把一维数组转换为2维列向量(2维数组)再进行合并。
对数组进行重复以产生更大数组主要使用tile/repeat两个函数:
repeat会将数组中的各个元素重复一定次数,产生一个更大的数组:
arr = np.arange(3)
print(arr)
print(arr.repeat(3)) #arr中的每个元素都重复3次
和其他流行的数组编程语言如Matlab不同,NumPy中很少需要对数组进行重复,因为NumPy支持广播,能够更好的满足该要求,不同大小的数组间也是可以根据广播规则直接运算的。
默认情况下,如果传入一个整数,则各个元素就会重复那么多次。如果传入的是一组整数,则各个元素就可以重复不同的次数:
print(arr)
print(arr.repeat([2,3,4]))
对于多维数组,还可以让他们的元素沿指定轴重复:
arr = np.random.randn(2,2)
print(arr)
print(arr.repeat(2,axis=0)) #沿轴0(沿各个行) 每个元素重复2次
注意如果没有设置轴向,则数组会被扁平化,可能不是你期望的:
arr = np.random.randn(2,2)
print(arr)
print(arr.repeat(2))
同样对于多维数组进行重复时,也可以传入一组整数,这样会使各切片重复不同的次数:
print(arr)
print(arr.repeat([2,3],axis=0))
print(arr.repeat([2,4],axis=1))
tile的功能是沿指定轴向堆叠数组的副本,可以形象地想象为“铺瓷砖”:
print(arr)
print(np.tile(arr,2)) #第2个参数是一个标量时 表示沿轴1/水平方向(各个列)进行重复堆叠
print(np.tile(arr,(2,1))) #第2个参数也可以是一个元组 表示沿每个轴的重复堆叠次数 第一个元素沿轴0次数 依次类推
print(np.tile(arr,(3,2)))
注意tile和repeat的区别,tile是将数组整体沿指定的轴进行重复堆叠;repeat是将数组中的每个元素/每行/每列分别沿指定的轴进行重复堆叠。2者都返回数组的副本。