如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~

目录

函数简介

np.fromiter

np.array

测试代码

实验结果

结果分析

实验总结

学长想说


函数简介

np.fromiter

np.fromiter 是 NumPy 提供的一个函数,用于从可迭代对象(如生成器、列表等)创建一个 NumPy 数组。它直接从可迭代对象中逐个读取数据,适合在数据量较大或数据生成过程中节省内存的场景。

优点:

  • 内存效率高:从可迭代对象中逐个读取数据而不是一次性加载所有数据,适合处理大数据量。
  • 速度较快:在特定情况下(尤其是数据量大时),由于从迭代器逐个读取数据,可能比 np.array 更快。

缺点:

  • 适用于从迭代器或生成器创建数组,对于已经存在的 Python 序列(如列表、元组)不具备明显优势。

np.array

np.array 是 NumPy 最常用的函数之一,用于将输入数据(如列表、元组、嵌套序列等)转换为 NumPy 数组。它会一次性读取输入数据并将其存储到内存中的连续块中,适合在数据已经加载到内存中的场景。

优点:

  • 通用性强:可以从各种序列(如列表、元组等)或其他数组对象创建 NumPy 数组。
  • 易于使用:语法简单,使用场景广泛。

缺点:

  • 对于非常大的数据,可能需要一次性加载到内存中,内存消耗较大。
  • 处理生成器或迭代器时,性能可能不如 np.fromiter

测试代码

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

# 测试数据生成函数
def generate_data(size):
    return range(size)  # 使用生成器来模拟大量数据

# 测试 np.fromiter 的性能
def test_fromiter_int32(data):
    start_time = time.time()
    np.fromiter(data, dtype=np.int32)
    return time.time() - start_time

# 测试 np.array 的性能(不计算 list 开销)
def test_array_no_list_overhead(data):
    data = list(data)  # 先将生成器转换为列表
    start_time = time.time()
    np.array(data, dtype=np.int32)  # 确保 dtype 为 int32
    return time.time() - start_time

# 测试 np.array 的性能(计算 list 开销)
def test_array_with_list_overhead(data):
    start_time = time.time()
    data = list(data)  # 生成器转换为列表的时间也包含在内
    np.array(data, dtype=np.int32)  # 确保 dtype 为 int32
    return time.time() - start_time

# 数据量从 10^1 到 10^9
data_sizes = [10**i for i in range(1, 8)]  # 从 10^1 到 10^7
results_comparison = []

for size in data_sizes:
    data = generate_data(size)
    
    # np.fromiter 性能测试
    fromiter_time_int32 = test_fromiter_int32(data)
    
    # np.array 性能测试(不计算 list 开销)
    data = generate_data(size)  # 重新生成数据
    array_time_no_list_overhead = test_array_no_list_overhead(data)
    
    # np.array 性能测试(计算 list 开销)
    data = generate_data(size)  # 重新生成数据
    array_time_with_list_overhead = test_array_with_list_overhead(data)
    
    results_comparison.append((size, fromiter_time_int32, array_time_no_list_overhead, array_time_with_list_overhead))

# 将结果显示为数据框
df_results_comparison = pd.DataFrame(results_comparison, columns=[
    'Data Size', 'Fromiter Time (s)', 'Array Time without List Overhead (s)', 'Array Time with List Overhead (s)'
])

# 绘制比较性能曲线
plt.figure(figsize=(10, 6))
plt.plot(df_results_comparison['Data Size'], df_results_comparison['Fromiter Time (s)'], marker='o', label='np.fromiter (int32)')
plt.plot(df_results_comparison['Data Size'], df_results_comparison['Array Time without List Overhead (s)'], marker='o', label='np.array without list overhead (int32)')
plt.plot(df_results_comparison['Data Size'], df_results_comparison['Array Time with List Overhead (s)'], marker='o', label='np.array with list overhead (int32)')
plt.xlabel('Data Size')
plt.ylabel('Time (s)')
plt.xscale('log')  # 使用对数刻度显示更大范围的数据
plt.yscale('log')  # 使用对数刻度显示时间差异
plt.title('Performance Comparison: np.fromiter vs np.array (dtype=int32)')
plt.legend()
plt.grid(True)
plt.show()

实验结果

【教程】实测np.fromiter 和 np.array 的性能_机器学习

【教程】实测np.fromiter 和 np.array 的性能_人工智能_02

结果分析

        从实验结果和图表中,我们可以观察到 np.fromiternp.array(不计算列表开销)和 np.array(计算列表开销)在不同数据量下的性能表现差异。以下是对实验结果的详细分析:

1. 小数据量 (10^110^3)

  • 性能差异较小:在数据量较小时(如 10^110^3),三种方法的执行时间差异非常小。此时,数据的处理开销可以忽略不计,所有方法的性能表现几乎相同。
  • np.fromiter 稍慢:在这些小数据量下,np.fromiter 的执行时间稍微比 np.array 长。这是因为 np.fromiter 需要逐个元素地从生成器中读取数据,而 np.array 直接操作列表(尤其是不计算列表开销时)。

2. 中等数据量 (10^410^5)

  • 开销开始显现:当数据量增加到 10^4 及以上时,np.array 方法开始表现出性能差异。特别是,当我们计算列表转换开销时,np.array 的执行时间开始显著增加。
  • np.fromiter 表现稳定np.fromiter 在中等数据量下表现相对稳定,时间随数据量线性增长,这表明其适合处理较大规模的数据。

3. 大数据量 (10^6 及以上)

  • np.array 的开销显著增加:对于 10^5 以上的数据量,包含列表转换的 np.array 方法的执行时间显著增加,表明当数据量很大时,列表转换开销成为一个显著的瓶颈。
  • np.fromiter 和不包含列表转换的 np.array 方法更优:在处理大数据时,这两种方法的时间相对较低,尤其是不计算列表开销的 np.array 方法,在大数据量下明显比计算列表开销的 np.array 更快。

实验总结

  • np.fromiter 的优势:当处理非常大的数据量且数据来源是生成器时,np.fromiter 表现得非常稳定且高效,适合处理大数据量。
  • np.array(不包含列表开销)适合已有数据结构:如果你已经有一个数据结构(如列表),并且需要将其转换为 NumPy 数组,那么不包含列表转换的 np.array 是最有效的选择。
  • 避免不必要的列表转换:在处理大数据时,避免将生成器不必要地转换为列表可以显著提高性能。因此,除非必要,尽量使用 np.fromiter 或直接将列表转换为数组,而不是将生成器转换为列表再转为数组。

学长想说

        还有一种情况,如果变量aaa已经是tensor了,那么使用aaa.numpy()比以上方法都高效

【教程】实测np.fromiter 和 np.array 的性能_机器学习_03