Numpy5——数组的扩充(相加、复制、广播)排序,形状调整

一、数组扩充

数组扩充:通过对原始数据进行各种变换来增加数据量,提高模型的泛化能力。

常见的扩充方法(拼接轴可以变,其他轴必须对齐)
  • np.append(数组变量,要添加的数据,axis=指定的轴):在指定的轴上增加指定数据
  • np.vstack((变量,变量)):沿着0轴进行拼接,0轴上的数量发生变化
  • np.hstack((变量,变量)) :沿着1轴进行进行拼接,1轴上的数量发生变化
  • np.dstack((变量,变量)):沿着2轴进行拼接,2轴上的数量发生变化
  • np.concatenate( (变量,变量),axis) :沿着指定的轴进行拼接
  • np.stack((变量,变量),axis):将数组在指定的维度(可以是新维度可以是已有维度)上进行堆叠(两个变量的数组形状必须是完全一致的)
a = np.arange(12).reshape(2, 2,3)
b = np.arange(12).reshape(2,2,3)
print(a)
# [[[ 0  1  2]
#   [ 3  4  5]]
# 
#  [[ 6  7  8]
#   [ 9 10 11]]]
print("----------------------")
print(b)
# [[[ 0  1  2]
#   [ 3  4  5]]
# 
#  [[ 6  7  8]
#   [ 9 10 11]]]
print("----------------------")
print(np.vstack((a,b)))
# 等价于print(np.concatenate((a,b),axis = 0))
# [[[ 0  1  2]
#   [ 3  4  5]]
# 
#  [[ 6  7  8]
#   [ 9 10 11]]
# 
#  [[ 0  1  2]
#   [ 3  4  5]]
# 
#  [[ 6  7  8]
#   [ 9 10 11]]]
print("----------------------")
print(np.hstack((a,b)))
# 等价于print(np.concatenate((a,b),axis = 1))
# [[[ 0  1  2]
#   [ 3  4  5]
#   [ 0  1  2]
#   [ 3  4  5]]
# 
#  [[ 6  7  8]
#   [ 9 10 11]
#   [ 6  7  8]
#   [ 9 10 11]]]
print("----------------------")
print(np.dstack((a,b)))
# 等价于print(np.concatenate((a,b),axis = 2))
# [[[ 0  1  2  0  1  2]
#   [ 3  4  5  3  4  5]]
# 
#  [[ 6  7  8  6  7  8]
#   [ 9 10 11  9 10 11]]]
print(np.stack((a,b),axis=3))
# [[[[ 0  0]
#    [ 1  1]
#    [ 2  2]]
# 
#   [[ 3  3]
#    [ 4  4]
#    [ 5  5]]]
# 
# 
#  [[[ 6  6]
#    [ 7  7]
#    [ 8  8]]
# 
#   [[ 9  9]
#    [10 10]
#    [11 11]]]]
基于已有数组内容,将数组进行扩充

repeat:重复元素

  • np.repeat(数组变量,想要重复的次数n,axis):沿着指定的轴,将变量内容依照顺序重复n次。如果不指定轴的话,就会将数组平铺成一维数组,之后在进行重复。
  • 变量.repeat(想要重复的次数n,axis):沿着指定的轴,将变量内容依照顺序重复n次。
  • 两种写法的结果一致,只是一个调用的是numpy的函数,一个调用的是数组变量的方法
arr = np.random.standard_normal((2,2))
print(arr)
# [[-0.13427715 -1.74640395]
#  [ 0.15025149 -1.95301146]]
print(np.repeat(arr, 2,axis=0))
# [[-0.13427715 -1.74640395]
#  [-0.13427715 -1.74640395]
#  [ 0.15025149 -1.95301146]
#  [ 0.15025149 -1.95301146]]
print(arr.repeat(2,axis=1))
# [[-0.13427715 -0.13427715 -1.74640395 -1.74640395]
#  [ 0.15025149  0.15025149 -1.95301146 -1.95301146]]

tile:使用铺瓷砖的方式,重复整个结构

  • np.tile(数组变量,整数或者元组)
    • 如果传入的第二个参数是整数的,那么会沿着所有轴重复指定次数
    • 如果传入的第二个参数是是元组,那么分别沿着各个轴重复指定次数
  • 数组变量下没有该方法
arr = np.random.standard_normal((2,2))
print(arr)
# [[ 1.40148927  0.76308092]
#  [-0.04267682 -1.62260472]]
print(np.tile(arr,(2,3)))
# [[ 1.40148927  0.76308092  1.40148927  0.76308092  1.40148927  0.76308092 ]
#  [-0.04267682 -1.62260472 -0.04267682 -1.62260472 -0.04267682 -1.62260472 ]
#  [ 1.40148927  0.76308092  1.40148927  0.76308092  1.40148927  0.76308092]
#  [-0.04267682 -1.62260472 -0.04267682 -1.62260472 -0.04267682 -1.62260472]]
print(np.tile(arr,2)) # 这里的2被广播成了(1,2)
# [[ 0.96356878 -0.37401939  0.96356878 -0.37401939]
#  [ 1.31243353 -0.25105547  1.31243353 -0.25105547]]

广播:不同形状数组之间的运算执行方式,自动扩展维度较小的数组,以适配较大维度的数组。

  • 规则一:如果两个数组的维度数不同,形状会在较小的数组前面补1
    A形状:(3,4,2)、B形状: (4,1)——>B形状广播成(1,4,1)
  • 规则二:对于每个维度,大小要么相等,要么其中一个为1,要么其中一个不存在
    A形状:(3,4,2)、B形状广播后的形状(1,4,1)
    第一维度:3,1:存在1,可兼容
    第二维度:4,4:大小相等,可兼容
    第三维度:2,1:存在1,可兼容
  • 规则三:在维度大小为1的情况下,数组会沿着该维度"拉伸"以匹配另一个数组的形状
    A形状:(3,4,2)、B形状广播后的形状(1,4,1)
    第一维度:3,1:B的第一维度复制三次(3,4,1)
    第二维度:4,4:大小相等,可兼容(3,4,1)
    第三维度:2,1:B的第三维度复制两次(3,4,2)

不可广播与newaxis : 解决不符合广播条件的数组之间的运算

  • 普遍问题:为了可以广播,需要专门添加一个长度为1的新轴。
    可以reshape,但reshape需要传一个表示新形状的元组,有点麻烦。
    NumPy数组提供了一种通过索引机制插入轴的特殊语法:np.newaxis属性以及全切片插入新轴
  • np.newsxis:配合切片使用。主要作用是在数组的指定位置插入一个新的轴(维度),从而改变数组的形状而不改变其数据
rng = np.random.default_rng(seed = 123)
arr = rng.standard_normal((4,3))
print(arr)
# [[-0.98912135 -0.36778665  1.28792526]
#  [ 0.19397442  0.9202309   0.57710379]
#  [-0.63646365  0.54195222 -0.31659545]
#  [-0.32238912  0.09716732 -1.52593041]]
# 计算每一行的平均值
a_mean = arr.mean(1)
print(a_mean)
# [-0.02299425  0.5637697  -0.13703563 -0.5837174 ]
# 想要通过减去行平均值的方式,降低数组中每一行的数值
# arr - arr.mean(1)   报错,因为二者的维度不同,达不到广播条件
a_mean_f = a_mean[:,np.newaxis] # 将原先的一维数组改成4*1维度的数组
print(a_mean_f)
# [[-0.02299425]
#  [ 0.5637697 ]
#  [-0.13703563]
#  [-0.5837174 ]]
print(arr - a_mean_f)
# [[-0.9661271  -0.3447924   1.31091951]
#  [-0.36979528  0.3564612   0.01333409]
#  [-0.49942802  0.67898785 -0.17955983]
#  [ 0.26132829  0.68088472 -0.94221301]]

二、排序

  • np.sort() : 返回排序后的数组副本
  • ndarray.sort() : 原地排序
  • np.argsort():获取排序索引
  • np.partition(变量,k):找出前k小的元素(不保证顺序),前k小的元素在左边
  • sortargsort中的参数:
    • kind参数:用于选择排序时使用的算法:quicksot(默认的,快速排序),mergesort(归并排序,稳定),heapsort(堆排序)
    • axis:默认值是-1,从最低维度(也就是编号最高的轴)开始排序
    • order:针对结构化数组的参数,它用于指定按照哪些字段进行排序,可指定多个字段
  • 想要实现降序排序需要使用切片 [::-1]
arr = np.array([3, 1, 4, 2, 5])
stable_sorted = np.sort(arr, kind='mergesort')
print(stable_sorted) # 输出:[1 2 3 4 5]

indices = np.argsort(arr)
print(indices)  # 输出: [1 3 0 2 4] (原始数组中元素的排序后位置)

partitioned = np.partition(arr, 3)
print(partitioned)  # 输出: [1 2 3 4 5] (前3小的元素在左边)

desc_sorted = np.sort(arr)[::-1]  # 升序后反转
print(desc_sorted)  # 输出: [5 4 3 2 1]


# 结构化数组排序
dtype = [('name', 'S10'), ('age', int)]
values = [('Alice', 25), ('Bob', 20), ('Charlie', 30)]
arr = np.array(values, dtype=dtype)
# 按age字段排序
sorted_by_age = np.sort(arr, order=['name', 'age'])
print(sorted_by_age)
# 输出: [(b'Bob', 20) (b'Alice', 25) (b'Charlie', 30)]

三、数组形状调整(resize(reshape),flatten,unravel

resize vs reshape :调整数组的形状
  • np.reshape(变量,(形状))

  • 变量.reshape((形状))
    返回:返回一个新视图(共享原数据),而非新数组。
    功能:仅改变数组的视图(shape),不修改数据本身。
    条件:新形状必须与原数组的元素总数一致(即 shape1.prod() == shape2.prod()),否则会报错。

    arr = np.array([3, 1, 4, 2, 5])
    print(np.reshape(arr,(5,1)))
    # 输出:
    # [[3]
    #  [1]
    #  [4]
    #  [2]
    #  [5]]
    print(np.reshape(arr,(5,2))) # 数组中的元素不同,报错
    
    print(arr.reshape((5,1)))
    # 输出:
    # [[3]
    #  [1]
    #  [4]
    #  [2]
    #  [5]]
    print(arr)
    # 输出:# [3 1 4 2 5]
    
  • np.resize(变量,(形状)) :填充的时候使用数组本身的数据;返回修改后的数组

  • 变量.reshape((形状)):填充的时候,全部填充0;原数组被原地修改,返回空值
    功能:直接修改数组的形状和数据(如果新形状更大,会填充重复数据;如果更小,会截断数据)。
    条件:不要求新形状与原数组元素总数一致。
    refcheck参数:控制数组大小调整时的引用检查行为。默认是true,表示有引用的时候调整形状报错,可以改成False,表示跳过引用检查。

    arr = np.array([3, 1, 4, 2, 5])
    print(np.resize(arr,(3,2)))
    # 输出:
    # [[3 1]
    #  [4 2]
    #  [5 3]]
    # 如果这里添加一个引用:b = arr,那么再次使用resize调整形状就会报错
    arr.resize((5,2))  # 这里使用print的话,返回none
    print(arr)
    # 输出:
    # [[3 1]
    #  [4 2]
    #  [5 0]
    #  [0 0]
    #  [0 0]]
    
flatten vs ravel:返回一维数组
  • 变量.flatten() :返回是一个完全独立的新数组,相当于深拷贝内容

  • 变量.ravel():尽可能返回视图

  • order参数:C:在最低维度的坐标轴上对元素进行读取并将数据进行拉平;F:在最高维度上将数据进行拉平,会强制转换存储顺序;A:智能选择C/F,如果存储的时候不是连续的则退回C;K:严格遵循内存顺序读取数据。

    a = np.array(np.arange(10).reshape(2, 5),order = "F") # 模拟Fortran语言存放数组
    print(a)
    # [[0 1 2 3 4]
    #  [5 6 7 8 9]]
    print(a.ravel(order='C'))  # 在最低维度的坐标轴方向上对元素进行读取,拉平
    # [0 1 2 3 4 5 6 7 8 9]
    print(a.ravel(order='F'))  # 与 C相反,在最高维度的坐标轴方向上对元素进行读取,拉平
    # [0 5 1 6 2 7 3 8 4 9]
    print(a.ravel(order = "A"))
    # [0 5 1 6 2 7 3 8 4 9]
    

你可能感兴趣的:(Numpy5——数组的扩充(相加、复制、广播)排序,形状调整)