Для циклического переписывания части, но не всей, предыдущей записи в массиве

Я пишу довольно простую функцию случайного блуждания. Весь код ниже. Я использую массив для отслеживания значений параметров, когда текущая функция стоимости меньше предыдущей. Но по какой-то причине массив, который отслеживает вывод, переписывается? предыдущие записи. Я думаю, что это как-то связано с добавлением параметров как "c", и поэтому существует проблема выделения памяти, потому что "c" добавляется вместо значений c, но я не знаю, как это исправить, и почему будет отличаться со значением функции стоимости psi, которая добавляет и поддерживает свои значения, как и предполагалось.

Я пытаюсь создать что-то вроде:

input: 
for n in N: 
if cost < previous cost: keep current parameters
write current parameters & cost to tracking list

output:
n = 0, parameters = [1,2,3], cost = 4.5, track = [([1,2,3], 4.5)]
n = 1, parameters = [1.1,2.4,2.7], cost = 3.9, track = [([1,2,3], 4.5), ([1.1, 2.4, 2.7], 3.9)]
etc

вместо этого я получаю

output:
n = 0, parameters = [1,2,3], cost = 4.5, track = [([1,2,3], 4.5)]
n = 1, parameters = [1.1,2.4,2.7], cost = 3.9, track = [([1.1,2.4,2.7], 4.5), ([1.1, 2.4, 2.7], 3.9)]

поэтому он заменяет параметры, но сохраняет прежнюю стоимость. Это происходит, когда функция отслеживания находится за пределами успеха (более низкая стоимость), если оператор тоже.

Помогите?

#pure random walk where all c parameters are randomly updated at once; no restrictions on pos/neg of parameters
del track
del bigtrack

c = [5,5,-5]
cp = c
kB = -8

M = 10
N = 5000
bigtrack = []

psip = cost(LN, LB, dldtN, dldtB, c[2], kB, c[0], c[1]) #cost using initialized parameters

for m in range(M):

    track = []
    for n in range(N):

        for i in range(len(c)):
            rand = np.random.uniform(-1,1)
            c[i] = c[i] + rand
            #print(c[i])
        #print("parameters = ", c)

        psi = cost(LN, LB, dldtN, dldtB, c[2], kB, c[0], c[1])
        #print("new cost = ", psi)

        if psi < psip:
            cp = c
            resp = res
            psip = psi
            track.append((c, psi))
            print("tracking function: \n", track)
        else:
            c = cp #keep prior 
            res = resp
            psi = psip

        if psi <16:
            print("VICTORY")
            break


    #print(track)
    #if track != []:
    bigtrack.append((track, m))

и вот пример вывода

tracking function: 
 [([4.145180382591114, 5.194803875207629, -5.77417154313107], 457.37070071446328)]
tracking function: 
 [([4.366620027701061, 5.610886161756634, -6.300451985366614], 457.37070071446328), ([4.366620027701061, 5.610886161756634, -6.300451985366614], 406.27520117896)]
tracking function: 
 [([4.294900222966394, 6.104004008230176, -6.636360393709489], 457.37070071446328), ([4.294900222966394, 6.104004008230176, -6.636360393709489], 406.27520117896), ([4.294900222966394, 6.104004008230176, -6.636360393709489], 377.1702411076343)]

1 ответ

Решение

Вы вставляете то же самое list к результатам при изменении его между вставками. Эффективно вы делаете следующее:

>>> track = []
>>> c = [1, 2, 3]
>>> track.append(c)
>>> track
[[1, 2, 3]]
>>> c[1] += 2
>>> track.append(c)
>>> track
[[1, 4, 3], [1, 4, 3]]

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

track.append((c[:], psi)) # instead of track.append((c, psi))
Другие вопросы по тегам