#python #serialization #numpy #scipy #pickle
#python #сериализация #numpy #scipy #рассол
Вопрос:
Я использую реализацию KDTree от Scipy для чтения большого файла размером 300 МБ. Теперь, есть ли способ, которым я могу просто сохранить структуру данных на диск и загрузить ее снова, или я застрял с чтением необработанных точек из файла и созданием структуры данных каждый раз, когда я запускаю свою программу? Я создаю 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. вы пробовали мариновать?
2. Когда я попытался использовать cPickle для объекта KDTree, я получаю сообщение об ошибке на своем компьютере
Ответ №1:
KDTree использует вложенные классы для определения типов своих узлов (innernode, leafnode). Pickle работает только с определениями классов на уровне модуля, поэтому вложенный класс отключает его:
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
области видимости модуля at, чтобы программа выбора могла их найти. Если весь ваш код, который считывает и записывает обработанные объекты 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_regn_reconstructornp1n(cscipy.spatial.kdtreenKDTreenp2nc_
[3 4] [3 4]
Комментарии:
1. у вас тоже есть патч для cython cKDTree?
2. @Denis К сожалению, у меня нет патча для cKDTree. Должна быть возможна некоторая форма метода сохранения / загрузки, но он был бы более настраиваемым, поскольку узлы cKDTree являются структурами malloc’d, а не классами.
3. К сожалению, я получаю сообщение об ошибке: «при вызове объекта Python превышена максимальная глубина рекурсии» Справедливости ради, мое дерево вычисляется на основе 1 000 000 длинного списка координат 5d, поскольку вычисление из этого массива занимает всего несколько минут (сам массив я могу сохранить и загрузить через numpy) Думаю, мне придется с этим смириться.
4. Очень хорошее решение, будет ли это работать для других типов? и как вы можете исследовать, какие типы предоставлять таким образом?