Для каждого из этих альф на пути сокращения я обучаю соответствующую модель на обучающих данных, используя параметр ccp_alpha в функции DecisionTreeClassifier. Затем я беру каждую из этих моделей и оцениваю оценку F1 на тестовых данных, чтобы увидеть, какая модель (и какое поддерево) лучше всего работает по шкале F1. Показатель F1 я определил как самый важный показатель производительности для моих данных. Однако в настоящее время оценка F1 по тестовым данным является самой высокой для полностью выращенного дерева, поэтому обрезка вообще не производится.
Я заметил, что если я оставлю параметр class_weight со значением по умолчанию None, некоторое сокращение произойдет, но все равно оставит очень сложное дерево - глубина варьируется от 33 для полного дерева до 28 для сокращенного дерева. Я подумал, что было бы неплохо установить для параметра class_weight значение «сбалансированный», поскольку около 2/3 целевой переменной в выборке относятся к классу большинства (я не уверен, нужно ли предотвращать такую степень дисбаланса или нет). Я не уверен, почему этот параметр вызывает проблемы, но даже если оставить его по умолчанию, дерево получится очень сложным.
Ниже приведен код, который я использую. Прямо сейчас я установил для параметра Alpha_threshold значение 0, потому что хочу посмотреть, произойдет ли сокращение, если единственным требованием является наивысший балл F1. X_train — это фрейм данных Pandas, в котором хранятся переменные-предикторы (все числовые типы), а y_train хранит двоичную целевую переменную (1 или 0).
Код: Выделить всё
#We will get the cost-complexity paramater (ccp_alpha) and the corresponding sum of impurities for the leaves of the subtree
path_dict = DecisionTreeClassifier(class_weight = 'balanced', random_state = 1).cost_complexity_pruning_path(X_train, y_train)
df_path = pd.DataFrame(path_dict)
#For each ccp_alpha, we will train a model with that parameter on training data and evaluate the performance on F1 score on test data
#I'm also going to demand alpha is at least alpha_threshold so we don't end up with a tree that is too complex
alpha_threshold = 0
f1_scores = np.zeros(len(df_path))
f1_max = 0 #initialize max f1 to 1 so that we can test each f1 to see which is the highest
for i in range(len(df_path)):
alpha = df_path['ccp_alphas'].iloc[i]
#model = DecisionTreeClassifier(class_weight = 'balanced', random_state = 1, ccp_alpha = alpha).fit(X_train, y_train)
model = DecisionTreeClassifier(random_state = 1, ccp_alpha = alpha).fit(X_train, y_train)
class_pred = model.predict(X_test)
f1_scores[i] = f1_score(y_test, class_pred)
if f1_scores[i] > f1_max and alpha > alpha_threshold: #if the current F1 score based on alpha is the highest and alpha is greater than our threshold
f1_max = f1_scores[i] #set the new f1_max to this F1
best_model = model #Set the best model to be the current model (which currently has the highest F1 score)
best_ccp_alpha = alpha #this alpha is currently our best alpha in terms of performance on F1 score
Код: Выделить всё
Best ccp_alpha: 1.923738208085851e-05
Код: Выделить всё
Max depth of tree: 33
Код: Выделить всё
Maximum F1 Score Test Data: 0.910182873338282
ОБНОВЛЕНИЕ:
Обновление: я попробовал подход jgonz1 для использования перекрестной проверки (CV) только на обучающем наборе. Вот мой код и результаты. Обратите внимание, что результаты те же — глубина дерева равна 33. Если я сделал что-то не так, дайте мне знать.
Код: Выделить всё
#We will take each cost-complexity alpha along the path and do a randomized grid search using cross-validation to see which hyperparameter performs best on cross-validation F1 score for the training set.
ccp_alphas_dict = {'ccp_alpha':df_path['ccp_alphas'].to_list()}
#make estimator, random_state=1 ensures reproducability, class_weight='balanced' is used so the fit is not biased towards the majority class
tree_post1 = DecisionTreeClassifier(class_weight = 'balanced', random_state = 1)
scorer = make_scorer(f1_score) #measure performance using F1 score
#We will set n_iter to 100 so that a total of 100 hyperparameter combinations are tested (it will select them at random from the possible combinations)
#cv = 5 will make 5 folds. error_score = 'raise' will raise an error in the case that a score can't be calculated. refit = True will alow us to get the hyperparameters that
#have the pest cross-validation performance
#We will use the same scorer we made earlier that measures F1 score
grid_search_post = RandomizedSearchCV(estimator = tree_post1, param_distributions = ccp_alphas_dict, scoring = scorer, n_iter = 100, refit = True, cv = 5, error_score = 'raise').fit(X_train, y_train)
best_model_post = grid_search_post.best_estimator_ #make model with the best ccp_alpha
best_model_post.tree_.max_depth
Обновление 2:
Вот график зависимости оценки F1 (на основе тестовых данных) от альфа (рассчитанной по пути сокращения стоимости и сложности). Примечание. Это из моей старой процедуры, в которой я обучал модель на обучающих данных, но оценивал оценку F1 на тестовых данных. Если бы я оценивал F1 на обучающих данных, то он должен был бы быть самым высоким для самого сложного дерева. Я по-прежнему считаю, что метод перекрестной проверки данных о поездах, предложенный jgonz1, является лучшим способом продолжить, но для построения графика я думаю, что моя старая процедура имеет наибольший смысл.
F1 против альфа
Здесь я выполнил ту же процедуру, но на этот раз построил график зависимости точности от альфа.
Точность против альфа
Подробнее здесь: https://stackoverflow.com/questions/798 ... using-cost
Мобильная версия