知远漫谈头像
关注
Python NumPy - 数组的堆叠 hstack 与 vstack 函数的使用封面图

Python NumPy - 数组的堆叠 hstack 与 vstack 函数的使用

在这里插入图片描述

👋 大家好,欢迎来到我的技术博客!
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕NumPy这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!


Python NumPy - 数组的堆叠 hstack 与 vstack 函数的使用 📊

在数据科学和机器学习的世界中,NumPy 是一个不可或缺的强大工具包。它提供了高效的数组操作功能,使得处理大规模数值数据变得轻而易举。其中,hstack 和 vstack 函数是两个非常实用的数组堆叠方法,它们可以帮助我们将多个数组按水平或垂直方向进行组合。

什么是数组堆叠? 🤔

数组堆叠是指将两个或多个数组按照特定的方向连接在一起的操作。想象一下你在拼接乐高积木块,每一块都有自己的形状和大小,通过特定的方式将它们连接起来形成更大的结构。在 NumPy 中,我们可以通过堆叠来创建更复杂的多维数组结构。

堆叠的基本概念

堆叠操作的核心思想是:

  • 水平堆叠 (hstack):沿着数组的列方向(axis=1)进行连接
  • 垂直堆叠 (vstack):沿着数组的行方向(axis=0)进行连接
import numpy as np

# 创建示例数组
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])

print("原始数组 arr1:")
print(arr1)
print("\n原始数组 arr2:")
print(arr2)

# 水平堆叠
h_result = np.hstack((arr1, arr2))
print("\n水平堆叠结果:")
print(h_result)

# 垂直堆叠
v_result = np.vstack((arr1, arr2))
print("\n垂直堆叠结果:")
print(v_result)

让我们通过一个简单的流程图来理解这个过程:

水平堆叠

垂直堆叠

输入数组1

堆叠类型

输入数组2

按列连接

按行连接

输出数组

深入理解 hstack 函数 🔍

np.hstack() 函数用于水平堆叠数组,也就是沿着数组的第二个轴(列方向)进行连接。这个函数特别适用于需要将数据按特征维度扩展的情况。

基本语法和参数

numpy.hstack(tup)

参数说明:

  • tup: 包含数组的元组或列表,这些数组将被水平堆叠

返回值:

  • 返回一个新的数组,包含所有输入数组的水平堆叠结果

一维数组的水平堆叠

对于一维数组,hstack 相当于将数组简单地连接在一起:

import numpy as np

# 一维数组示例
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.array([7, 8, 9])

print("一维数组 a:", a)
print("一维数组 b:", b)
print("一维数组 c:", c)

# 水平堆叠
result = np.hstack((a, b, c))
print("\n水平堆叠结果:", result)
print("结果形状:", result.shape)

二维数组的水平堆叠

对于二维数组,水平堆叠会增加列的数量:

import numpy as np

# 创建二维数组
matrix1 = np.array([[1, 2],
                    [3, 4],
                    [5, 6]])

matrix2 = np.array([[7, 8],
                    [9, 10],
                    [11, 12]])

print("矩阵1:")
print(matrix1)
print("形状:", matrix1.shape)

print("\n矩阵2:")
print(matrix2)
print("形状:", matrix2.shape)

# 水平堆叠
h_stacked = np.hstack((matrix1, matrix2))
print("\n水平堆叠结果:")
print(h_stacked)
print("结果形状:", h_stacked.shape)

不同形状数组的水平堆叠

需要注意的是,进行水平堆叠时,除了最后一个维度外,其他维度必须匹配:

import numpy as np

# 形状兼容的数组
arr1 = np.array([[1, 2, 3],
                 [4, 5, 6]])

arr2 = np.array([[7],
                 [8]])

print("数组1形状:", arr1.shape)
print("数组2形状:", arr2.shape)

# 这种情况是可以水平堆叠的
try:
    result = np.hstack((arr1, arr2))
    print("水平堆叠成功:")
    print(result)
    print("结果形状:", result.shape)
except ValueError as e:
    print("错误:", e)

# 形状不兼容的例子
arr3 = np.array([[1, 2],
                 [3, 4]])

arr4 = np.array([[5, 6, 7]])  # 行数不匹配

print("\n尝试堆叠形状不匹配的数组...")
try:
    result = np.hstack((arr3, arr4))
except ValueError as e:
    print("错误:", e)

探索 vstack 函数 💡

np.vstack() 函数用于垂直堆叠数组,即沿着数组的第一个轴(行方向)进行连接。这在需要增加样本数量或合并不同数据集时非常有用。

基本用法

import numpy as np

# 创建示例数组
top_array = np.array([[1, 2, 3],
                      [4, 5, 6]])

bottom_array = np.array([[7, 8, 9],
                         [10, 11, 12]])

print("顶部数组:")
print(top_array)
print("形状:", top_array.shape)

print("\n底部数组:")
print(bottom_array)
print("形状:", bottom_array.shape)

# 垂直堆叠
v_stacked = np.vstack((top_array, bottom_array))
print("\n垂直堆叠结果:")
print(v_stacked)
print("结果形状:", v_stacked.shape)

一维数组的垂直堆叠

对于一维数组,vstack 会将其转换为二维数组并按行堆叠:

import numpy as np

# 一维数组
row1 = np.array([1, 2, 3, 4])
row2 = np.array([5, 6, 7, 8])
row3 = np.array([9, 10, 11, 12])

print("行1:", row1)
print("行2:", row2)
print("行3:", row3)

# 垂直堆叠
v_result = np.vstack((row1, row2, row3))
print("\n垂直堆叠结果:")
print(v_result)
print("结果形状:", v_result.shape)

多维数组的垂直堆叠

import numpy as np

# 三维数组示例
cube1 = np.array([[[1, 2], [3, 4]],
                  [[5, 6], [7, 8]]])

cube2 = np.array([[[9, 10], [11, 12]],
                  [[13, 14], [15, 16]]])

print("立方体1形状:", cube1.shape)
print("立方体2形状:", cube2.shape)

# 垂直堆叠(沿第一个轴)
v_3d = np.vstack((cube1, cube2))
print("垂直堆叠后形状:", v_3d.shape)

实际应用场景 🚀

了解了基本用法后,让我们看看这些函数在实际项目中的应用。

数据预处理中的应用

在机器学习项目中,经常需要将不同的特征数据集合并:

import numpy as np

# 模拟用户数据
user_ids = np.array([[1], [2], [3], [4], [5]])
ages = np.array([[25], [30], [35], [28], [42]])
incomes = np.array([[50000], [75000], [100000], [60000], [120000]])

print("用户ID:")
print(user_ids)
print("年龄:")
print(ages)
print("收入:")
print(incomes)

# 将特征水平堆叠成完整的特征矩阵
features = np.hstack((user_ids, ages, incomes))
print("\n完整特征矩阵:")
print(features)
print("特征矩阵形状:", features.shape)

图像处理中的应用

在计算机视觉领域,图像通常表示为多维数组,堆叠操作常用于创建图像批次:

import numpy as np

# 模拟单个图像数据 (假设是 28x28 的灰度图像)
image1 = np.random.randint(0, 256, size=(28, 28))
image2 = np.random.randint(0, 256, size=(28, 28))
image3 = np.random.randint(0, 256, size=(28, 28))

print("单个图像形状:", image1.shape)

# 创建图像批次
batch = np.stack((image1, image2, image3))  # 使用 stack 而不是 vstack
print("图像批次形状:", batch.shape)

# 如果要使用 vstack,需要先增加维度
image1_expanded = np.expand_dims(image1, axis=0)
image2_expanded = np.expand_dims(image2, axis=0)
image3_expanded = np.expand_dims(image3, axis=0)

batch_vstack = np.vstack((image1_expanded, image2_expanded, image3_expanded))
print("使用 vstack 的批次形状:", batch_vstack.shape)

时间序列数据处理

在时间序列分析中,可能需要将不同时间段的数据垂直堆叠:

import numpy as np

# 模拟股票价格数据
january_prices = np.array([[100.5, 101.2, 99.8],
                          [101.0, 102.5, 100.1],
                          [102.3, 103.1, 101.9]])

february_prices = np.array([[103.5, 104.2, 102.8],
                           [104.0, 105.5, 103.1],
                           [105.3, 106.1, 104.9]])

march_prices = np.array([[106.5, 107.2, 105.8],
                        [107.0, 108.5, 106.1],
                        [108.3, 109.1, 107.9]])

print("一月价格数据形状:", january_prices.shape)
print("二月价格数据形状:", february_prices.shape)
print("三月价格数据形状:", march_prices.shape)

# 垂直堆叠三个月份的数据
all_prices = np.vstack((january_prices, february_prices, march_prices))
print("\n合并后的价格数据形状:", all_prices.shape)
print("总共有", all_prices.shape[0], "天的价格数据")

高级技巧和最佳实践 🎯

掌握一些高级技巧可以让我们的代码更加高效和优雅。

性能优化技巧

当处理大量数组时,合理选择堆叠方法可以显著提升性能:

import numpy as np
import time

# 创建测试数据
arrays = [np.random.rand(1000, 100) for _ in range(10)]

# 方法1: 逐个堆叠
start_time = time.time()
result1 = arrays[0]
for arr in arrays[1:]:
    result1 = np.vstack((result1, arr))
time1 = time.time() - start_time

# 方法2: 一次性堆叠
start_time = time.time()
result2 = np.vstack(arrays)
time2 = time.time() - start_time

print(f"逐个堆叠耗时: {time1:.4f} 秒")
print(f"一次性堆叠耗时: {time2:.4f} 秒")
print(f"性能提升: {time1/time2:.2f} 倍")

错误处理和调试

在实际应用中,良好的错误处理机制非常重要:

import numpy as np

def safe_hstack(*arrays):
    """
    安全的水平堆叠函数,包含错误检查
    """
    if not arrays:
        raise ValueError("至少需要一个数组")
    
    try:
        # 检查数组是否为空
        for i, arr in enumerate(arrays):
            if arr.size == 0:
                print(f"警告: 第{i}个数组为空")
        
        # 执行堆叠
        result = np.hstack(arrays)
        return result
    
    except ValueError as e:
        print(f"堆叠失败: {e}")
        print("请检查数组的维度是否兼容")
        return None

# 测试安全堆叠函数
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
arr3 = np.array([[9], [10]])  # 维度不匹配

result = safe_hstack(arr1, arr2)
if result is not None:
    print("成功堆叠:")
    print(result)

result = safe_hstack(arr1, arr3)
if result is not None:
    print("成功堆叠:")
    print(result)

内存管理考虑

处理大型数组时,内存使用是一个重要考虑因素:

import numpy as np

# 创建大型数组
large_arrays = [np.random.rand(10000, 1000) for _ in range(5)]

print("每个数组的内存占用:", large_arrays[0].nbytes / (1024**2), "MB")
print("总内存需求:", len(large_arrays) * large_arrays[0].nbytes / (1024**2), "MB")

# 使用 delete 删除原始数组以释放内存(如果不再需要)
# 注意:这只是示例,在实际应用中要谨慎使用
# del large_arrays

# 更好的做法是使用生成器或分批处理
def process_arrays_in_batches(arrays, batch_size=2):
    """分批处理大型数组"""
    for i in range(0, len(arrays), batch_size):
        batch = arrays[i:i+batch_size]
        yield np.hstack(batch)

# 分批处理示例
small_arrays = [np.random.rand(100, 10) for _ in range(6)]
for i, batch_result in enumerate(process_arrays_in_batches(small_arrays, 3)):
    print(f"批次 {i+1} 处理完成,形状: {batch_result.shape}")

与其他堆叠函数的比较 ⚖️

NumPy 提供了多种堆叠函数,了解它们的区别有助于选择最适合的方法。

stack vs hstack/vstack

import numpy as np

# 创建示例数组
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

print("原始数组 a:", a)
print("原始数组 b:", b)

# 使用 stack(默认沿新轴堆叠)
stacked_new_axis = np.stack((a, b))
print("\n使用 stack 的结果:")
print(stacked_new_axis)
print("形状:", stacked_new_axis.shape)

# 使用 vstack(沿现有轴0堆叠)
vstacked = np.vstack((a, b))
print("\n使用 vstack 的结果:")
print(vstacked)
print("形状:", vstacked.shape)

# 使用 hstack(沿现有轴1堆叠)
hstacked = np.hstack((a, b))
print("\n使用 hstack 的结果:")
print(hstacked)
print("形状:", hstacked.shape)

concatenate 函数的灵活性

concatenate 是最通用的连接函数,可以指定任意轴进行连接:

import numpy as np

# 创建三维数组
arr1 = np.random.rand(2, 3, 4)
arr2 = np.random.rand(2, 3, 4)

print("数组1形状:", arr1.shape)
print("数组2形状:", arr2.shape)

# 沿不同轴连接
concat_axis0 = np.concatenate((arr1, arr2), axis=0)
print("\n沿轴0连接后形状:", concat_axis0.shape)

concat_axis1 = np.concatenate((arr1, arr2), axis=1)
print("沿轴1连接后形状:", concat_axis1.shape)

concat_axis2 = np.concatenate((arr1, arr2), axis=2)
print("沿轴2连接后形状:", concat_axis2.shape)

# 等价关系
print("\n验证等价性:")
print("np.vstack 等价于 np.concatenate(axis=0):", 
      np.array_equal(np.vstack((arr1, arr2)), concat_axis0))

print("np.hstack 等价于 np.concatenate(axis=1) 对于2D数组:", 
      np.array_equal(np.hstack((arr1[:, 0, :], arr2[:, 0, :])), 
                   np.concatenate((arr1[:, 0, :], arr2[:, 0, :]), axis=1)))

实战案例分析 📈

让我们通过几个实战案例来深入理解这些函数的应用。

案例1: 构建机器学习特征矩阵

在构建机器学习模型时,经常需要将不同类型的数据特征组合成一个完整的特征矩阵:

import numpy as np

class FeatureBuilder:
    """特征构建器类"""
    
    def __init__(self):
        self.features = []
    
    def add_numerical_features(self, data):
        """添加数值型特征"""
        if isinstance(data, list):
            data = np.array(data)
        if data.ndim == 1:
            data = data.reshape(-1, 1)
        self.features.append(data)
        return self
    
    def add_categorical_features(self, data, one_hot_encoded=True):
        """添加分类特征"""
        if isinstance(data, list):
            data = np.array(data)
        if data.ndim == 1 and one_hot_encoded:
            # 这里简化处理,实际应用中应该使用 sklearn 的 OneHotEncoder
            unique_vals = np.unique(data)
            encoded = np.zeros((len(data), len(unique_vals)))
            for i, val in enumerate(unique_vals):
                encoded[data == val, i] = 1
            data = encoded
        elif data.ndim == 1:
            data = data.reshape(-1, 1)
        self.features.append(data)
        return self
    
    def build(self):
        """构建最终的特征矩阵"""
        if not self.features:
            raise ValueError("没有添加任何特征")
        return np.hstack(self.features)

# 使用示例
builder = FeatureBuilder()

# 添加数值型特征
age_data = [25, 30, 35, 28, 42]
income_data = [50000, 75000, 100000, 60000, 120000]

builder.add_numerical_features(age_data)
builder.add_numerical_features(income_data)

# 添加分类特征
gender_data = ['M', 'F', 'M', 'F', 'M']
city_data = ['NYC', 'LA', 'Chicago', 'NYC', 'Boston']

# 这里简化处理,实际应用中应该使用 proper encoding
gender_encoded = np.array([[1, 0], [0, 1], [1, 0], [0, 1], [1, 0]])  # M/F 编码
city_encoded = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 0, 0], [0, 0, 1]])  # 城市编码

builder.features.append(gender_encoded)
builder.features.append(city_encoded)

# 构建特征矩阵
feature_matrix = builder.build()
print("特征矩阵:")
print(feature_matrix)
print("特征矩阵形状:", feature_matrix.shape)
print("特征名称: Age, Income, Gender_M, Gender_F, City_NYC, City_LA, City_Chicago")

案例2: 数据聚合和统计分析

在数据分析中,经常需要将来自不同源的数据进行聚合:

import numpy as np

class DataAggregator:
    """数据聚合器"""
    
    def __init__(self):
        self.datasets = []
    
    def add_dataset(self, data, name):
        """添加数据集"""
        if isinstance(data, list):
            data = np.array(data)
        self.datasets.append({'data': data, 'name': name})
        return self
    
    def aggregate_by_rows(self):
        """按行聚合(垂直堆叠)"""
        if not self.datasets:
            raise ValueError("没有数据集")
        
        data_arrays = [ds['data'] for ds in self.datasets]
        aggregated = np.vstack(data_arrays)
        
        print("数据聚合信息:")
        for i, ds in enumerate(self.datasets):
            shape = ds['data'].shape
            print(f"  {ds['name']}: {shape[0]} 行, {shape[1] if len(shape) > 1 else 1} 列")
        
        return aggregated
    
    def combine_features(self):
        """按列组合(水平堆叠)"""
        if not self.datasets:
            raise ValueError("没有数据集")
        
        data_arrays = [ds['data'] for ds in self.datasets]
        combined = np.hstack(data_arrays)
        
        print("特征组合信息:")
        for i, ds in enumerate(self.datasets):
            shape = ds['data'].shape
            print(f"  {ds['name']}: {shape[1] if len(shape) > 1 else 1} 个特征")
        
        return combined

# 模拟销售数据
sales_q1 = np.array([[100, 200, 150],
                     [120, 180, 160],
                     [110, 220, 140]])

sales_q2 = np.array([[130, 210, 170],
                     [140, 190, 180],
                     [120, 230, 150]])

sales_q3 = np.array([[150, 240, 190],
                     [160, 200, 200],
                     [130, 250, 160]])

# 按季度聚合数据
aggregator = DataAggregator()
aggregator.add_dataset(sales_q1, "Q1 Sales").add_dataset(sales_q2, "Q2 Sales").add_dataset(sales_q3, "Q3 Sales")

quarterly_data = aggregator.aggregate_by_rows()
print("\n季度聚合数据:")
print(quarterly_data)
print("聚合后形状:", quarterly_data.shape)

# 按产品线组合特征
product_a_sales = sales_q1[:, 0:1]  # 第一列
product_b_sales = sales_q1[:, 1:2]  # 第二列
product_c_sales = sales_q1[:, 2:3]  # 第三列

feature_aggregator = DataAggregator()
feature_aggregator.add_dataset(product_a_sales, "Product A").add_dataset(product_b_sales, "Product B").add_dataset(product_c_sales, "Product C")

combined_features = feature_aggregator.combine_features()
print("\n组合特征数据:")
print(combined_features)
print("组合后形状:", combined_features.shape)

性能基准测试 📊

为了更好地理解不同方法的性能差异,让我们进行一些基准测试:

import numpy as np
import time
import matplotlib.pyplot as plt

def benchmark_stacking_methods():
    """基准测试不同的堆叠方法"""
    
    # 测试不同规模的数据
    sizes = [100, 500, 1000, 2000]
    hstack_times = []
    vstack_times = []
    concatenate_times = []
    
    for size in sizes:
        # 创建测试数组
        arrays_h = [np.random.rand(size, 50) for _ in range(10)]
        arrays_v = [np.random.rand(50, size) for _ in range(10)]
        
        # 测试 hstack
        start = time.time()
        result_h = np.hstack(arrays_h)
        hstack_times.append(time.time() - start)
        
        # 测试 vstack
        start = time.time()
        result_v = np.vstack(arrays_v)
        vstack_times.append(time.time() - start)
        
        # 测试 concatenate
        start = time.time()
        result_c = np.concatenate(arrays_h, axis=1)
        concatenate_times.append(time.time() - start)
    
    return sizes, hstack_times, vstack_times, concatenate_times

# 运行基准测试
sizes, h_times, v_times, c_times = benchmark_stacking_methods()

print("性能基准测试结果:")
print("数组大小\tHStack(s)\tVStack(s)\tConcat(s)")
for i, size in enumerate(sizes):
    print(f"{size}\t\t{h_times[i]:.6f}\t{v_times[i]:.6f}\t{c_times[i]:.6f}")

# 可视化结果
plt.figure(figsize=(10, 6))
plt.plot(sizes, h_times, 'o-', label='hstack')
plt.plot(sizes, v_times, 's-', label='vstack')
plt.plot(sizes, c_times, '^-', label='concatenate')
plt.xlabel('数组大小')
plt.ylabel('执行时间 (秒)')
plt.title('不同堆叠方法的性能比较')
plt.legend()
plt.grid(True)
plt.show()

常见问题和解决方案 ❓

在使用 hstack 和 vstack 时,可能会遇到一些常见问题,让我们来看看如何解决它们。

问题1: 维度不匹配

import numpy as np

def fix_dimension_mismatch():
    """解决维度不匹配问题"""
    
    # 问题示例
    arr1 = np.array([[1, 2, 3], [4, 5, 6]])  # 2x3
    arr2 = np.array([7, 8])                  # 1D array
    
    print("原始数组:")
    print("arr1 shape:", arr1.shape)
    print("arr2 shape:", arr2.shape)
    
    try:
        result = np.hstack((arr1, arr2))
    except ValueError as e:
        print(f"\n错误: {e}")
        print("解决方法1: 调整数组维度")
        
        # 解决方案1: 扩展 arr2 的维度
        arr2_reshaped = arr2.reshape(-1, 1)  # 变为 2x1
        result1 = np.hstack((arr1, arr2_reshaped))
        print("调整后 arr2 shape:", arr2_reshaped.shape)
        print("hstack 结果:")
        print(result1)
        
        print("\n解决方法2: 使用 concatenate 并指定合适的轴")
        arr2_broadcast = np.broadcast_to(arr2.reshape(-1, 1), (2, 1))
        result2 = np.concatenate((arr1, arr2_broadcast), axis=1)
        print("concatenate 结果:")
        print(result2)

fix_dimension_mismatch()

问题2: 内存不足

import numpy as np
import psutil
import os

def memory_efficient_stacking():
    """内存高效的堆叠方法"""
    
    # 获取当前内存使用情况
    def get_memory_usage():
        process = psutil.Process(os.getpid())
        return process.memory_info().rss / 1024 / 1024  # MB
    
    print(f"初始内存使用: {get_memory_usage():.2f} MB")
    
    # 创建大数组
    big_arrays = []
    for i in range(5):
        arr = np.random.rand(10000, 1000)
        big_arrays.append(arr)
        print(f"创建第{i+1}个数组后内存: {get_memory_usage():.2f} MB")
    
    # 内存高效的堆叠方式
    print("\n开始堆叠...")
    start_mem = get_memory_usage()
    
    # 方法1: 直接堆叠(可能消耗大量内存)
    result_direct = np.vstack(big_arrays)
    end_mem = get_memory_usage()
    print(f"直接堆叠后内存增加: {end_mem - start_mem:.2f} MB")
    print(f"结果形状: {result_direct.shape}")
    
    # 清理内存
    del result_direct
    import gc
    gc.collect()
    
    # 方法2: 分批处理
    def batch_stack(arrays, batch_size=2):
        """分批堆叠以节省内存"""
        results = []
        for i in range(0, len(arrays), batch_size):
            batch = arrays[i:i+batch_size]
            batch_result = np.vstack(batch)
            results.append(batch_result)
        return np.vstack(results)
    
    print("\n使用分批处理...")
    start_mem = get_memory_usage()
    result_batch = batch_stack(big_arrays, batch_size=2)
    end_mem = get_memory_usage()
    print(f"分批处理后内存增加: {end_mem - start_mem:.2f} MB")
    print(f"结果形状: {result_batch.shape}")

# memory_efficient_stacking()  # 注释掉避免运行时间过长

最佳实践总结 ✅

基于前面的学习和实践,总结出以下最佳实践:

设计模式和架构建议

import numpy as np
from typing import List, Union, Optional

class ArrayStacker:
    """数组堆叠器 - 封装最佳实践"""
    
    @staticmethod
    def safe_hstack(arrays: List[np.ndarray], 
                   validate_shapes: bool = True,
                   fill_value: Optional[float] = None) -> np.ndarray:
        """
        安全的水平堆叠
        
        Parameters:
        -----------
        arrays : List[np.ndarray]
            要堆叠的数组列表
        validate_shapes : bool
            是否验证形状兼容性
        fill_value : float, optional
            用于填充不匹配维度的值
            
        Returns:
        --------
        np.ndarray
            堆叠后的数组
        """
        if not arrays:
            raise ValueError("数组列表不能为空")
        
        if len(arrays) == 1:
            return arrays[0]
        
        if validate_shapes:
            # 验证除最后一维外的所有维度是否匹配
            base_shape = arrays[0].shape[:-1] if arrays[0].ndim > 1 else ()
            for i, arr in enumerate(arrays[1:], 1):
                current_shape = arr.shape[:-1] if arr.ndim > 1 else ()
                if base_shape != current_shape:
                    if fill_value is not None:
                        # 尝试自动调整
                        arrays = ArrayStacker._adjust_dimensions(arrays, fill_value)
                    else:
                        raise ValueError(f"数组 {i} 的形状 {current_shape} 与基础形状 {base_shape} 不匹配")
        
        return np.hstack(arrays)
    
    @staticmethod
    def safe_vstack(arrays: List[np.ndarray],
                   validate_shapes: bool = True) -> np.ndarray:
        """
        安全的垂直堆叠
        """
        if not arrays:
            raise ValueError("数组列表不能为空")
        
        if len(arrays) == 1:
            return arrays[0]
        
        if validate_shapes:
            # 验证除第一维外的所有维度是否匹配
            base_shape = arrays[0].shape[1:] if arrays[0].ndim > 1 else ()
            for i, arr in enumerate(arrays[1:], 1):
                current_shape = arr.shape[1:] if arr.ndim > 1 else ()
                if base_shape != current_shape:
                    raise ValueError(f"数组 {i} 的形状 {current_shape} 与基础形状 {base_shape} 不匹配")
        
        return np.vstack(arrays)
    
    @staticmethod
    def _adjust_dimensions(arrays: List[np.ndarray], fill_value: float) -> List[np.ndarray]:
        """调整数组维度以使其兼容"""
        # 找到最大的维度
        max_dims = max(arr.ndim for arr in arrays)
        
        adjusted_arrays = []
        for arr in arrays:
            if arr.ndim < max_dims:
                # 增加维度
                new_arr = np.expand_dims(arr, axis=tuple(range(max_dims - arr.ndim)))
                adjusted_arrays.append(new_arr)
            else:
                adjusted_arrays.append(arr)
        
        return adjusted_arrays

# 使用示例
stacker = ArrayStacker()

# 正常情况
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
result = stacker.safe_hstack([arr1, arr2])
print("正常堆叠结果:")
print(result)

# 自动调整维度的情况
arr3 = np.array([1, 2, 3])  # 1D
arr4 = np.array([[4, 5, 6]])  # 2D
try:
    result = stacker.safe_hstack([arr3, arr4], fill_value=0)
    print("\n自动调整维度后堆叠结果:")
    print(result)
except Exception as e:
    print(f"错误: {e}")

性能优化指南

import numpy as np
import time
from functools import wraps

def timing_decorator(func):
    """计时装饰器"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 执行时间: {end - start:.6f} 秒")
        return result
    return wrapper

class PerformanceOptimizer:
    """性能优化器"""
    
    @staticmethod
    @timing_decorator
    def inefficient_method(arrays):
        """低效的方法:逐个堆叠"""
        result = arrays[0]
        for arr in arrays[1:]:
            result = np.vstack((result, arr))
        return result
    
    @staticmethod
    @timing_decorator
    def efficient_method(arrays):
        """高效的方法:一次性堆叠"""
        return np.vstack(arrays)
    
    @staticmethod
    @timing_decorator
    def preallocate_method(arrays):
        """预分配内存的方法"""
        total_rows = sum(arr.shape[0] for arr in arrays)
        cols = arrays[0].shape[1]
        result = np.empty((total_rows, cols), dtype=arrays[0].dtype)
        
        current_row = 0
        for arr in arrays:
            next_row = current_row + arr.shape[0]
            result[current_row:next_row, :] = arr
            current_row = next_row
        
        return result

# 性能测试
test_arrays = [np.random.rand(1000, 100) for _ in range(10)]

print("性能比较测试:")
result1 = PerformanceOptimizer.inefficient_method(test_arrays)
result2 = PerformanceOptimizer.efficient_method(test_arrays)
result3 = PerformanceOptimizer.preallocate_method(test_arrays)

# 验证结果一致性
print("结果一致性检查:")
print("方法1和方法2相同:", np.array_equal(result1, result2))
print("方法2和方法3相同:", np.array_equal(result2, result3))

相关资源推荐 📚

为了进一步深入学习 NumPy 和相关的数组操作,推荐以下几个优秀的学习资源:

  1. NumPy 官方文档 - 最权威的参考资料,包含了所有函数的详细说明和示例。

  2. SciPy Lecture Notes - 免费的科学计算教程,涵盖了 NumPy、SciPy、Matplotlib 等库的综合使用。

  3. Python Data Science Handbook - Jake VanderPlas 的经典著作,在线免费阅读,深入介绍了数据科学中的各种技术。

这些资源提供了从基础到高级的各种内容,适合不同层次的学习者。

总结 🎉

通过本文的详细介绍,我们深入了解了 NumPy 中 hstack 和 vstack 函数的强大功能和实际应用。这两个函数虽然看似简单,但在数据处理、机器学习、科学计算等领域发挥着重要作用。

关键要点回顾:

  1. hstack 用于水平堆叠(按列连接),适用于特征维度的扩展
  2. vstack 用于垂直堆叠(按行连接),适用于样本数量的增加
  3. 在使用前要注意数组维度的兼容性
  4. 合理选择堆叠方法可以显著提升性能
  5. 实际应用中要考虑内存管理和错误处理

学习建议:

  • 从简单的一维数组开始练习,逐步过渡到复杂多维数组
  • 在实际项目中多实践,积累经验
  • 关注性能优化,特别是在处理大数据集时
  • 学会使用相关的调试和错误处理技巧

NumPy 的数组堆叠功能只是其强大功能的一个方面。随着你对 NumPy 的深入了解,你会发现更多有趣和实用的功能,帮助你在数据科学的道路上走得更远。记住,编程是一门实践的艺术,只有通过不断的练习和应用,才能真正掌握这些工具的力量。


🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/qq_41187124/article/details/157774860

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--