转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn]
如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~
目录
函数简介
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 为 int32return 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 为 int32return 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.array
(计算列表开销)在不同数据量下的性能表现差异。以下是对实验结果的详细分析:
1. 小数据量 (10^1
到 10^3
)
- 性能差异较小:在数据量较小时(如
10^1
到10^3
),三种方法的执行时间差异非常小。此时,数据的处理开销可以忽略不计,所有方法的性能表现几乎相同。 np.fromiter
稍慢:在这些小数据量下,np.fromiter
的执行时间稍微比np.array
长。这是因为np.fromiter
需要逐个元素地从生成器中读取数据,而np.array
直接操作列表(尤其是不计算列表开销时)。
2. 中等数据量 (10^4
到 10^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()比以上方法都高效!