我正在构建一个从文件导入数据的新函数。我构建自己的,所以它可以使用与loadtxt()相同的通用函数调用,并处理数据列的标题。问题出在数据文件的大小上,我使用的最后一个是1.3gig。为了尽量减少ram的使用,我计划将文件加载到变量中,将其分解为一个数组" f"然后一次处理50,000行。这样我就可以将这50,000条处理过的行放入一个数组中,然后用原始文件从变量中删除它们。 (处理然后一次删除一行需要太长时间,因此想要做50,000。)
对于我正在使用的处理:
import numpy as np
def processing(arr, delimiter, dtype):
return map(dtype, arr.split(delimiter))
df = open(file, 'r')
f = df.readlines()
df.close()
fn = vectorize(processing, otypes=[float])
fn的工作条件是我没有将数组传递给它。考虑:
a = ['1,2,3', '4,5,6', '7,8,9']
此:
fn(a, ',', int)
返回,
" ValueError:使用序列设置数组元素。"
我的其余功能都有效。没有这个的Variant工作,但对于大文件来说真的很慢。我有一个简短的一次性脚本,在4分钟内加载文件以便达到目标(loadtxt()用完了~16g的ram并使我的机器崩溃)。我想尝试这种矢量化的想法,但如果有更好的方法来打破数据,同时最大限度地减少ram的使用,我会对此持开放态度。
答案 0 :(得分:0)
vectorize
不能代替迭代。这是一种为您提供numpy
广播全部功能的方式。生成的函数接受一个或多个数组,将它们一起广播,然后将一个简单的值元组(即标量,每个数组中的一个)提供给包装函数。
在您的代码中f
是一个行列表 - 文件中的所有行。
您可以执行以下操作:
N = len(f)
for i in range(0,N,1000):
a = np.loadtxt(f[i:i+1000], delimiter=',')
<process array a>
换句话说,在块中提供f
到loadtxt
的行。
实际上,您不需要一次阅读所有行。您可以编写一个逐行读取文件的生成器,并返回行块。
以前已经讨论过使用生成器来提供loadtxt
(或genfromtxt
)。
vectorize的工作示例
In [121]: def processing(astr):
return list(map(int, astr.split(',')))[0] # py3
.....:
In [122]: processing(a[0])
Out[122]: 1
In [123]: fn=np.vectorize(processing, otypes=[int])
In [124]: fn(a)
Out[124]: array([1, 4, 7])
此函数接受一个字符串并返回一个int
。它并不比
In [125]: [processing(l) for l in a]
Out[125]: [1, 4, 7]
我从参数中删除了delimiter
和dtype
因为我们不想迭代这些参数。 exclude
有一个vectorize
参数;但我并不想玩那个。
vectorize
也为otypes
提供了多个值,但我还没有看到这种用法的例子。你的函数没有用,因为它返回了一个序列(例如3个整数),但vectorize
期望它返回一个值(标量浮点数或整数)。
如果您将otypes
指定为对象,则processing
可以正常工作 - 排序
In [126]: def processing(astr):
return list(map(int, astr.split(','))) # py3
.....:
In [127]: fn=np.vectorize(processing, otypes=[object])
In [128]: fn(a)
Out[128]: array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=object)
但为什么不迭代?
In [129]: [processing(l) for l in a]
Out[129]: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
In [130]: np.array([processing(l) for l in a])
Out[130]:
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
我模糊地回忆起在使用vectorize
并返回object
时出现错误的一些问题。
虽然我在滚动,但我还是可以说明广播:
这是你的函数,它接受2个值 - 一个字符串和一个函数,并将该函数应用于拆分的每个元素:
In [131]: def processing(astr, conv):
return list(map(conv, astr.split(','))) # py3
.....:
In [132]: fn=np.vectorize(processing, otypes=[object])
现在vectorized
功能需要2个输入,例如列表和功能:
In [133]: fn(a,int)
Out[133]: array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=object)
或a
中每个字符串的不同函数(2个列表)
In [134]: fn(a,[int,float,str])
Out[134]: array([[1, 2, 3], [4.0, 5.0, 6.0], ['7', '8', '9']], dtype=object)
或者将第二个列表设为&#39;列&#39; list - 并返回(2,3)列表。一行是整数,另一行是浮点数。显然我可以用数组替换列表(0,1d,2d等)。
In [136]: fn(a,[[int],[float]])
Out[136]:
array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]], dtype=object)
如果您需要输入的这种灵活性,请使用vectorize
。但是如果你只是迭代一个数组或列表 - 直接进行。
我找到了多个otypes
:https://stackoverflow.com/a/30255971/901925
适用于此案例:
In [140]: def processing(astr):
return tuple(map(int, astr.split(','))) # py3
.....:
重要的是它返回一个元组,而不是列表或数组。
In [141]: processing(a[0])
Out[141]: (1, 2, 3)
In [142]: fn=np.vectorize(processing, otypes=[int,int,int])
请注意,返回的元组的每个项目都必须有otype
。
In [144]: fn(a)
Out[144]: (array([1, 4, 7]), array([2, 5, 8]), array([3, 6, 9]))
但[1, 4, 7]
是3个输入中每个输入的第一个值。它返回了一个数组元组,而不是一个数组。
In [146]: x,y,z=fn(a)
In [147]: x
Out[147]: array([1, 4, 7])
这种行为困扰着另一个提问者,我怀疑它是否也是你想要的。 :)
https://stackoverflow.com/a/30088791/901925 - 带时间测试的矢量化示例。