2016-02-01 99 views
1

我正在構建一個新的函數來從文件中導入數據。我構建自己的,所以它可以使用與loadtxt()相同的一般函數調用,並處理數據列標題。這個問題伴隨着數據文件的大小,我正在使用的最後一個是1.3gigs。爲了儘量減少RAM的使用,我計劃將文件加載到一個變量中,將其分解爲一個「f」數組,然後每次處理50,000行數據。這樣我可以將這些50,000行處理過的行放入一個數組中,然後用原始文件從變量中刪除它們。 (加工,然後刪除一行在時間花費的時間太長,因而這個想法做50,000。)向量化Python中的函數問題

對於我使用的處理:

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: setting an array element with a sequence."

我的函數的其他工作。沒有這個工作的變體,對於大文件來說確實很慢。我有一個簡短的一次性腳本,它在4分鐘內加載了這個文件,所以這就是目標(loadtxt()用完了~16g的ram並使我的機器崩潰)。我想嘗試這個矢量化的想法,但如果有更好的方式來打破數據,同時最大限度地減少內存使用率,我願意接受。

+3

您是否考慮過自己打開文件,僅讀取其中的一小部分,將該部分放入StringIO對象中,並將StringIO對象傳遞給'loadtxt()'。 'numpy.loadtxt'文件中有一個例子。 –

回答

0

vectorize不是迭代的替代品。這是一種給予您全部廣播權的方式。結果函數接受一個或多個數組,將它們一起廣播,然後將簡單的值元組(即標量,每個數組中的一個)提供給包裝函數。

在您的代碼中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)。矢量化

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從參數,因爲我們不想遍歷這些參數。 vectorize有一個exclude參數;但我不想玩那個。

vectorize也需要多個值爲otypes,但我還沒有看到這種使用的例子。你的函數不起作用,因爲它返回了一個序列(例如3個整數),但是vectorize預期它返回一個值(一個標量float或int)。


如果指定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]]) 

我使用vectorizeobject返回時依稀記得有關錯誤的一些做題。

雖然我在一滾,我還不如說明廣播:

這是你的函數,採用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) 

,或使第二列表中的「列名單 - 並得到一個(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 - 帶時間測試的矢量化示例。

+0

我仍然在通過這種方式工作,但你問爲什麼不只是迭代。我希望vectorize可以讓我爲同時降低時間的多個實例調用相同的函數,並且可以讓處理器在處理多個進程的同時減少時間。我得到的印象是它一次只運行一個。 – BobJoe1803

+1

'np.vectorize'不是一個多處理包裝器。這是一個迭代包裝。在其他情況下,它比用戶實現的迭代節省了大約20%的時間。但是,如果任務是一次處理50,000行,則與處理時間相比,迭代開銷將很小。 – hpaulj