#algorithm #machine-learning #classification #adaboost #boosting
Вопрос:
Я сам пытался написать алгоритм AdaBoost, используя пни решений и индекс Джини для расщеплений. Вот код:
class AdaBoost:
def main(x,y):
# set the weights to 1/n
weights=np.empty(x.shape[0])
weights.fill(1/x.shape[0])
classifier_weights=[]
features=[]
thresholds=[]
for i in range(4):
# create decision stump
feature,threshold=AdaBoost.find_split(x,y,weights)
features.append(feature)
thresholds.append(threshold)
# evaluate decision stump
final_say,predictions=AdaBoost.evaluate_classifier(x,y,weights,feature,threshold)
classifier_weights.append(final_say)
# adjust sample weights
weights=AdaBoost.adjust_sample_weights(x,y,weights,final_say,predictions)
# classification
classification=0
predictions=[]
for i in range(x.shape[0]):
for j in range(len(features)):
if x[i,features[j]]>thresholds[j]:
y_hat=1
else:
y_hat=-1
classification =classifier_weights[j]*y_hat
if classification>0:
predictions.append(1)
else:
predictions.append(-1)
classification=0
# classification accuracy
correct=0
for i in range(x.shape[0]):
if predictions[i]==y[i]:
correct =1
accuracy=correct/x.shape[0]
return accuracy, features, thresholds
def find_split(x,y,weights):
gini=[]
feature_gini=[]
thresholds=[]
for i in range(x.shape[1]): # cycle through features
for j in range(x.shape[0]): # cycle through all values and evaluate as thresholds
gini.append(AdaBoost.evaluate_num_split(x,y,weights,i,x[j,i]))
feature_gini.append(min(gini))
thresholds.append(gini.index(min(gini)))
gini=[]
# feature_gini is a list containing the lowest gini value for every feature
# therefore, the split occurs on the feature with the lowest min gini
feature=feature_gini.index(min(feature_gini))
# we also need to know which threshold lead to this lowest gini
threshold=x[thresholds[feature],feature]
return feature, threshold
def evaluate_num_split(x,y,weights,feature,threshold): # evaluate split with numeric values
ye=[]
nah=[]
# loop puts index of samples into corresponding lists so that
# we can access both x and y via the index
for i in range(x.shape[0]):
if x[i,feature]>threshold:
ye.append(i)
else:
nah.append(i)
return AdaBoost.evaluate_gini(ye,nah,x,y,weights)
def evaluate_gini(ye,nah,x,y,weights):
# evaluate Gini index
weights_ye=0
weights_nah=0
corr=0
wrong=0
# determine weights for yes and no
for i in ye:
weights_ye =weights[i]
for i in nah:
weights_nah =weights[i]
# prevent an error for dividing by zero later
if weights_ye==0:
return 100
elif weights_nah==0:
return 100
else:
pass
# determine gini for 'yes' leaf
for i in ye:
if y[i]==1:
corr =weights[i]
else:
wrong =weights[i]
gini_ye=1-(corr/weights_ye)**2-(wrong/weights_ye)**2
# determine gini for 'no' leaf
corr=0
wrong=0
for i in nah:
if y[i]==1:
corr =weights[i]
else:
wrong =weights[i]
gini_nah=1-(corr/weights_nah)**2-(wrong/weights_nah)**2
return weights_ye*gini_ye weights_nah*gini_nah # return weighted gini between both leaves
def evaluate_classifier(x,y,weights,feature,threshold):
total_error=0
predictions=[]
for i in range(x.shape[0]):
if x[i,feature]>threshold:
y_hat=1
else:
y_hat=-1
if y_hat!=y[i]:
total_error =weights[i]
else:
pass
predictions.append(y_hat)
return 0.5*np.log((1-total_error)/total_error), predictions
def adjust_sample_weights(x,y,weights,final_say, predictions):
summation=0
for i in range(x.shape[0]):
weights[i]=weights[i] np.exp(-y[i]*predictions[i]*final_say)
for i in weights:
summation =i
for i in range(x.shape[0]):
weights[i]=weights[i]/summation
return weights
Я использовал набор данных о диабете с 12 функциями и более чем 400 образцами. После создания первого пня принятия решения точность составляет 60%. Вторая культя также отлично работает и повышает точность до 68%. Но затем следующие пни повторяют эти же два раскола снова и снова. Они разделяются на одну и ту же функцию с одинаковым порогом. Может быть, я неправильно регулирую вес. Я весь день пытался устранить неполадки в коде и обнаружил некоторые ошибки, но не могу понять, что здесь не так.
Вызов основной функции создает следующий вывод. Возвращается точность классификации в обучающем наборе, список функций, на которые разделяются пни принятия решений, и список выбранных пороговых значений для разделения:
AdaBoost.main(x,y)
(0.6780045351473923, [5, 2, 5, 2], [44.0, 88.0, 44.0, 88.0])
P. S: Я уверен, что код слишком запутан и сложен для того, что я пытаюсь здесь сделать. Я новичок в программировании, поэтому, если я систематически делаю что-то слишком сложное или неправильное, пожалуйста, скажите мне.
Большое спасибо за чтение всего этого грязного кода. Сделал все возможное, чтобы прокомментировать это.