Почему цикл ‘for’ не повторяется по списку?

#python #numpy #for-loop

#python #numpy #for-цикл

Вопрос:

Я пытаюсь написать процедуру перекрестной проверки для модели Lasso на Python. Я имею дело с временными рядами, поэтому я использую TimeSeriesSplit метод from sklearn .

Зависимая переменная и регрессоры обозначаются соответственно Y (numpy 1-мерный массив) и F (numpy nd-массив) в моем коде. Я применяю ЛАССО к

$ Y = F beta U $

в очень стандартном приложении. Я использую перекрестную проверку, чтобы выбрать штрафной гиперпараметр для LASSO. Чтобы сделать это, я определяю следующую функцию в Python 3.6:

 def optimal_penalty(Y, F, penalty_list, splits):
  data = np.hstack((Y[:, None], F))
  splitter = TimeSeriesSplit(n_splits = splits).split(data)

  penalty_errors = np.zeros(len(penalty_list))

  for p, penalty in enumerate(penalty_list):
    estimator = Lasso(alpha = penalty, normalize = False)
    cv_error = np.zeros(splits)
    i = 0

    for train, test in splitter:
      F_train, F_test = F[train], F[test]
      Y_train, Y_test = Y[train], Y[test]
      Y_hat = estimator.fit(F_train, Y_train).predict(F_test)
      cv_error[i] = r2_score(Y_test, Y_hat)
      i = i  1
      print('in loop')

    penalty_errors[p] = np.mean(cv_error)
    print('Penalty', penalty, penalty_errors[p])

  best = penalty_list[np.argmin(penalty_errors)]

  return(best, penalty_errors)
 

в котором np означает numpy. Операторы print предназначены только для проверки того, что делает код. Меня интересует только наилучшее наказание из заданного пользователем списка наказаний (список с плавающей запятой) и итоговая средняя ошибка для каждого значения штрафа, хранящегося в массиве penalty_errors . Однако, когда я запускаю эту функцию, я получаю следующее поведение:

 In [64]: optimal_penalty(Y, F, [0.5, 1, 2], 5)
in loop
in loop
in loop
in loop
in loop
Penalty 0.5 0.02312207752945177
Penalty 1 0.0
Penalty 2 0.0
Out[64]: (1, array([0.02312208, 0.        , 0.        ]))
 

Как можно видеть, код работает, как и ожидалось, для первого значения в penalty_list . Однако, похоже, что для других значений параметра штрафа вообще ничего не вычисляется, поскольку я не вижу операторов «в цикле». Можете ли вы, ребята, заметить какую-нибудь глупую ошибку? Я только начал с Python и, вероятно, что-то здесь упускаю. Заранее большое вам спасибо!!

Комментарии:

1. splitter является итератором. как только вы исчерпаете итерации (в первом цикле), повторный вызов немедленно приведет StopIteration к исключению. вы должны создавать splitter на каждой итерации внешнего цикла.

2. Спасибо @Aaron! Я не знал этого свойства об итераторах. Как потреблять память для создания splitter при каждом запуске? Не лучше ли тогда создать список элементов из splitter этого списка и выполнить итерацию по этому списку?

3. Это компромисс между временем и пространством. Для создания списка элементов используется память для всех из них. Итератор использует только память для текущего элемента, но он должен вычислять каждый из них каждый раз, когда вы его используете.

4. Я не знаком с тем, как splitter это работает. Это не обязательно создание копий данных, скорее просто структура, которая указывает на исходные данные, так что это может быть не проблема.

5. @Barmar ну, в идеале хорошо реализованный итератор должен. Не всегда так, но обычно это безопасное предположение. Но ничто не мешает кому-то делать что-то вроде data_to_iterate = list(some_lazy_iterator); yield from data_to_iterate