Как избежать такого большого количества индексации в коде - python - PullRequest
0 голосов
/ 09 мая 2018

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

У меня есть такой список:

selected_parents = 
[array([[4, 6, 3, 1, 0, 7, 5, 2]]), array([[0, 2, 7, 3, 5, 4, 1, 6]])]

Теперь я хочу применить кроссовер к элементам списка (см. PS , что я имею в виду под кроссовером и как это делается, но, опять же, мой вопрос заключается в том, как мне следует избегать так много индексирование, которое я использую при программировании на python):

crossed_p1 = np.zeros((len(selected_parents[0][0]))).astype(int)
crossed_p2 = np.zeros((len(selected_parents[0][0]))).astype(int)

co_point = rd.sample(range(len(selected_parents[0][0])),1)

if co_point[0] >= len(selected_parents[0][0])/2:
        crossed_p1[0:co_point[0]] = selected_parents[0][0][0:co_point[0]]

        indeces = []
        for i in range(co_point[0],len(selected_parents[0][0])):
            a = np.where(selected_parents[1][0] == selected_parents[0][0][i])
            indeces.append(a)
            indeces = sorted(indeces)

        for i in range(len(indeces)):
            crossed_p1[i + co_point[0]] = selected_parents[1][0][indeces[i][0][0]]

        crossed_p2[0:co_point[0]] = selected_parents[1][0][0:co_point[0]]

        indeces = []
        for i in range(co_point[0],len(selected_parents[0][0])):
            a = np.where(selected_parents[0][0] == selected_parents[1][0][i])
            indeces.append(a)
            indeces = sorted(indeces)

        for i in range(len(indeces)):
            crossed_p2[i + co_point[0]] = selected_parents[0][0][indeces[i][0][0]]

    else:
        crossed_p1[co_point[0]:] = selected_parents[0][0][co_point[0]:]

        indeces = []
        for i in range(co_point[0]):
            a = np.where(selected_parents[1][0] == selected_parents[0][0][i])
            indeces.append(a)
            indeces = sorted(indeces)

        for i in range(len(indeces)):
            crossed_p1[i] = selected_parents[1][0][indeces[i][0][0]]

        crossed_p2[co_point[0]:] = selected_parents[1][0][co_point[0]:]

        indeces = []
        for i in range(co_point[0]):
            a = np.where(selected_parents[0][0] == selected_parents[1][0][i])
            indeces.append(a)
            indeces = sorted(indeces)

        for i in range(len(indeces)):
            crossed_p2[i] = selected_parents[0][0][indeces[i][0][0]]

Код работает как шарм, но я ненавижу то, как пишу его! Как будто я продолжаю задавать себе вопросы, я действительно должен написать что-то вроде selected_parents[0][0][indeces[i][0][0]] ?! Например, есть ли лучший способ сделать то, что я делаю?!

P.S. Это пример генетического алгоритма, и у меня есть два массива в selected_parents в качестве родителей первого поколения. Теперь я хочу применить кроссовер, что означает: точка отсечения (т. Е. co_point в коде), которая представляет собой случайное целое число от 1 до длины родителя (в данном документе 8), выбирается случайным образом; Первый потомок (то есть crossed_p1) наследует более длинную подстроку от первого родителя и заменяет номера более короткой подстроки в порядке чисел, появившихся во втором родителе. И аналогичная процедура повторяется для второго потомка (т.е. crossed_p2). Например, на основе текущего списка selected_parents и для co_point = 5 первый потомок (то есть crossed_p1) наследует подстроку 46310 от первого родителя, а оставшаяся подстрока 752 заменяется на 275, то есть порядок чисел, появившихся у второго родителя. Следовательно, первый потомок (т.е. crossed_p1) равен 46310275, а второй потомок (т.е. crossed_p2) будет 02735461.

Ответы [ 3 ]

0 голосов
/ 10 мая 2018

Большая часть индекса относится к элементам списка selected_parents, которые представляют собой двумерные массивы:

selected_parents[0][0][0:co_point[0]]

массивы могут быть проиндексированы одним набором []:

selected_parents[0][0, 0:co_point[0]]

в нотации может быть удобно «назвать» 2 элемента списка (распаковка):

p1, p2 = selected_parents
p1[0, 0:co_point[0]]

Обычно для массива лучше использовать shape, чем len. Заменить

len(selected_parents[0][0])

с

p1.shape[1]

p1.shape (1,8)

Похоже, p1, p2 имеют одинаковую форму. В каком случае

np.stack(selected_parents)

должен создать массив (2,1,8), который можно преобразовать в (2,8). Или

np.concatenate(selected_parents, axis=0)

создание массива (2,8).

0 голосов
/ 10 мая 2018

Вот векторизованная версия вашего кода. Одним приятным побочным эффектом векторизации является то, что она часто устраняет большинство индексов.

В этом коде предполагается, что родительские векторы являются случайными числами 0, 1, 2, .... Если это не так, потребуется еще немного работы:

def invperm(p):
    out = np.empty_like(p)
    idx = np.ogrid[tuple(map(slice, p.shape))]
    idx[-1] = p
    out[idx] = np.arange(p.shape[-1])
    return out

def f_pp(selected_parents):
    sp = np.reshape(selected_parents, (2, -1))
    _, N = sp.shape
    co = np.random.randint(0, N)
    out = sp.copy()
    slc = np.s_[:co] if 2*co < N else np.s_[co:]
    out[::-1, slc] = out[
        np.c_[:2], np.sort(invperm(sp)[np.c_[:2], sp[::-1, slc]], axis=1)]
    return out
0 голосов
/ 09 мая 2018

Кажется, самый простой способ сделать кроссовер, если ваши гены - это 1D списки:

>>> selected_parents = [[4, 6, 3, 1, 0, 7, 5, 2], [0, 2, 7, 3, 5, 4, 1, 6]]

Давайте создадим два паранта и выберем точку пересечения:

>>> p1, p2 = selected_parents
>>> cx = random.randint(len(p1))
>>> p1
[4, 6, 3, 1, 0, 7, 5, 2]
>>> p2
[0, 2, 7, 3, 5, 4, 1, 6]
>>> cx
4

Первый и второй дети - это соединения двух списков танков

>>> ch1=p1[:cx]+p2[cx:]
>>> ch1
[4, 6, 3, 1, 5, 4, 1, 6]
>>> ch2=p2[:cx]+p1[cx:]
>>> ch2
[0, 2, 7, 3, 0, 7, 5, 2]
>>> 

Если вам нужен NumPy, это не проблема. Та же идея ниже:

>>> selected_parents = [array([[4, 6, 3, 1, 0, 7, 5, 2]]), array([[0, 2, 7, 3, 5, 4, 1, 6]])]
>>> p1, p2 = selected_parents
>>> p1
array([[4, 6, 3, 1, 0, 7, 5, 2]])
>>> p2
array([[0, 2, 7, 3, 5, 4, 1, 6]])
>>> cx = random.randint(p1.shape[1])
>>> cx
5
>>> ch1=append(p1[0][:cx],p2[0][cx:])
>>> ch1
array([4, 6, 3, 1, 0, 4, 1, 6])
>>> ch2=append(p2[0][:cx],p1[0][cx:])
>>> ch2
array([0, 2, 7, 3, 5, 7, 5, 2])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...