Увеличение скорости операций со списками Python и сравнений в пользовательском табличном классе - PullRequest
0 голосов
/ 21 января 2011

Я использую следующий класс для создания таблицы, и мне нужно найти способ не только сделать ее быстрее, но и ускорить взаимодействие с ней:

class Table(object):
    """a three dimensional table object"""
    def __init__(self, xsize=1, ysize=1, zsize=1):
        self.xsize = xsize
        self.ysize = ysize
        self.zsize = zsize
        self.data = [0] * (xsize * ysize * zsize)

    def __getitem__(self, key):
        x, y, z = self.__extractIndices(key)
        return self.data[x + self.xsize * (y + self.ysize * z)]

    def __setitem__(self, key, value):
        x, y, z = self.__extractIndices(key)
        self.data[x + self.xsize * (y + self.ysize * z)] = value

    def __extractIndices(self, key):
        x = y = z = 0
        if (self.ysize > 1):
            if (self.zsize > 1):
                if len(key) != 3:
                    raise IndexError
                else:
                    x, y, z = key
            elif len(key) != 2:
                raise IndexError
            else:
                x, y = key
        elif not isinstance(key, int):
            raise IndexError
        else:
            x = key
        return (x, y, z)

    def resize(self, xsize=1, ysize=1, zsize=1):
        """resize the table preserving data"""
        oldlist = list(self.data)
        self.data = [0] * (xsize * ysize * zsize)
        self.xsize = xsize
        self.ysize = ysize
        self.zsize = zsize
        for i in range(0, oldlist):
            self.data[1] = oldlist[i]

в данный момент мне нужно найтиесли данные в двух списках эквивалентны каждому из Z, так что я сделал это.self.data и self.map.data - это экземпляры классов таблиц сверху

    for x in range(self.map.width - 1):
        for y in range(self.map.height - 1):
            tempflag = False
            #layer 1
            if self.data[x, y, 0] != self.map.data[x, y, 0]:
                tempflag = True
                layer1flag = True
            #layer 2
            if self.data[x, y, 1] != self.map.data[x, y, 1]:
                tempflag = True
                layer2flag = True
            #layer 3
            if self.data[x, y, 2] != self.map.data[x, y, 2]:
                tempflag = True
                layer3flag = True
            #copy the data if it changed
            if tempflag:
                self.data = copy.deepcopy(self.map.data)
                previewflag = True

, очевидно, это самый медленный способ, которым я мог бы это сделать, и учитывая, что некоторые из этих таблиц, которые я сравниваю, имеют размер 200 *200 * 3 = 120000 записей.Мне нужно, чтобы это было как можно быстрее.

Я подумал переписать вышеприведенное сравнение, чтобы разделить все записи на один z, например

tempflag = False
#layer 1
slicepoint1 = 0
slicepoint2 = self.data.xsize * self.data.ysize * 1
data1 = self.data.data[slicepoint1:slicepoint2]
data2 = self.map.data.data[slicepoint1:slicepoint2]
if data1 != data2:
    tempflag = True
    layer1flag = True
#layer 2
slicepoint1 = self.data.xsize * self.data.ysize * 1
slicepoint2 = self.data.xsize * self.data.ysize * 2
data1 = self.data.data[slicepoint1:slicepoint2]
data2 = self.map.data.data[slicepoint1:slicepoint2]
if data1 != data2:
    tempflag = True
    layer2flag = True
#layer 3
slicepoint1 = self.data.xsize * self.data.ysize * 2
slicepoint2 = self.data.xsize * self.data.ysize * 3
data1 = self.data.data[slicepoint1:slicepoint2]
data2 = self.map.data.data[slicepoint1:slicepoint2]
if data1 != data2:
    tempflag = True
    layer3flag = True
#copy the data if it changed
if tempflag:
    self.data = copy.deepcopy(self.map.data)
    previewflag = True

, и хотя это выглядит так, как будтоидти быстрее, это все еще кажется, что это может быть значительно улучшено.например, не может ли использовать numpy для построения списка данных внутри класса Table?

Мне нужен этот класс, и эта проверка выполняется настолько быстро, насколько это возможно

, было бы также неплохо, если быиспользование numpy позволило бы мне действительно быстро перебирать таблицу, чтобы я мог использовать данные в ней для блиц-операций для построения карты тайлов

I do необходимо сохранить общий интерфейскласс таблицы, в частности тот факт, что данные таблицы хранятся в self.data

В итоге Можно ли увеличить скорость операций с помощью numpy?Если да, то как я могу это сделать?

Ответы [ 2 ]

2 голосов
/ 21 января 2011

Я думаю, что да, используя numpy, вы, вероятно, сможете получить большую скорость.

Вы можете не только создавать срезы, но вы также можете делать прямоугольные и, возможно, кубические срезы, например:

>>> a = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
>>> a[:2,1:]
array([[2, 3],
       [5, 6]])

Я не уверен, чего вы хотите достичь, но вы также можете легко сравнить поэтапно массивы:

>>> numpy.array([1,2,3])==numpy.array([9,2,3])
array([False,  True,  True], dtype=bool)

Если у вас есть вопросы, не стесняйтесь комментировать.

1 голос
/ 21 января 2011

Это определенно приложение для NumPy!Это не только ускорит ваш код, но и значительно упростит ваш код, потому что NumPy уже выполняет индексирование и сравнение.Чтобы изучить NumPy, вам нужно будет прочесть какое-то учебное пособие - всего несколько советов, которые помогут вам в этом.

Обычно я бы просто взял из numpy.ndarray определение пользовательского класса массива, но вы заявили, чточто вам определенно нужен атрибут data, который конфликтует с numpy.ndarray.data.Ваш класс упрощается до

class Table(object):
    def __init__(self, xsize=1, ysize=1, zsize=1):
        self.data = numpy.zeros((xsize, ysize, zsize))

    def __getitem__(self, key):
        return self.data[key]

    def __setitem__(self, key, value):
        self.data[key] = value

    def resize(self, xsize=1, ysize=1, zsize=1):
        # This only works for increasing the size of the data,
        # but is easy do adapt to other cases
        newdata = numpy.zeros((xsize, ysize, zsize))
        shape = self.data.shape
        newdata[:shape[0], :shape[1], :shape[2]] = self.data
        self.data = newdata

Ваш код сравнения упрощается до

eq = self.data == self.data.map
layerflags = eq.reshape(-1, 3).any(axis=0)
if layerflags.any():
    self.data[:] = self.map.data

И он также будет намного быстрее!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...