Почему в Python переменные не изменяются в цикле?

Почему функция обучения нейросети возвращает исходные значения весов и смещения, несмотря на то, что они изменяются внутри цикла? Я сравниваю это с аналогичным кодом, где используются numpy.array вместо списков. Какова причина этой проблемы с изменением переменных? <br/> <pre><code class="python">from random import uniform

data = [
	[1, 0, 0],
	[0, 1, 0],
	[0, 0, 1],
	[0, 0, 1],
	[0, 1, 0],
	[1, 0, 0],
	[1, 0, 0],
	[0, 1, 0],
	[0, 0, 1],
	[0, 0, 1],
	[0, 1, 0],
	[1, 0, 0],
]
response = [0, 1, 2, 2, 1, 0, 0, 1, 2, 2, 1, 0]

hardlim = lambda s: 1 if s &gt;= 0 else 0

def net(x: list, w: list, bias: int) -> int:
	assert len(x) == len(w)
	return sum([ w[i] * x[i] for i in range(len(x)) ]) + bias

def train(data: list, current: list, epoch: int=10):
	w = [uniform(0, 1) for _ in range(3)]
	print(w)
	bias = 0
	for _ in range(epoch):
		for i in range(len(data)):
			res = net(data[i], w, bias)
			err = current[i] - res
			# w = [w[j] + (err * data[i][j]) for j in range(len(w))]
			w[0] += err * data[i][0]
			w[1] += err * data[i][1]
			w[2] += err * data[i][2]
			bias += err
			print(w, bias)
	return w, bias

W, bias = train(data, response, 3)
print(W, bias)</code></pre> <br/> <br/> Вывод <br/> [0.21010613206587636, 0.9633637928027444, 0.41479921119301144] <br/> [0.0, 0.9633637928027444, 0.41479921119301144] -0.21010613206587636 <br/> [0.0, 1.2101061320658764, 0.41479921119301144] 0.03663620719725558 <br/> [0.0, 1.2101061320658764, 1.9633637928027445] 1.5852007888069886 <br/> [0.0, 1.2101061320658764, 0.41479921119301144] 0.036636207197255466 <br/> [0.0, 0.9633637928027445, 0.41479921119301144] -0.21010613206587636 <br/> [0.21010613206587636, 0.9633
  • 27 апреля 2025 г. 14:55
Ответы на вопрос 2
В вашем коде функция `train` использует простые списки Python для хранения весов (переменная `w`). Изменения в переменных внутри функции должны работать корректно, как вы ожидаете. Однако, вы можете столкнуться с непредвиденным поведением, если вы неверно интерпретируете, как работает Python при изменении переменных в циклах.

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

### 1. Изменение списков в Python
Списки в Python — это изменяемые типы данных, что значит, что вы можете изменять их содержимое. Когда вы делаете `w[0] += ...`, это просто обновляет первый элемент списка `w`, который хранится в памяти. Это должно отразиться на значении `w` в вашей функции. Если бы вы вместо этого приравняли `w` к другому списку (например, `w = [new_value1, new_value2, new_value3]`), то `w` в функции указывал бы на новый объект, и изменения не отражались бы на оригинальном списке, если на него нет внешних ссылок.

### 2. Помните о возвращаемом результате
В вашей функции `train` вы правильно обновляете веса и значение смещения в каждом шаге. Однако, чтобы эти обновления были доступны вне функции, вы должны вернуть обновленные значения. В вашем коде вы делаете это: `return w, bias`.

Ниже представлен измененный код с некоторыми дополнительными комментариями:

```python
from random import uniform

data = [
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 1],
    [0, 0, 1],
    [0, 1, 0],
    [1, 0, 0],
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 1],
    [0, 0, 1],
    [0, 1, 0],
    [1, 0, 0],
]
response = [0, 1, 2, 2, 1, 0, 0, 1, 2, 2, 1, 0]

hardlim = lambda s: 1 if s >= 0 else 0

def net(x: list, w: list, bias: int) -> int:
    assert len(x) == len(w)
    return sum(w[i] * x[i] for i in range(len(x))) + bias

def train(data: list, current: list, epoch: int=10):
    w = [uniform(0, 1) for _ in range(3)]
    print("Initial weights:", w)
    bias = 0
    for _ in range(epoch):
        for i in range(len(data)):
            res = net(data[i], w, bias)
            err = current[i] - res
            # Обновляем веса и смещение
            w[0] += err * data[i][0]
            w[1] += err * data[i][1]
            w[2] += err * data[i][2]
            bias += err
            print("Weights:", w, "Bias:", bias)
    return w, bias

W, bias = train(data, response, 3)
print("Final weights:", W, "Final bias:", bias)
```

### 3. Сравнение с Numpy
Когда вы используете `numpy.array`, поведение также будет изменяемым, но у вас могут возникнуть другие казусы, связанные с типами данных и их обработкой в NumPy по сравнению с обычными списками. NumPy предоставляет более оптимизированные операции и может вести себя несколько иначе из-за векторизации.

Если у вас есть конкретные моменты в коде с использованием `numpy`, которые вы хотите обсудить, пожалуйста, уточните их.

### Заключение
Ваш код должен работать, как ожидается, если вы изменяете элементы списка `w` непосредственно, и возвращаете их в конце выполнения функции. Если вы всё еще сталкиваетесь с проблемами, убедитесь, что вы правильно трактовали вывод и функции, а также следите за тем, как именно переменные обрабатываются внутри вашей функции.
У вас в аргументах функции train три константы на входе: каких изменений вы ждете от повторения? Предполагается, видимо, current должен как-то меняться, но в коде нет этого.
Похожие вопросы