在Python

时间:2016-02-01 05:38:30

标签: python arrays numpy vectorization

我正在构建一个从文件导入数据的新函数。我构建自己的,所以它可以使用与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的使用,我会对此持开放态度。

1 个答案:

答案 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>

换句话说,在块中提供floadtxt的行。

实际上,您不需要一次阅读所有行。您可以编写一个逐行读取文件的生成器,并返回行块。

以前已经讨论过使用生成器来提供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]

我从参数中删除了delimiterdtype因为我们不想迭代这些参数。 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。但是如果你只是迭代一个数组或列表 - 直接进行。

我找到了多个otypeshttps://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 - 带时间测试的矢量化示例。