#python #arrays #python-3.x #list #loops
Вопрос:
У меня есть объект со структурой, похожей на:
models = [{
'name': 'Model 1',
'errors': {
'mse': None,
'rmse': None
}
},
{
'name': 'Model 2',
'errors': {
'mse': None,
'rmse': None
}
}]
Теперь я хочу пройтись по объекту и что-то изменить, поэтому я попытался использовать что-то вроде этого:
for index, model in enumerate(models):
# Carry out model performance and update the respective errors
model['errors']['mse'] = metrics.mean_squared_error(...)
Что происходит, так это то, что все объекты внутри models
списка обновляются значениями последнего элемента. Я тоже пытался использовать это (и это тоже не сработало).:
for index in range(len(models)):
# Carry out model performance and update the respective errors
models[index]['errors']['mse'] = metrics.mean_squared_error(...)
Если я даже напишу models[0]['errors']['mse'] = 10
, все остальные индексы также будут обновлены. Может ли кто-нибудь, пожалуйста, помочь мне с решением этой проблемы?
(Было бы действительно здорово, если бы вы могли предложить решение, в котором я мог бы обновлять, просматривая список)
Фактический Код
import importlib
class Models:
# Model structure
model = {
'base': None,
'name': None,
'model': None,
'config': {},
'errors': {
'mae': None,
'mse': None,
'rmse': None,
},
'scores': {
'r2': None,
'accuracy_score': None
}
}
# Prints Looping Progress
def progress(self, index):
return '(' str(index 1) '/' str(self.models.__len__()) ')'
# Import Models
def import_models(self):
for model in self.models:
model['model'] = getattr(importlib.import_module(model['base']), model['name'])(**model['config'])
# Restructure Models Object
def restructure_models(self, models):
restructured_models = []
for model in models:
restructured_model = {**self.model, **model}
restructured_models.append(restructured_model)
return restructured_models
# Constructor
def __init__(self, models):
self.models = self.restructure_models(models)
self.import_models()
# Train Models
def fit(self, X_train, y_train):
for index, model in enumerate(self.models):
print('Training ' self.progress(index) ': ', model['name'])
model['model'].fit(X_train, y_train)
print('n')
# Predict Values
def predict(self, X_test):
all_predictions = []
for index, model in enumerate(self.models):
print('Running ' self.progress(index) ': ', model['name'])
# Predict
predictions = model['model'].predict(X_test)
all_predictions.append({
'model': model['name'],
'predictions': predictions
})
print('n')
return all_predictions
# Evaluate Trained Models
def test(self, X_test, y_test):
from sklearn import metrics
all_predictions = []
for index, model in enumerate(self.models):
print('Evaluating ' self.progress(index) ': ', model['name'])
# Predict
predictions = model['model'].predict(X_test)
# Errors
model['errors']['mae'] = metrics.mean_absolute_error(y_test, predictions)
model['errors']['mse'] = metrics.mean_squared_error(y_test, predictions)
model['errors']['rmse'] = np.sqrt(model['errors']['mse'])
# Scores
model['scores']['r2'] = metrics.r2_score(y_test, predictions)
model['scores']['accuracy_score'] = metrics.r2_score(y_true = y_test, y_pred = predictions)
all_predictions.append({
'model': model['name'],
'predictions': predictions
})
print('n')
return all_predictions
# Evaluated Performance Metrics
def results(self):
for model in self.models:
print('Model: ', model['name'])
print('MAE: ', model['errors']['mae'])
print('MSE: ', model['errors']['mse'])
print('RMSE: ', model['errors']['rmse'])
print('R2: ', model['scores']['r2'])
print('Accuracy Score: ', model['scores']['accuracy_score'])
print('n')
Вызов и использование класса:
selected_models = [
{
'base': 'sklearn.linear_model',
'name': 'LinearRegression'
},
{
'base': 'sklearn.ensemble',
'name': 'RandomForestRegressor',
'config': {
'n_estimators': 50
}
}
]
models = Models(models = selected_models)
predictions = models.test(X_test = X_test_scaled, y_test = y_test)
Проблема заключается в test
self.models
неправильном обновлении функции (все элементы списка изменяются в соответствии с последним элементом).
Комментарии:
1. Пожалуйста, опубликуйте код, который действительно демонстрирует проблему, или попробуйте воспроизвести проблему с помощью предоставленного вами примера кода, в котором каждый элемент списка является независимо объявленным диктом (вы обнаружите, что он ведет себя по-разному).
2. Я обновил вопрос с помощью фактического кода
Ответ №1:
Проблема в том, что здесь:
restructured_model = {**self.model, **model}
Вы создаете новый dict
, но он ссылается на синглтон Models.model
.
Я думаю, ты это имел в виду:
import copy
copy_model = copy.deepcopy(self.model)
restructured_model = {**copy_model, **model}
Комментарии:
1. Вау, это сработало как заклинание! Большое вам спасибо за помощь!
Ответ №2:
Можете ли вы попробовать это для отладки?
for index, model in enumerate(models):
# Carry out model performance and update the respective errors
set_value = metrics.mean_squared_error(...)
print('setting value to ' str(set_value))
model['errors']['mse'] = set_value
Комментарии:
1. Я добавил его, и результаты снова те же. При печати внутри цикла он выдает правильные значения, однако после запуска цикла, когда я печатаю весь объект, все элементы обновляются со значением последнего элемента.