当前位置: 代码网 > it编程>前端脚本>Python > Python NumPy中数组的读取与加载详解

Python NumPy中数组的读取与加载详解

2026年09月03日 Python 我要评论
在科学计算和数据分析的世界中,numpy 作为 python 生态系统中最基础且最重要的库之一,为我们提供了强大的多维数组对象和丰富的数学函数。当我们处理大量数值数据时,如何高效地保存和加载这些数据就

在科学计算和数据分析的世界中,numpy 作为 python 生态系统中最基础且最重要的库之一,为我们提供了强大的多维数组对象和丰富的数学函数。当我们处理大量数值数据时,如何高效地保存和加载这些数据就成为了一个关键问题。今天,我们就来深入探讨 numpy 中最核心的数据持久化功能——npy 格式文件的读取与加载。

什么是 npy 格式?

npy 是 numpy 专门为存储数组数据而设计的二进制文件格式。这种格式具有以下显著优势:

  • 高效性:以二进制形式存储,读写速度快
  • 完整性:保存完整的数组元数据,包括形状、数据类型等信息
  • 兼容性:跨平台支持,可在不同操作系统间共享
  • 压缩性:支持压缩存储,节省磁盘空间
import numpy as np

# 创建一个示例数组
sample_array = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32)
print("原始数组:")
print(sample_array)
print(f"数组形状: {sample_array.shape}")
print(f"数据类型: {sample_array.dtype}")

# 保存为 npy 文件
np.save('sample_data.npy', sample_array)
print("✅ 数据已保存为 sample_data.npy")

基础保存操作:np.save()

np.save() 函数是保存单个数组到 npy 文件的标准方法。让我们通过一些实际例子来理解它的用法:

import numpy as np

# 示例1:保存一维数组
arr_1d = np.linspace(0, 10, 5)
np.save('array_1d.npy', arr_1d)
print("一维数组保存完成")

# 示例2:保存二维数组
arr_2d = np.random.rand(3, 4)
np.save('array_2d.npy', arr_2d)
print("二维数组保存完成")

# 示例3:保存三维数组
arr_3d = np.arange(24).reshape(2, 3, 4)
np.save('array_3d.npy', arr_3d)
print("三维数组保存完成")

# 示例4:保存复数数组
complex_arr = np.array([1+2j, 3+4j, 5+6j])
np.save('complex_array.npy', complex_arr)
print("复数数组保存完成")

基础加载操作:np.load()

对应的 np.load() 函数用于从 npy 文件中加载数组数据:

import numpy as np

# 加载之前保存的一维数组
loaded_1d = np.load('array_1d.npy')
print("加载的一维数组:")
print(loaded_1d)

# 加载二维数组
loaded_2d = np.load('array_2d.npy')
print("\n加载的二维数组:")
print(loaded_2d)

# 加载三维数组
loaded_3d = np.load('array_3d.npy')
print("\n加载的三维数组:")
print(loaded_3d)

# 加载复数数组
loaded_complex = np.load('complex_array.npy')
print("\n加载的复数数组:")
print(loaded_complex)

高级用法:使用上下文管理器

为了更好地管理文件资源,我们可以使用 np.load() 的返回值作为上下文管理器:

import numpy as np

# 保存一个大型数组
large_array = np.random.rand(1000, 1000)
np.save('large_array.npy', large_array)

# 使用上下文管理器加载
with np.load('large_array.npy') as data:
    print(f"数组形状: {data.shape}")
    print(f"前5个元素: {data.flat[:5]}")
    # 在这里进行数据处理...

print("✅ 上下文管理器自动关闭文件句柄")

批量保存与加载:np.savez()

当需要同时保存多个数组时,np.savez() 提供了便利的方法:

import numpy as np

# 创建多个相关数组
temperature = np.array([20, 22, 25, 23, 21])
humidity = np.array([45, 50, 55, 48, 47])
pressure = np.array([1013, 1015, 1012, 1014, 1016])

# 同时保存多个数组
np.savez('weather_data.npz', 
         temp=temperature, 
         humid=humidity, 
         press=pressure)

print("✅ 多个数组已打包保存")

# 加载并查看内容
loaded_weather = np.load('weather_data.npz')
print(f"包含的键: {list(loaded_weather.keys())}")
print(f"温度数据: {loaded_weather['temp']}")
print(f"湿度数据: {loaded_weather['humid']}")
print(f"气压数据: {loaded_weather['press']}")

压缩存储:np.savez_compressed()

对于大型数据集,使用压缩格式可以显著减少存储空间:

import numpy as np
import os

# 创建大型测试数据
big_data1 = np.random.rand(10000, 100)
big_data2 = np.random.rand(5000, 200)

# 普通保存
np.savez('uncompressed.npz', data1=big_data1, data2=big_data2)

# 压缩保存
np.savez_compressed('compressed.npz', data1=big_data1, data2=big_data2)

# 比较文件大小
size_uncompressed = os.path.getsize('uncompressed.npz')
size_compressed = os.path.getsize('compressed.npz')

print(f"未压缩文件大小: {size_uncompressed / (1024*1024):.2f} mb")
print(f"压缩文件大小: {size_compressed / (1024*1024):.2f} mb")
print(f"压缩率: {(1 - size_compressed/size_uncompressed)*100:.1f}%")

实际应用场景

科学实验数据管理

在科研工作中,数据的管理和复用非常重要:

import numpy as np

def save_experiment_data(experiment_name, time_series, measurements, parameters):
    """保存实验数据"""
    filename = f"{experiment_name}_data.npz"
    np.savez_compressed(filename,
                       time=time_series,
                       measurements=measurements,
                       parameters=parameters)
    print(f"实验数据已保存到 {filename}")

def load_experiment_data(experiment_name):
    """加载实验数据"""
    filename = f"{experiment_name}_data.npz"
    try:
        data = np.load(filename)
        return {
            'time': data['time'],
            'measurements': data['measurements'],
            'parameters': data['parameters']
        }
    except filenotfounderror:
        print(f"❌ 未找到实验数据文件: {filename}")
        return none

# 模拟实验数据
time_points = np.linspace(0, 10, 100)
voltage_measurements = np.sin(time_points) + np.random.normal(0, 0.1, 100)
exp_params = {'frequency': 50, 'amplitude': 1.0, 'offset': 0.0}

# 保存实验数据
save_experiment_data('oscilloscope_test', time_points, voltage_measurements, exp_params)

# 加载实验数据
loaded_data = load_experiment_data('oscilloscope_test')
if loaded_data:
    print("✅ 实验数据加载成功")
    print(f"时间点数量: {len(loaded_data['time'])}")
    print(f"测量参数: {loaded_data['parameters']}")

机器学习模型权重保存

在深度学习中,模型权重的保存和加载是训练过程的重要环节:

import numpy as np

class simpleneuralnetwork:
    def __init__(self, input_size, hidden_size, output_size):
        self.weights_input_hidden = np.random.randn(input_size, hidden_size) * 0.1
        self.weights_hidden_output = np.random.randn(hidden_size, output_size) * 0.1
        self.bias_hidden = np.zeros(hidden_size)
        self.bias_output = np.zeros(output_size)
    
    def save_weights(self, filename):
        """保存网络权重"""
        np.savez_compressed(filename,
                           w_ih=self.weights_input_hidden,
                           w_ho=self.weights_hidden_output,
                           b_h=self.bias_hidden,
                           b_o=self.bias_output)
        print(f"🧠 网络权重已保存到 {filename}")
    
    def load_weights(self, filename):
        """加载网络权重"""
        try:
            weights_data = np.load(filename)
            self.weights_input_hidden = weights_data['w_ih']
            self.weights_hidden_output = weights_data['w_ho']
            self.bias_hidden = weights_data['b_h']
            self.bias_output = weights_data['b_o']
            print(f"🧠 网络权重已从 {filename} 加载")
        except exception as e:
            print(f"❌ 权重加载失败: {e}")

# 创建神经网络实例
nn = simpleneuralnetwork(10, 20, 5)

# 保存权重
nn.save_weights('neural_network_weights.npz')

# 创建新实例并加载权重
new_nn = simpleneuralnetwork(10, 20, 5)
new_nn.load_weights('neural_network_weights.npz')

# 验证权重是否一致
print("权重一致性检查:")
print(f"输入到隐藏层权重一致: {np.allclose(nn.weights_input_hidden, new_nn.weights_input_hidden)}")
print(f"隐藏层到输出层权重一致: {np.allclose(nn.weights_hidden_output, new_nn.weights_hidden_output)}")

性能优化技巧

内存映射加载

对于超大文件,可以使用内存映射技术避免一次性加载所有数据:

import numpy as np
import time

# 创建一个大型数组
large_array = np.random.rand(10000, 10000)  # 约 800mb
np.save('huge_array.npy', large_array)

# 普通加载方式
start_time = time.time()
normal_load = np.load('huge_array.npy')
normal_time = time.time() - start_time
print(f"普通加载耗时: {normal_time:.3f} 秒")

# 内存映射加载方式
start_time = time.time()
mmap_load = np.load('huge_array.npy', mmap_mode='r')  # 只读模式
mmap_time = time.time() - start_time
print(f"内存映射加载耗时: {mmap_time:.3f} 秒")

# 访问部分数据
print(f"数组形状: {mmap_load.shape}")
print(f"前10个元素: {mmap_load.flat[:10]}")

# 清理文件
import os
os.remove('huge_array.npy')

分块处理大数据

当处理超出内存限制的数据时,分块处理是一种有效的策略:

import numpy as np

def process_large_array_in_chunks(filename, chunk_size=1000):
    """分块处理大型数组"""
    # 先获取数组基本信息
    with np.load(filename, mmap_mode='r') as data:
        total_rows = data.shape[0]
        print(f"总行数: {total_rows}")
        
        # 分块处理
        for i in range(0, total_rows, chunk_size):
            end_idx = min(i + chunk_size, total_rows)
            chunk = data[i:end_idx]
            
            # 对每个块进行处理(这里是简单的统计)
            chunk_mean = np.mean(chunk)
            chunk_std = np.std(chunk)
            
            print(f"块 {i//chunk_size + 1}: 行 {i}-{end_idx-1}, "
                  f"均值={chunk_mean:.4f}, 标准差={chunk_std:.4f}")

# 创建测试数据
test_data = np.random.randn(5000, 100)
np.save('test_large_array.npy', test_data)

# 分块处理
process_large_array_in_chunks('test_large_array.npy', chunk_size=1000)

# 清理
import os
os.remove('test_large_array.npy')

错误处理与调试

在实际应用中,完善的错误处理机制是必不可少的:

import numpy as np
import os

def safe_save_array(array, filename):
    """安全保存数组"""
    try:
        np.save(filename, array)
        print(f"✅ 数组成功保存到 {filename}")
        return true
    except permissionerror:
        print(f"❌ 权限不足,无法保存到 {filename}")
        return false
    except oserror as e:
        print(f"❌ 系统错误: {e}")
        return false
    except exception as e:
        print(f"❌ 未知错误: {e}")
        return false

def safe_load_array(filename):
    """安全加载数组"""
    if not os.path.exists(filename):
        print(f"❌ 文件不存在: {filename}")
        return none
    
    try:
        array = np.load(filename)
        print(f"✅ 成功加载数组,形状: {array.shape}, 类型: {array.dtype}")
        return array
    except valueerror as e:
        print(f"❌ 文件格式错误: {e}")
        return none
    except memoryerror:
        print("❌ 内存不足,尝试使用内存映射加载")
        try:
            return np.load(filename, mmap_mode='r')
        except exception as e:
            print(f"❌ 内存映射加载也失败: {e}")
            return none
    except exception as e:
        print(f"❌ 加载过程中发生未知错误: {e}")
        return none

# 测试错误处理
test_array = np.random.rand(100, 50)

# 正常保存和加载
safe_save_array(test_array, 'test_safe.npy')
loaded_array = safe_load_array('test_safe.npy')
if loaded_array is not none:
    print(f"数据一致性检查: {np.array_equal(test_array, loaded_array)}")

# 测试不存在的文件
safe_load_array('nonexistent.npy')

# 清理
os.remove('test_safe.npy')

跨平台兼容性考虑

在不同的操作系统和环境中工作时,需要注意一些兼容性问题:

import numpy as np
import sys
import platform

def check_npy_compatibility():
    """检查当前环境的 npy 兼容性"""
    print("🔧 系统信息:")
    print(f"操作系统: {platform.system()} {platform.release()}")
    print(f"python 版本: {sys.version}")
    print(f"numpy 版本: {np.__version__}")
    
    # 创建测试数组
    test_arrays = {
        'int8': np.array([1, 2, 3], dtype=np.int8),
        'uint64': np.array([1, 2, 3], dtype=np.uint64),
        'float32': np.array([1.1, 2.2, 3.3], dtype=np.float32),
        'complex128': np.array([1+2j, 3+4j], dtype=np.complex128),
        'bool': np.array([true, false, true], dtype=bool)
    }
    
    # 测试各种数据类型的保存和加载
    for name, arr in test_arrays.items():
        filename = f'test_{name}.npy'
        try:
            np.save(filename, arr)
            loaded = np.load(filename)
            is_consistent = np.array_equal(arr, loaded) or np.allclose(arr, loaded, equal_nan=true)
            print(f"✅ {name:>12} 类型: {'✓' if is_consistent else '✗'}")
            
            # 清理临时文件
            import os
            os.remove(filename)
        except exception as e:
            print(f"❌ {name:>12} 类型: 错误 - {e}")

check_npy_compatibility()

实际案例:图像数据处理

让我们看一个更贴近实际应用的例子——处理和保存图像数据:

import numpy as np

def create_sample_image(height=100, width=100, channels=3):
    """创建示例图像数据"""
    # 创建随机彩色图像
    image = np.random.randint(0, 256, (height, width, channels), dtype=np.uint8)
    return image

def save_image_dataset(image_list, labels, dataset_name):
    """保存图像数据集"""
    filename = f"{dataset_name}.npz"
    np.savez_compressed(filename, images=image_list, labels=labels)
    print(f"🖼️ 图像数据集已保存: {filename}")

def load_image_dataset(dataset_name):
    """加载图像数据集"""
    filename = f"{dataset_name}.npz"
    try:
        data = np.load(filename)
        return data['images'], data['labels']
    except exception as e:
        print(f"❌ 加载图像数据集失败: {e}")
        return none, none

# 创建示例图像数据集
num_images = 10
image_height, image_width = 64, 64

images = np.array([create_sample_image(image_height, image_width) 
                   for _ in range(num_images)])
labels = np.random.randint(0, 5, num_images)  # 5类分类任务

print(f"创建了 {len(images)} 张图像")
print(f"每张图像尺寸: {images[0].shape}")
print(f"标签范围: {np.min(labels)} 到 {np.max(labels)}")

# 保存数据集
save_image_dataset(images, labels, 'sample_image_dataset')

# 加载数据集
loaded_images, loaded_labels = load_image_dataset('sample_image_dataset')
if loaded_images is not none:
    print(f"✅ 成功加载 {len(loaded_images)} 张图像")
    print(f"图像形状验证: {loaded_images[0].shape}")
    print(f"标签一致性: {np.array_equal(labels, loaded_labels)}")

高级特性探索

自定义对象序列化

虽然 npy 主要用于数组,但我们可以通过一些技巧保存自定义结构:

import numpy as np
import pickle

def save_custom_object(obj, filename):
    """保存自定义对象到 npy 格式"""
    # 将对象序列化为字节流
    serialized_obj = pickle.dumps(obj)
    
    # 转换为 numpy 数组保存
    byte_array = np.frombuffer(serialized_obj, dtype=np.uint8)
    np.save(filename, byte_array)
    print(f"📦 自定义对象已保存到 {filename}")

def load_custom_object(filename):
    """从 npy 文件加载自定义对象"""
    try:
        byte_array = np.load(filename)
        serialized_obj = byte_array.tobytes()
        obj = pickle.loads(serialized_obj)
        print(f"📦 自定义对象已从 {filename} 加载")
        return obj
    except exception as e:
        print(f"❌ 加载自定义对象失败: {e}")
        return none

# 测试自定义对象保存
class person:
    def __init__(self, name, age, hobbies):
        self.name = name
        self.age = age
        self.hobbies = hobbies
    
    def __repr__(self):
        return f"person(name='{self.name}', age={self.age}, hobbies={self.hobbies})"

# 创建测试对象
person = person("alice", 30, ["reading", "swimming", "coding"])

# 保存和加载
save_custom_object(person, 'person_data.npy')
loaded_person = load_custom_object('person_data.npy')

if loaded_person:
    print(f"原始对象: {person}")
    print(f"加载对象: {loaded_person}")
    print(f"对象一致性: {person.name == loaded_person.name and person.age == loaded_person.age}")

版本控制和元数据管理

在生产环境中,版本控制和元数据管理非常重要:

import numpy as np
import datetime
import json

def save_array_with_metadata(array, filename, metadata=none):
    """保存数组并附加元数据"""
    if metadata is none:
        metadata = {}
    
    # 添加基本元数据
    metadata.update({
        'creation_time': datetime.datetime.now().isoformat(),
        'array_shape': array.shape,
        'array_dtype': str(array.dtype),
        'numpy_version': np.__version__
    })
    
    # 序列化元数据
    metadata_json = json.dumps(metadata)
    
    # 保存数组和元数据
    np.savez_compressed(filename, 
                       data=array, 
                       metadata=np.array(metadata_json, dtype='u{}'.format(len(metadata_json))))
    
    print(f"📊 数组和元数据已保存到 {filename}")

def load_array_with_metadata(filename):
    """加载数组及其元数据"""
    try:
        data = np.load(filename)
        array = data['data']
        
        # 解析元数据
        metadata_json = str(data['metadata'].item())
        metadata = json.loads(metadata_json)
        
        print(f"📊 从 {filename} 加载数据:")
        print(f"   创建时间: {metadata.get('creation_time', 'n/a')}")
        print(f"   数组形状: {metadata.get('array_shape', 'n/a')}")
        print(f"   数据类型: {metadata.get('array_dtype', 'n/a')}")
        
        return array, metadata
    except exception as e:
        print(f"❌ 加载失败: {e}")
        return none, none

# 测试带元数据的保存
test_array = np.random.rand(100, 50)
custom_metadata = {
    'project': 'data analysis project',
    'author': 'data scientist',
    'description': 'sample numerical data for analysis',
    'version': '1.0.0'
}

save_array_with_metadata(test_array, 'data_with_metadata.npz', custom_metadata)
loaded_array, loaded_metadata = load_array_with_metadata('data_with_metadata.npz')

if loaded_array is not none:
    print(f"数据一致性检查: {np.array_equal(test_array, loaded_array)}")

最佳实践总结

基于以上讨论,以下是使用 numpy 进行数据持久化的最佳实践:

性能优化建议

import numpy as np
import time

def benchmark_saving_methods():
    """比较不同保存方法的性能"""
    # 创建测试数据
    test_data = np.random.rand(1000, 1000)
    
    methods = [
        ('np.save (npy)', lambda: np.save('test.npy', test_data)),
        ('np.savez (npz)', lambda: np.savez('test.npz', data=test_data)),
        ('np.savez_compressed', lambda: np.savez_compressed('test_compressed.npz', data=test_data))
    ]
    
    results = []
    for name, method in methods:
        start_time = time.time()
        method()
        elapsed_time = time.time() - start_time
        results.append((name, elapsed_time))
    
    # 显示结果
    print("⏱️ 保存性能对比:")
    for name, time_taken in results:
        print(f"   {name}: {time_taken:.4f} 秒")

benchmark_saving_methods()

文件管理最佳实践

import numpy as np
import os
from pathlib import path

class numpydatamanager:
    """numpy 数据管理器"""
    
    def __init__(self, base_directory='./numpy_data'):
        self.base_dir = path(base_directory)
        self.base_dir.mkdir(exist_ok=true)
        print(f"📁 数据目录: {self.base_dir.absolute()}")
    
    def save_dataset(self, name, **arrays):
        """保存数据集"""
        filename = self.base_dir / f"{name}.npz"
        try:
            np.savez_compressed(filename, **arrays)
            file_size = filename.stat().st_size / (1024 * 1024)  # mb
            print(f"✅ 数据集 '{name}' 已保存 ({file_size:.2f} mb)")
            return true
        except exception as e:
            print(f"❌ 保存失败: {e}")
            return false
    
    def load_dataset(self, name):
        """加载数据集"""
        filename = self.base_dir / f"{name}.npz"
        if not filename.exists():
            print(f"❌ 数据集 '{name}' 不存在")
            return none
        
        try:
            data = np.load(filename)
            print(f"✅ 数据集 '{name}' 已加载")
            return dict(data)
        except exception as e:
            print(f"❌ 加载失败: {e}")
            return none
    
    def list_datasets(self):
        """列出所有数据集"""
        datasets = list(self.base_dir.glob('*.npz'))
        print(f"📋 找到 {len(datasets)} 个数据集:")
        for ds in datasets:
            size_mb = ds.stat().st_size / (1024 * 1024)
            print(f"   - {ds.stem} ({size_mb:.2f} mb)")

# 使用示例
manager = numpydatamanager('./my_project_data')

# 保存一些测试数据
test_data1 = np.random.rand(100, 50)
test_data2 = np.random.randint(0, 100, (200, 30))

manager.save_dataset('test_set', features=test_data1, targets=test_data2)
manager.list_datasets()

# 加载数据
loaded_data = manager.load_dataset('test_set')
if loaded_data:
    print(f"加载的数据键: {list(loaded_data.keys())}")

# 清理测试文件
import shutil
shutil.rmtree('./my_project_data')

结语

通过本文的详细介绍,我们全面了解了 numpy 中数组读取和加载的核心功能。从基础的 np.save()np.load(),到高级的压缩存储和批量处理,再到实际应用场景和最佳实践,相信你已经掌握了使用 npy 格式进行数据持久化的完整技能体系。

记住,选择合适的保存方式取决于你的具体需求:

  • 单个数组:使用 np.save()
  • 多个数组:使用 np.savez()
  • 大型数据:考虑压缩和内存映射
  • 生产环境:注重错误处理和元数据管理

掌握这些技巧,你就能在科学计算和数据分析项目中更加高效地管理和利用数据资源。

以上就是python numpy中数组的读取与加载详解的详细内容,更多关于python numpy数组读取与加载的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com