前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【教程】实测np.fromiter 和 np.array 的性能

【教程】实测np.fromiter 和 np.array 的性能

原创
作者头像
小锋学长生活大爆炸
发布2024-09-26 03:24:16
740
发布2024-09-26 03:24:16
举报
文章被收录于专栏:学习之旅

转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~

目录

函数简介

np.fromiter

np.array

测试代码

实验结果

结果分析

实验总结

学长想说


函数简介

np.fromiter

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

优点:

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

缺点:

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

np.array

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

优点:

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

缺点:

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

测试代码

代码语言:javascript
复制
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.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()比以上方法都高效

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 函数简介
    • np.fromiter
      • np.array
      • 测试代码
      • 实验结果
      • 结果分析
      • 实验总结
      • 学长想说
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档