Lev*_*sky 9 python arrays iteration numpy
我遇到的实际问题是我想(float, str)在RAM中存储一个长排序的元组列表.普通列表不适合我的4Gb RAM,所以我想我可以使用两个numpy.ndarray.
数据源是可重复的2元组.numpy有fromiter功能,但我怎么用呢?迭代中的项目数是未知的.由于内存限制,我无法首先将其消耗到列表中.我想到了itertools.tee,但这似乎增加了很多内存开销.
我想我能做的就是以块的形式使用迭代器并将它们添加到数组中.然后我的问题是,如何有效地做到这一点?我应该制作2个2D阵列并为它们添加行吗?(然后我需要将它们转换为1D).
或者可能有更好的方法?我真正需要的是通过对数时间内相应数字的值搜索字符串数组(这就是我想按浮点值排序的原因)并尽可能保持紧凑.
PS迭代没有排序.
也许使用以下方法构建单个结构化数组np.fromiter:
import numpy as np
def gendata():
# You, of course, have a different gendata...
for i in xrange(N):
yield (np.random.random(), str(i))
N = 100
arr = np.fromiter(gendata(), dtype='<f8,|S20')
Run Code Online (Sandbox Code Playgroud)
按第一列排序,使用第二列进行排序,需要O(N log N)时间:
arr.sort(order=['f0','f1'])
Run Code Online (Sandbox Code Playgroud)
按第一列中的值查找行可以searchsorted在O(log N)时间内完成:
# Some pseudo-random value in arr['f0']
val = arr['f0'][10]
print(arr[10])
# (0.049875262239617246, '46')
idx = arr['f0'].searchsorted(val)
print(arr[idx])
# (0.049875262239617246, '46')
Run Code Online (Sandbox Code Playgroud)
你在评论中提出了许多重要问题; 让我试着在这里回答他们:
numpy中解释了基本的dtypes.可能有一个或两个额外的dtypes(float16自编写该书以来已经添加了这些dtypes ,但基本知识都在那里解释.)
Dtypes可用于定义具有列名称或默认列名称的结构化数组.'f0','f1'等等是默认列名.由于我将dtype定义为'<f8,|S20'无法提供列名,因此NumPy命名第一列'f0',第二
列命名'f1'.如果我们使用过
dtype='[('fval','<f8'), ('text','|S20')]
Run Code Online (Sandbox Code Playgroud)
然后结构化数组arr将具有列名称'fval'和
'text'.
np.fromiter被调用的时候被修复.你可以想象,迭代gendata一次,发现字符串的最大长度,构建你的dtype,然后调用np.fromiter(并再次
迭代gendata),但这是相当繁琐的.如果您事先知道字符串的最大大小,那当然会更好.(|S20将字符串字段定义为具有20个字节的固定长度.)dtype)快速计算访问所需的偏移来获得大部分速度.数组中的元素.如果字符串具有可变大小,那么NumPy很难找到正确的偏移量.很难,我的意思是NumPy需要索引或以某种方式重新设计.NumPy根本就不是这种方式构建的.objectdtype,它允许你将一个4字节的指针放到你想要的任何Python对象上.这样,您可以使NumPy数组具有任意Python数据.不幸的是,该np.fromiter
函数不允许您创建dtype数组object.我不确定为什么会有这个限制......np.fromiter时具有更好的性能count.通过知道count(行数)和
dtype(以及每行的大小),NumPy可以为结果数组预先分配足够的内存.如果你没有指定count,那么NumPy会猜测数组的初始大小,如果太小,它会尝试调整数组的大小.如果原始的内存块可以扩展,那么你很幸运.但是如果NumPy必须分配一个全新的内存块,那么所有旧数据都必须被复制到新位置,这将显着降低性能.