2011-04-24 29 views
8

我正在使用Scipy的KDTree實現來讀取300 MB的大文件。現在,有沒有辦法將數據結構保存到磁盤並重新加載它,或者我堅持每次從文件中讀取原始數據並在每次啓動程序時構造數據結構?我正在構建KDTree,如下所示:在Python中保存KDTree對象?

def buildKDTree(self): 
     self.kdpoints = numpy.fromfile("All", sep=' ') 
     self.kdpoints.shape = self.kdpoints.size/self.NDIM, NDIM 
     self.kdtree = KDTree(self.kdpoints, leafsize = self.kdpoints.shape[0]+1) 
     print "Preparing KDTree... Ready!" 

有什麼建議嗎?

+1

你嘗試過酸洗? – helloworld922 2011-04-24 21:04:48

+0

當我試圖在KDTree對象上使用cPickle時,我的計算機上出現錯誤 – JoshAdel 2011-04-24 22:19:04

回答

10

KDtree使用嵌套類來定義其節點類型(innernode,leafnode)。泡菜只能在模塊級的類定義,所以嵌套類車次起來:

import cPickle 

class Foo(object): 
    class Bar(object): 
     pass 

obj = Foo.Bar() 
print obj.__class__ 
cPickle.dumps(obj) 

<class '__main__.Bar'> 
cPickle.PicklingError: Can't pickle <class '__main__.Bar'>: attribute lookup __main__.Bar failed 

但是,通過猴子打補丁的類定義爲scipy.spatial.kdtree在模塊範圍,所以,皮克勒一(哈克)解決方法可以找到他們。如果您的所有代碼的讀取和寫入醃製KDtree對象安裝這些補丁,這個技巧應該很好地工作:

import cPickle 
import numpy 
from scipy.spatial import kdtree 

# patch module-level attribute to enable pickle to work 
kdtree.node = kdtree.KDTree.node 
kdtree.leafnode = kdtree.KDTree.leafnode 
kdtree.innernode = kdtree.KDTree.innernode 

x, y = numpy.mgrid[0:5, 2:8] 
t1 = kdtree.KDTree(zip(x.ravel(), y.ravel())) 
r1 = t1.query([3.4, 4.1]) 
raw = cPickle.dumps(t1) 

# read in the pickled tree 
t2 = cPickle.loads(raw) 
r2 = t2.query([3.4, 4.1]) 
print t1.tree.__class__ 
print repr(raw)[:70] 
print t1.data[r1[1]], t2.data[r2[1]] 

輸出:

<class 'scipy.spatial.kdtree.innernode'> 
"ccopy_reg\n_reconstructor\np1\n(cscipy.spatial.kdtree\nKDTree\np2\nc_ 
[3 4] [3 4] 
+0

您是否也有針對cython cKDTree的補丁? – denis 2011-04-25 11:41:19

+0

@Denis不幸的是我沒有cKDTree的補丁。某些形式的保存/加載方法應該是可能的,但是會更加自定義,因爲[cKDTree](http://svn.scipy.org/svn/scipy/trunk/scipy/spatial/ckdtree.pyx)節點是malloc'd結構,而不是類。 – samplebias 2011-04-25 13:32:50

+0

不幸的是我得到的錯誤: 「調用Python對象時超出最大遞歸深度」 公平地說,我的樹是在一個1,000,000長的5d座標列表上計算的,因爲它只需要幾分鐘就可以從該數組中計算(數組本身我可以通過numpy保存並加載)我想我必須忍受這一點。 – CastleH 2014-09-16 15:53:43