Esempio n. 1
0
class Runner:

    #######################################################################################
    #                                 INSTANCE OF RUNNER                                  #
    #######################################################################################

    def __init__(self, recommender, name, evaluate=True):
        print("Evaluation: " + str(evaluate))
        self.recommender = recommender
        self.evaluate = evaluate
        self.name = name
        self.functionality = BaseFunction()

    #######################################################################################
    #                                     WRITE RESULT                                    #
    #######################################################################################

    def write_csv(self, rows, name):
        fields = FIELDS
        timestr = time.strftime("%Y-%m-%d_%H.%M.%S")
        file_path = "Results/" + name + "-" + timestr + ".csv"

        with open(file_path, 'w') as csv_file:
            csv_write_head = csv.writer(csv_file, delimiter=',')
            csv_write_head.writerow(fields)
            csv_write_content = csv.writer(csv_file, delimiter=' ')
            csv_write_content.writerows(rows)

    #######################################################################################
    #                                     RUN FITTNG                                      #
    #######################################################################################

    def fit_recommender(self,
                        requires_icm=False,
                        requires_ucm=False,
                        load_similarity=True):
        print("Fitting model...")
        ICM_all = self.functionality.ICM_all
        UCM_all = self.functionality.UCM_all

        if not self.evaluate:

            if requires_icm and requires_ucm:
                self.recommender.fit(self.functionality.URM_all, ICM_all,
                                     UCM_all)
            elif requires_icm:
                self.recommender.fit(self.functionality.URM_all, ICM_all)
            elif requires_ucm:
                self.recommender.fit(self.functionality.URM_all, UCM_all)
            else:
                self.recommender.fit(self.functionality.URM_all)
        else:
            self.functionality.split_80_20(0.8)
            if requires_icm and requires_ucm:
                self.recommender.fit(self.functionality.URM_train,
                                     ICM_all,
                                     UCM_all,
                                     tuning=True)
            elif requires_icm:
                self.recommender.fit(self.functionality.URM_train,
                                     ICM_all,
                                     tuning=True)
            elif requires_ucm:
                self.recommender.fit(self.functionality.URM_train,
                                     UCM_all,
                                     tuning=True)
            else:
                self.recommender.fit(self.functionality.URM_train, tuning=True)
        print("Model fitted")

    #######################################################################################
    #                                 RUN RECOMMENDATION                                  #
    #######################################################################################

    def run_recommendations(self):
        recommendations = []
        saved_tuple = []
        print("Computing recommendations...")
        for user in tqdm(self.functionality.userlist_unique):
            index = [str(user) + ","]
            recommendations.clear()

            for recommendation in self.recommender.recommend(user):
                recommendations.append(recommendation)
            saved_tuple.append(index + recommendations)
        print("Recommendations computed")
        if not self.evaluate:
            print("Printing csv...")
            self.write_csv(saved_tuple, self.name)
            print("Ended")
        return saved_tuple

    #######################################################################################
    #                                   RUN COMPUTATION                                   #
    #######################################################################################

    def run(self, requires_ucm=False, requires_icm=False):
        self.functionality.get_URM()

        if requires_icm:
            self.functionality.get_ICM()

        if requires_ucm:
            self.functionality.get_UCM()

        self.functionality.get_target_users()
        self.fit_recommender(requires_icm, requires_ucm)
        if not self.evaluate:
            # Recommendations on target users are necessary only during file printing
            self.run_recommendations()
        if self.evaluate:
            evaluation.evaluate_algorithm(self.functionality.URM_test,
                                          self.recommender,
                                          at=10)
Esempio n. 2
0
class BayesianSearch:

    #######################################################################################
    #                             INIT CLASS BAYESIAN SEARCH                              #
    #######################################################################################

    def __init__(self, recommender, name):
        self.recommender = recommender
        self.name = name
        self.helper = BaseFunction()
        self.helper.get_URM()
        self.helper.split_80_20()
        self.helper.get_target_users()
        self.helper.get_UCM()
        self.helper.get_ICM()
        self.optimazer = None

    def instanziate_optimazer(self, bayesian_method_call, pbounds):
        optimizer = BayesianOptimization(
            f=bayesian_method_call,
            pbounds=pbounds,
            verbose=
            2,  # verbose = 1 prints only when a maximum is observed, verbose = 0 is silent
        )

        optimizer.maximize(init_points=30, n_iter=1000, acq='ucb', kappa=0.1)

    #######################################################################################
    #                                   STEP TO MAXIMAXE                                  #
    #######################################################################################

    def step_hybrid_three(self, weight1=0, weight2=0, weight3=0):
        start_time = time.time()
        UCM_all = self.helper.UCM_all
        ICM_all = self.helper.ICM_all
        self.recommender.fit(self.helper.URM_train,
                             ICM_all=ICM_all,
                             UCM_all=UCM_all,
                             weights=[weight1, weight2, weight3],
                             tuning=True)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_hybrid_four(self, weight1=0, weight2=0, weight3=0, weight4=0):
        start_time = time.time()
        UCM_all = self.helper.UCM_all
        ICM_all = self.helper.ICM_all
        self.recommender.fit(self.helper.URM_train,
                             ICM_all=ICM_all,
                             UCM_all=UCM_all,
                             weights=[weight1, weight2, weight3, weight4],
                             tuning=True)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_hybrid_six(self,
                        weight1=0,
                        weight2=0,
                        weight3=0,
                        weight4=0,
                        weight5=0,
                        weight6=0):
        start_time = time.time()
        UCM_all = self.helper.UCM_all
        ICM_all = self.helper.ICM_all
        self.recommender.fit(
            self.helper.URM_train,
            ICM_all=ICM_all,
            UCM_all=UCM_all,
            weights=[weight1, weight2, weight3, weight4, weight5, weight6],
            tuning=True)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_hybrid_seven(self,
                          weight1=0,
                          weight2=0,
                          weight3=0,
                          weight4=0,
                          weight5=0,
                          weight6=0,
                          weight7=0):
        start_time = time.time()
        UCM_all = self.helper.UCM_all
        ICM_all = self.helper.ICM_all
        self.recommender.fit(self.helper.URM_train,
                             ICM_all=ICM_all,
                             UCM_all=UCM_all,
                             weights=[
                                 weight1, weight2, weight3, weight4, weight5,
                                 weight6, weight7
                             ],
                             tuning=True)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_fallBack_Hybrid(self, weight1=0, weight2=0):
        start_time = time.time()
        UCM_all = self.helper.UCM_all
        ICM_all = self.helper.ICM_all
        self.recommender.fit(self.helper.URM_train,
                             ICM_all=ICM_all,
                             UCM_all=UCM_all,
                             weights_fallback=[int(weight1),
                                               int(weight2)],
                             tuning=True)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_slim(self, weight1=0, weight2=0, weight3=0):
        start_time = time.time()
        self.recommender = SLIM_BPR_Cython(lambda_i=weight1,
                                           lambda_j=weight2,
                                           learning_rate=weight3)
        self.recommender.fit(self.helper.URM_train)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_elastic(self, weight1=0, weight2=0, weight3=0):
        start_time = time.time()
        self.recommender.fit(self.helper.URM_train,
                             l1_ratio=weight1,
                             alpha=weight2,
                             topK=int(weight3))
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_ALS(self, weight1=0, weight2=0, weight3=0):
        start_time = time.time()
        self.recommender = AlternatingLeastSquare(n_factors=int(weight1),
                                                  regularization=weight2,
                                                  iterations=int(weight3))
        self.recommender.fit(self.helper.URM_train)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_Item_CB(self, weight1=0, weight2=0):
        start_time = time.time()
        ICM_all = self.helper.ICM_all
        self.recommender.fit(self.helper.URM_train,
                             ICM_all,
                             knn=int(weight1),
                             shrink=int(weight2),
                             tuning=False)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_User_CB(self, weight1=0, weight2=0):
        start_time = time.time()
        UCM_all = self.helper.UCM_all
        self.recommender.fit(self.helper.URM_train,
                             UCM_all,
                             knn=int(weight1),
                             shrink=int(weight2))
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_P3Alpha(self, weight1=0, weight2=0):
        start_time = time.time()
        self.recommender.fit(self.helper.URM_train,
                             topK=int(weight1),
                             alpha=weight2)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_RP3Beta(self, alpha=0, beta=0, min_rating=0, topK=0):
        start_time = time.time()
        self.recommender.fit(self.helper.URM_train,
                             alpha=alpha,
                             beta=beta,
                             min_rating=min_rating,
                             topK=int(topK))
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_PureSVD_randomSVD(self, n_components, n_iter):
        start_time = time.time()
        self.recommender.fit(self.helper.URM_train,
                             n_components=int(n_components),
                             n_iter=int(n_iter))
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_FunkSVD(self, epoch, num_factors, learning_rate, user_reg,
                     item_reg):
        start_time = time.time()
        self.recommender = MatrixFactorization_FunkSVD_Cython(
            int(epoch), int(num_factors), learning_rate, user_reg, item_reg)
        self.recommender.fit(self.helper.URM_train)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_TEST(self, t1, t2, t3, t4, t5):
        start_time = time.time()
        UCM_all = self.helper.UCM_all
        ICM_all = self.helper.ICM_all
        self.recommender = Hybrid_User_Wise("Hybrid User Wise",
                                            UserCBFKNNRecommender())
        self.recommender.fit(self.helper.URM_train,
                             ICM_all=ICM_all,
                             UCM_all=UCM_all,
                             thre1=t1,
                             thre2=t2,
                             thre3=t3,
                             thre4=t4,
                             thre5=t5,
                             tuning=True)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    def step_all(self,
                 H0_ICF_sh=0,
                 H0_ICF_tK=0,
                 H1_UCF_sh=0,
                 H1_UCF_tK=0,
                 H2_ICB_sh=0,
                 H2_ICB_tK=0,
                 H3_UCB_sh=0,
                 H3_UCB_tK=0,
                 H4_El_tK=0,
                 H5_RP3_a=0,
                 H5_RP3_b=0,
                 H5_RP3_tK=0,
                 H6_SL_bs=0,
                 H6_SL_ep=0,
                 H6_SL_l_i=0,
                 H6_SL_l_j=0,
                 H6_SL_l_r=0,
                 H6_SL_tK=0,
                 H7_ALS_i=0,
                 H7_ALS_nf=0,
                 H7_ALS_re=0,
                 weight1=0,
                 weight2=0,
                 weight3=0,
                 weight4=0,
                 weight5=0,
                 weight6=0,
                 weight7=0):

        start_time = time.time()
        UCM_all = self.helper.UCM_all
        ICM_all = self.helper.ICM_all

        ItemCF = ItemKNNCFRecommender()
        UserCF = UserKNNCFRecommender()
        ItemCB = ItemCBFKNNRecommender()
        UserCB = UserCBFKNNRecommender()
        ElasticNet = SLIMElasticNetRecommender()
        RP3Beta = RP3BetaRecommender()
        Slim = SLIM_BPR_Cython(batch_size=int(H6_SL_bs),
                               epochs=int(H6_SL_ep),
                               lambda_i=H6_SL_l_i,
                               lambda_j=H6_SL_l_j,
                               learning_rate=H6_SL_l_r,
                               topK=int(H6_SL_tK))
        ALS = AlternatingLeastSquare(iterations=int(H7_ALS_i),
                                     n_factors=int(H7_ALS_nf),
                                     regularization=H7_ALS_re)

        ItemCF.fit(self.helper.URM_train, knn=int(H0_ICF_tK), shrink=H0_ICF_sh)
        UserCF.fit(self.helper.URM_train, knn=int(H1_UCF_tK), shrink=H1_UCF_sh)
        ItemCB.fit(self.helper.URM_train,
                   ICM_all,
                   knn=int(H2_ICB_tK),
                   shrink=H2_ICB_sh)
        UserCB.fit(self.helper.URM_train,
                   UCM_all,
                   knn=int(H3_UCB_tK),
                   shrink=H3_UCB_sh)
        ElasticNet.fit(self.helper.URM_train, topK=int(H4_El_tK))
        RP3Beta.fit(self.helper.URM_train,
                    alpha=H5_RP3_a,
                    beta=H5_RP3_b,
                    topK=int(H5_RP3_tK))
        Slim.fit(self.helper.URM_train)
        ALS.fit(self.helper.URM_train)

        self.recommender = Hybrid_Achille_Tuning("Hybrid_Achille_Tuning_All",
                                                 UserCB)
        self.recommender.fit(self.helper.URM_train,
                             ICM_all=ICM_all,
                             UCM_all=UCM_all,
                             weights=[
                                 weight1, weight2, weight3, weight4, weight5,
                                 weight6, weight7
                             ],
                             ItemCF=ItemCF,
                             UserCF=UserCF,
                             ItemCB=ItemCB,
                             ElasticNet=ElasticNet,
                             RP3=RP3Beta,
                             Slim=Slim,
                             ALS=ALS)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative
Esempio n. 3
0
class ClassesRating:
    def __init__(self):
        self.helper = BaseFunction()
        self.URM = None
        self.URM_train = None
        self.URM_test = None
        self.URM = self.helper.get_URM()
        self.helper.split_80_20()
        self.URM_train, self.URM_test = self.helper.URM_train, self.helper.URM_test
        self.helper.get_ICM()
        self.helper.get_UCM()
        self.helper.get_target_users()
        self.ICM_all = self.helper.ICM_all
        self.UCM_all = self.helper.UCM_all
        self.initial_target_user = self.helper.userlist_unique

        MAP_ItemCF_per_group = []
        MAP_UserCF_per_group = []
        MAP_ItemCBF_per_group = []
        MAP_UserCBF_per_group = []
        MAP_ItemCBF_BM25_per_group = []
        MAP_UserCBF_BM25_per_group = []
        MAP_ItemCBF_TFIDF_per_group = []
        MAP_UserCBF_TFIDF_per_group = []
        MAP_Slim_per_group = []
        MAP_Elastic_per_group = []
        MAP_PureSVD_per_group = []
        MAP_P3Alpha_per_group = []
        MAP_RP3Beta_per_group = []
        MAP_ALS_per_group = []
        MAP_Hybrid2_per_group = []
        MAP_Hybrid6_per_group = []
        MAP_H6_bis_per_group = []
        MAP_Hybrid7_per_group = []
        MAP_Hybrid8_per_group = []
        MAP_HybridCB_per_group = []

        self.profile_length = np.ediff1d(self.URM_train.indptr)
        self.blocksize = int(len(self.profile_length) * 0.05)
        self.sortedusers = np.argsort(self.profile_length)

        self.ItemCF = ItemKNNCFRecommender()
        self.UserCF = UserKNNCFRecommender()
        self.ItemCBF = ItemCBFKNNRecommender()
        self.UserCBF = UserCBFKNNRecommender()
        self.Slim = SLIM_BPR_Cython()
        self.Elastic = SLIMElasticNetRecommender()
        self.PureSVD = PureSVDRecommender()
        self.P3Alpha = P3AlphaRecommender()
        self.RP3Beta = RP3BetaRecommender()
        self.ALS = AlternatingLeastSquare()
        self.H6_bis = Hybrid_Combo6_bis("Combo6_bis", UserCBFKNNRecommender())

        self.ItemCBF.fit(
            self.URM_train,
            self.ICM_all,
            tuning=True,
            similarity_path="/SimilarityProduct/ItemCBF_similarity.npz")
        self.UserCBF.fit(
            self.URM_train,
            self.UCM_all,
            tuning=True,
            similarity_path="/SimilarityProduct/UserCBF_similarity.npz")
        self.ItemCF.fit(
            self.URM_train,
            tuning=True,
            similarity_path="/SimilarityProduct/ItemCF_similarity.npz")
        self.UserCF.fit(
            self.URM_train,
            tuning=True,
            similarity_path="/SimilarityProduct/UserCF_similarity.npz")
        self.Slim.fit(self.URM_train,
                      tuning=True,
                      similarity_path="/SimilarityProduct/Slim_similarity.npz")
        self.Elastic.fit(
            self.URM_train,
            tuning=True,
            similarity_path="/SimilarityProduct/Elastic_similarity.npz")
        self.PureSVD.fit(self.URM_train)
        self.P3Alpha.fit(
            self.URM_train,
            tuning=True,
            similarity_path="/SimilarityProduct/P3Aplha_similarity.npz")
        self.RP3Beta.fit(
            self.URM_train,
            tuning=True,
            similarity_path="/SimilarityProduct/RP3Beta_similarity.npz")
        self.ALS.fit(self.URM_train)
        self.H6_bis.fit(self.URM_train,
                        self.ICM_all,
                        self.UCM_all,
                        tuning=True)

        for group_id in range(0, 20):
            start_pos = group_id * self.blocksize
            end_pos = min((group_id + 1) * self.blocksize,
                          len(self.profile_length))

            users_in_group = self.sortedusers[start_pos:end_pos]

            users_in_group_p_len = self.profile_length[users_in_group]

            print("Group {}, average p.len {:.2f}, min {}, max {}".format(
                group_id, users_in_group_p_len.mean(),
                users_in_group_p_len.min(), users_in_group_p_len.max()))
            users_not_in_group_flag = np.isin(self.sortedusers,
                                              users_in_group,
                                              invert=True)
            users_not_in_group = self.sortedusers[users_not_in_group_flag]

            users_in_group = list(
                set(self.initial_target_user) - set(list(users_not_in_group)))

            results = evaluate_algorithm_classes(self.URM_test,
                                                 users_in_group,
                                                 self.ItemCBF,
                                                 at=10)
            MAP_ItemCBF_per_group.append(results)

            results = evaluate_algorithm_classes(self.URM_test,
                                                 users_in_group,
                                                 self.ItemCF,
                                                 at=10)
            MAP_ItemCF_per_group.append(results)

            results = evaluate_algorithm_classes(self.URM_test,
                                                 users_in_group,
                                                 self.UserCF,
                                                 at=10)
            MAP_UserCF_per_group.append(results)

            results = evaluate_algorithm_classes(self.URM_test,
                                                 users_in_group,
                                                 self.Slim,
                                                 at=10)
            MAP_Slim_per_group.append(results)

            results = evaluate_algorithm_classes(self.URM_test,
                                                 users_in_group,
                                                 self.Elastic,
                                                 at=10)
            MAP_Elastic_per_group.append(results)

            results = evaluate_algorithm_classes(self.URM_test,
                                                 users_in_group,
                                                 self.PureSVD,
                                                 at=10)
            MAP_PureSVD_per_group.append(results)

            results = evaluate_algorithm_classes(self.URM_test,
                                                 users_in_group,
                                                 self.P3Alpha,
                                                 at=10)
            MAP_P3Alpha_per_group.append(results)

            results = evaluate_algorithm_classes(self.URM_test,
                                                 users_in_group,
                                                 self.RP3Beta,
                                                 at=10)
            MAP_RP3Beta_per_group.append(results)

            results = evaluate_algorithm_classes(self.URM_test,
                                                 users_in_group,
                                                 self.UserCBF,
                                                 at=10)
            MAP_UserCBF_per_group.append(results)

            results = evaluate_algorithm_classes(self.URM_test,
                                                 users_in_group,
                                                 self.ALS,
                                                 at=10)
            MAP_ALS_per_group.append(results)

            results = evaluate_algorithm_classes(self.URM_test,
                                                 users_in_group,
                                                 self.H6_bis,
                                                 at=10)
            MAP_H6_bis_per_group.append(results)

        pyplot.plot(MAP_UserCBF_per_group, label="UserCBF")
        pyplot.plot(MAP_ItemCBF_per_group, label="ItemCBF")
        pyplot.plot(MAP_ItemCF_per_group, label="ItemCF")
        pyplot.plot(MAP_UserCF_per_group, label="UserCF")
        pyplot.plot(MAP_Slim_per_group, label="Slim")
        pyplot.plot(MAP_Elastic_per_group, label="Elastic")
        pyplot.plot(MAP_P3Alpha_per_group, label="P3Alpha")
        pyplot.plot(MAP_RP3Beta_per_group, label="RP3Beta")
        pyplot.plot(MAP_PureSVD_per_group, label="PureSVD")
        pyplot.plot(MAP_ALS_per_group, label="ALS")
        pyplot.plot(MAP_H6_bis_per_group, label="H6_bis")

        pyplot.xlabel('User Group')
        pyplot.ylabel('MAP')
        pyplot.xticks(np.arange(0, 20, 1))
        pyplot.grid(b=True,
                    axis='both',
                    color='firebrick',
                    linestyle='--',
                    linewidth=0.5)
        pyplot.legend(loc='lower right')
        pyplot.show()
Esempio n. 4
0
class Tuner_Singles():

    #######################################################################################
    #                                      INIT CLASS                                     #
    #######################################################################################

    def __init__(self, recommender, name):
        self.recommender = recommender
        self.name = name
        self.helper = BaseFunction()
        self.helper.get_URM()
        self.helper.get_ICM()
        self.helper.get_UCM()
        self.helper.split_80_20()
        self.helper.get_target_users()

    #######################################################################################
    #                                    TEP FOR TUNING                                   #
    #######################################################################################

    def step_weight(self, w1, w2):
        start_time = time.time()
        print("----------------------------------------")
        print("HybridCombination: " + self.name)
        print([w1, w2])
        print("----------------------------------------")
        list_UCM = [self.helper.UCM_age, self.helper.UCM_region]
        list_ICM = [
            self.helper.ICM, self.helper.ICM_price, self.helper.ICM_asset
        ]
        self.recommender.fit(self.helper.URM_train, [w1, w2],
                             list_ICM=list_ICM,
                             list_UCM=list_UCM,
                             tuning=False)
        cumulative = evaluation.evaluate_algorithm(self.helper.URM_test,
                                                   self.recommender,
                                                   at=10)
        elapsed_time = time.time() - start_time
        print("----------------" + str(elapsed_time) + "----------------")
        return cumulative

    #######################################################################################
    #                                  GENETIC ALGORITHM                                  #
    #######################################################################################

    def random_pop(self):
        weights = []

        for i in range(self.pop_size):
            w1 = random.randint(250, 600)  # epoch
            w2 = random.randint(100, 300)  # knn
            line = [w1, w2]
            weights.append(np.array(line))

        return weights

    def evaluate_pop(self):
        appo = []
        for chromosome in self.pop:
            res = self.evaluate_chromosome(chromosome)
            appo.append(res)
        return appo

    def evaluate_chromosome(self, chromosome):
        return self.step_weight(w1=chromosome[0], w2=chromosome[1])

    def my_index(self, l, item):
        for i in range(len(l)):
            if (item == l[i]).all():
                return i
        return -1

    def select_parents(self):
        sorted_pop_score = sorted(self.pop_scores, reverse=False)
        probs = []
        taken_pop = [False] * self.pop_size
        taken_score = [False] * self.pop_size

        l = (self.pop_size * (self.pop_size + 1)) / 2

        for i in self.pop:
            pos_of_i_in_pop = self.my_index(self.pop, i)
            while taken_pop[pos_of_i_in_pop]:
                pos_of_i_in_pop += self.my_index(
                    self.pop[pos_of_i_in_pop + 1:], i) + 1

            score_of_pos = self.pop_scores[pos_of_i_in_pop]
            ranking = self.my_index(sorted_pop_score, score_of_pos)

            while taken_score[ranking]:
                ranking += self.my_index(sorted_pop_score[ranking + 1:],
                                         score_of_pos) + 1

            taken_score[ranking] = True
            taken_pop[pos_of_i_in_pop] = True
            prob = (ranking + 1) / l
            probs.append(prob)

        parents = [
            self.pop[i] for i in np.random.choice(len(self.pop), 2, p=probs)
        ]

        return parents

    def generate_offspring(self, p1, p2):
        size = len(p1)
        offspring = np.empty((size), dtype='object')

        offspring[0] = p1[0]
        offspring[1] = p2[1]

        return offspring

    def crossover(self, parents):
        offspring1 = self.generate_offspring(parents[0], parents[1])
        offspring2 = self.generate_offspring(parents[1], parents[0])
        offspring1 = self.mutation(offspring1)
        offspring2 = self.mutation(offspring2)

        return offspring1, offspring2

    def mutation(self, offspring):
        if np.random.choice([True, False],
                            1,
                            p=[self.p_mutation, 1 - self.p_mutation]) == True:
            offspring += random.randint(0, 100)
        return offspring

    def elitism(self):
        els = self.pop[:]
        score_c = self.pop_scores[:]

        for _ in range(4):
            index = np.argmax(score_c)
            score_c.pop(index)
            self.new_pop.append(els.pop(index))

    #######################################################################################
    #                               RUN GENETIC ALGORITHM                                 #
    #######################################################################################

    def run(self, max=1000, pop_size=10, p_mutation=0.1):
        self.pop_size = pop_size
        self.p_mutation = p_mutation

        self.pop = self.random_pop()
        self.pop_scores = self.evaluate_pop()
        for i in range(max):
            self.new_pop = []
            self.elitism()
            while len(self.new_pop) < len(self.pop):
                parents = self.select_parents()
                off1, off2 = self.crossover(parents)
                self.new_pop.append(off1)
                self.new_pop.append(off2)
            self.pop = self.new_pop
            self.pop_scores = self.evaluate_pop()
            print("-----------------ENDED------------------")
            print(self.pop)
            print(np.argmax(self.pop_scores))
            print("----------------------------------------")