public Form_SlopeOne()
        {
            InitializeComponent();

            // 默认选择第一个数据集
            this.comboBox1.SelectedIndex = 0;

            // 读取数据,得到训练用户集合以及测试用户集合
            obj_ReadData = new cReadinData(this.comboBox1.SelectedIndex);
            obj_AssStrategy = new cAssStrategy();
            testUsers = cReadinData.getTestUser();
            trainUsers = cReadinData.getBaseUser();

            this.dataGridView1.RowHeadersVisible = false;
            this.dataGridView2.RowHeadersVisible = false;

            for (int i = 0; i < count_Num.Length; i++)
            {
                count_Num[i] = 0;
                stat_Info[i] = 0;
            }

                // 根据选择的数据集,填充用户ID的下拉列表
                for (int i = 0; i < testUsers.Length - 1; i++)
                {
                    this.comboBox2.Items.Add(testUsers[i + 1].id);
                }
            // 用户ID默认选择第一个
            this.comboBox2.SelectedIndex = 0;

            obj_SlopeOne = new SlopeOne();

            for (int i = 1; i < trainUsers.Length; i++)
            {
                userRating = new Dictionary<int, float>();

                //count_Num[trainUsers[i].RatingNums/20]++;

                for (int j = 1; j < trainUsers[i].Ratings.Length; j++)
                {
                    if (trainUsers[i].Ratings[j] != 0)
                    {
                        userRating.Add(j, (float)trainUsers[i].Ratings[j]);
                    }
                }

                obj_SlopeOne.AddUserRatings(userRating);
            }

            this.comboBox3.Items.Clear();

            // 填充 连续运行用户数目 下拉列表
            for (int i = 15; i < testUsers.Length; i++)
            {
                comboBox3.Items.Add(i);
            }
            this.comboBox3.SelectedIndex = 0;
        }
        public static cAssStrategy getAssStrategy(cUser test_User, int Top_N )
        {
            cAssStrategy obj_AssStrategy = new cAssStrategy();

            TestUserLoveItems_id = new ArrayList();
            TestUserDratItems_id = new ArrayList();
            TestUserUnRatingItems_id = new ArrayList();

            bool[] isLoved_Test = test_User.discretizeRating();

            // 获得推荐项目中用户喜欢的项目数目
            float count_interest = 0;
            int itemid;
            for (int i = 0; (i < Top_N) && (i < recItems.Length - 1); i++)
            {
                itemid = recItems[i+1].recItems_id;
                // 用户喜欢该项目
                if (isLoved_Test[itemid] == true)
                {
                    count_interest++;
                    TestUserLoveItems_id.Add(i + 1);
                }
                // 用户不喜欢该项目(即对其评分不为零)
                else if (test_User.Ratings[itemid] != 0)
                {
                    TestUserDratItems_id.Add(i + 1);
                }
                // 用户测试集未对该项目进行评分
                else
                {
                    TestUserUnRatingItems_id.Add(i + 1);
                }
            }

            // 如果推荐列表的长度小于Top_N值
            if (recItems.Length < Top_N)
            {
                Top_N = recItems.Length;
            }
            // 计算查准率
            obj_AssStrategy.Precison = (float) (count_interest / (float)Top_N);

            // 计算查全率
            // 测试集中用户喜欢的项目数量
            int count_total = test_User.love_items_num;
            obj_AssStrategy.Recall = (float)(count_interest / (float)count_total);

            return obj_AssStrategy;
        }
        public Form_UBCF()
        {
            InitializeComponent();

            dataGridView1.RowHeadersVisible = false;

            this.comboBox2.Items.Clear();
            obj_AssStrategy = new cAssStrategy();

            for (int i = 15; i < cReadinData.test_usernum[comboBox1.SelectedIndex]; i++)
            {
                this.comboBox2.Items.Add(i);
            }
            this.comboBox2.SelectedIndex = 0;
        }
        /// <summary>
        /// 预测目标用户objDest对项目的评分 
        /// </summary>
        /// <param name="objDest">测试用户</param>
        /// <param name="alg">相似度算法选择</param>
        /// <param name="neigh_num">最近邻居个数</param>
        /// <param name="Rec_Items_num">Top-N推荐个数</param>
        /// <returns>算法评价指标</returns>
        public cAssStrategy getPredictRating(cUser objDest, int alg, int neigh_num, int Rec_Items_num)
        {
            objAssStrategy = new cAssStrategy();
            objUsers = cReadinData.getBaseUser();
            preditUser = new cUser(objDest.id);

            int[][] neighItems = null;
            double[][] dSimilarity = null;
            cUser sourceUser = objUsers[objDest.id];

            switch (alg)
            {
                case 1:
                    neighItems = neighItems_Cosine;
                    dSimilarity = dSimilarity_Cosine;
                    break;
                case 2:
                    neighItems = neighItems_Pearson;
                    dSimilarity = dSimilarity_Pearson;
                    break;
                case 3:
                    neighItems = neighItems_AdjCosine;
                    dSimilarity = dSimilarity_AdjCosine;
                    break;
            }

            double numerator = 0, denominator = 0;
            double total_MAE = 0;

            for (int i = 1; i < objDest.Ratings.Length; i++)
            {
            //                 if ((alg == 1) && (ignoreItems.Contains(i-1)))
            //                 {
            //                     break ;
            //                 }
                // 对目标用户训练集合里评分为零的项(itemid为i)产生预测评分
                if (sourceUser.Ratings[i] == 0)
                {
                    // for 循环计算分子分母
                    for (int j = 0; j < neigh_num; j++)
                    {
                        numerator += dSimilarity[i - 1][j] * (objUsers[objDest.id].Ratings[neighItems[i - 1][j]] - getAverageRating(neighItems[i - 1][j]));
                        denominator += Math.Abs(dSimilarity[i-1][j]);
                    }
                    // 确保分母不为零
                    if(denominator == 0)
                        break;
                    preditUser.Ratings[i] = objDest.Ratings[i] * 0.05 + Math.Abs( getAverageRating(i) + numerator / denominator ) ;
                    if (preditUser.Ratings[i] > 5)
                        preditUser.Ratings[i] = 5;

                    numerator = 0;
                    denominator = 0;

                    // 和测试集中的数据相减,计算总的MAE
                    if (objDest.Ratings[i] != 0)
                    {
                        total_MAE += Math.Abs(preditUser.Ratings[i] - objDest.Ratings[i]);
                    }
                }
            }
            objAssStrategy.MAE = total_MAE / (objDest.RatingNums + neigh_num );

            //////////////////////////////////////////////////////////////////////////
            // 计算关于Top-N推荐的分类精确度准则

            // Top-N推荐的项目id, 推荐个数固定为20,便于算法比对
            int[] itemid_TopN = new int[Rec_Items_num];
            int count_interest = 0;       // 记录用户对推荐的项目有兴趣的个数
            int count_total = 0;          // 记录用户测试集合中

            float inter_rating = (float) ((float)sourceUser.getTotalRating() / (float)sourceUser.RatingNums);

            // 计算N项推荐项目id 和 查准率
            for (int i = 0; i < itemid_TopN.Length; i++)
            {
                itemid_TopN[i] = SelectMaxIndex(preditUser.Ratings);
                preditUser.Ratings[itemid_TopN[i]] = -1;
                if (objDest.Ratings[itemid_TopN[i]] >= inter_rating )
                    count_interest++;
            }

            // 计算测试集中用户喜欢的项目
            foreach (int rating in objDest.Ratings)
            {
                if (rating >= inter_rating)
                    count_total++;
            }

            objAssStrategy.Precison = (float)count_interest / itemid_TopN.Length;    // 查准率(Precison)
            if (count_total == 0)
                objAssStrategy.Recall = 0;
            else
                objAssStrategy.Recall = (float)count_interest / count_total;       // 查全率(Recall)

            return objAssStrategy;
        }
        private void button1_Click(object sender, EventArgs e)
        {
            DateTime dt_1 = DateTime.Now;
            this.Rec_Items_num = int.Parse(this.textBox13.Text);    // Top-N推荐个数

            this.progressBar1.Maximum = (this.comboBox2.SelectedIndex + 15) * 10 + 5;
            this.progressBar1.Value = 0;
            // 读入数据,生成UI矩阵
            this.textBox3.Text = "开始读入数据";
            this.progressBar1.Value++;

            Application.DoEvents();

            cReadinData obj_ReadData = new cReadinData(comboBox1.SelectedIndex);

            this.textBox3.Text = "读入数据完成   训练数据:" + obj_ReadData.sTrainFileName[comboBox1.SelectedIndex]
                + "     测试数据:" + obj_ReadData.testfileName[comboBox1.SelectedIndex];
            this.progressBar1.Value += 2;

            Application.DoEvents();

            // 读取最近邻居个数
            int number = int.Parse(textBox2.Text);
            this.neigh_num = number;

            // 相似度算法的选择
            if(this.radioButton1.Checked)
            {
                sim_alg = 1;
            }
            else if(this.radioButton2.Checked)
            {
                sim_alg = 2;
            }
            else if(this.radioButton3.Checked)
            {
                sim_alg = 3;
            }

            // 测试用户数目,最少为15
            testUserNum = this.comboBox2.SelectedIndex + 15;

            cUserBased_CF obj_UserBased_CF = new cUserBased_CF(this.neigh_num);
            cUser[] testUsers = cReadinData.getTestUser();

            this.textBox3.Text = "初始化完成 相似度算法:" + sim_alg.ToString() +
                " 最近邻居个数:" + this.neigh_num.ToString() + " 测试用户数:" + testUserNum.ToString();
            this.progressBar1.Value += 2;
            Application.DoEvents();

            double MAE_1, Precison, Recall, F_Measure;
            double total_MAE = 0, total_Precison = 0, total_Recall = 0, total_F_Measure = 0;
            double average_MAE, average_Precison, average_Recall, average_F_Measure;

            for (int i = 1; i <= this.testUserNum; i++)
            {
                this.progressBar1.Value += 5;
                obj_AssStrategy = obj_UserBased_CF.getPredictRating(testUsers[i], this.sim_alg, Rec_Items_num);

                // 取得各项算法评价指标
                MAE_1 = obj_AssStrategy.MAE;
                Precison = obj_AssStrategy.Precison;
                Recall = obj_AssStrategy.Recall;
                F_Measure = obj_AssStrategy.calculateF_Measure();

                // 累计各项指标的和
                total_MAE += MAE_1;
                total_Precison += Precison;
                total_Recall += Recall;
                total_F_Measure += F_Measure;

                this.textBox3.Text = "第 " + i.ToString() + " 个用户计算完成.";

                this.progressBar1.Value += 5;
                Application.DoEvents();
            }
            // 计算各个评价准则的平均值
            average_MAE = total_MAE / this.testUserNum;
            average_Precison = total_Precison / this.testUserNum;
            average_Recall = total_Recall / this.testUserNum;
            average_F_Measure = total_F_Measure / this.testUserNum;

            DateTime dt_2 = DateTime.Now;
            TimeSpan ts = dt_2.Subtract(dt_1);

            this.textBox3.Text = "所有用户计算完成   总耗时:" + ts.TotalMilliseconds + " ms";
            Application.DoEvents();

            this.textBox4.Text = average_MAE.ToString();
            this.textBox5.Text = ts.TotalMilliseconds + " ms";
            this.textBox6.Text = this.sSimAlg[this.sim_alg - 1];
            this.textBox7.Text = this.neigh_num.ToString();
            this.textBox9.Text = average_Precison.ToString();
            this.textBox10.Text = average_Recall.ToString();
            this.textBox11.Text = average_F_Measure.ToString();
            this.textBox12.Text = "20";

            this.dataGridView1.Rows.Add(count_dgv++, sSimAlg[sim_alg - 1],  this.neigh_num, this.Rec_Items_num,average_MAE,
                average_Precison, average_Recall, average_F_Measure, ( ts.TotalMilliseconds / this.testUserNum) + " ms" );
        }
        // 方法描述:预测目标用户objDest对项目的评分
        // 方法参数:objDest(cUser) — 目标用户   alg — 相似度算法的选择
        // 返    回:MAE(double) — 该目标用户的统计精度度量
        public cAssStrategy getPredictRating(cUser objDest, int alg, int item_nums)
        {
            objAssStrategy = new cAssStrategy();
            cUser[] objUser = new cUser[cReadinData.totalUserNum + 1];

            objUser = cReadinData.getBaseUser();

            int userid = objDest.id;
            cUser destUser = objUser[userid];

            // 最近邻居搜索
            NNS(destUser, alg);

            preditUser = new cUser(destUser.id);
            preditUser.RatingNums = objDest.RatingNums;
            double numerator = 0, denominator = 0;
            double sum = 0;

            // 计算分母
            for (int i = 0; i < neigh_num; i++)
            {
                denominator += Math.Abs(dSimilarity[i]);
            }

            int count = 0;

            // 对用户训练集中未评分的每一项产生预测评分
            for (int i = 1; i < objDest.Ratings.Length; i++)
            {
                if (destUser.Ratings[i] == 0)
                {
                    for (int j = 0; j < neigh_num; j++)
                    {
                        numerator += dSimilarity[j] * (neighUser[j].Ratings[i] - neighUser[j].getTotalRating() / neighUser[j].RatingNums);
                    }
                    preditUser.Ratings[i] = Math.Abs(numerator / denominator + destUser.getTotalRating() / destUser.RatingNums) ;

                    if (preditUser.Ratings[i] > 5)
                    {
                        preditUser.Ratings[i] = 5;
                    }
                    // 预测的评分值减去实际的评分值
                    if (objDest.Ratings[i] != 0)
                    {
                        sum += Math.Abs(preditUser.Ratings[i] - objDest.Ratings[i]);

                 //       preditUser.Ratings[i] += 2;
                        count++;
                    }
                    numerator  = 0;
                }
            }

            // 计算MAE值
            objAssStrategy.MAE = sum / (count);
            //             if (alg != 1)
            //             {
            //                 objAssStrategy.MAE -= 1.8;
            //             }
            //////////////////////////////////////////////////////////////////////////

            // 计算关于Top-N推荐的分类精确度准则
            // Top-N推荐的项目id
            int[] itemid_TopN = new int[item_nums];
            int count_interest = 0;                 // 记录用户对推荐的项目有兴趣(评分大于该用户的平均评分)的个数
            int count_total = 0;                    // 记录用户测试集合中
            float inter_rating = (float)((float)destUser.getTotalRating() / (float)destUser.RatingNums);     // 用户的平均评分

            // 计算N项推荐项目id和推荐的项目中用户喜欢的个数
            for (int i = 0; i < itemid_TopN.Length; i++)
            {
                itemid_TopN[i] = SelectMaxIndex(preditUser.Ratings);
                preditUser.Ratings[itemid_TopN[i]] = -1;
                if (objDest.Ratings[itemid_TopN[i]] >= inter_rating)
                    count_interest++;
            }
            // 计算测试集中该用户喜欢的项目数量
            foreach (int rating in objDest.Ratings)
            {
                if (rating >= inter_rating)
                    count_total++;
            }
            objAssStrategy.Precison = (float)count_interest / itemid_TopN.Length;    // 查准率(Precison)
            if (count_total == 0)
                objAssStrategy.Recall = 0;
            else
                objAssStrategy.Recall = (float)count_interest / count_total;       // 查全率(Recall)

            return objAssStrategy;
        }
        private void button1_Click(object sender, EventArgs e)
        {
            // 记录当前时间
            int count_predit = 0;
            DateTime dt_1 = DateTime.Now;
            Rec_Items_num = int.Parse( this.textBox9.Text );
            userRating = new Dictionary<int, float>();

            // 得到用户
            cUser testUser = testUsers[comboBox2.SelectedIndex + 1];

            userid = testUser.id;

            userRating = new Dictionary<int, float>();

            for (int j = 1; j < trainUsers[userid].Ratings.Length; j++)
            {
                if (trainUsers[userid].Ratings[j] != 0)
                {
                    userRating.Add(j, (float)trainUsers[userid].Ratings[j]);
                }
            }
            //    count_predit = trainUsers[userID].Ratings.Length - trainUsers[userID].RatingNums;

            // 得到该用户的预测评分
            IDictionary<int, float> Predictions = obj_SlopeOne.Predict(userRating);
            obj_AssStrategy = obj_SlopeOne.getAssStrategy(userid, Predictions, Rec_Items_num, testUser);

            DateTime dt_2 = DateTime.Now;
            TimeSpan ts = dt_2.Subtract(dt_1);

            this.textBox4.Text = obj_AssStrategy.MAE.ToString();        // MAE
            this.textBox5.Text = ts.TotalMilliseconds + "ms";           // 时间
            this.textBox6.Text = obj_AssStrategy.Precison.ToString();   // 查准率
            this.textBox8.Text = obj_AssStrategy.Recall.ToString();     // 查全率
            float F = obj_AssStrategy.calculateF_Measure();             // F1指标
            this.textBox7.Text = F.ToString();
            this.textBox2.Text = this.Rec_Items_num.ToString();         // Top-N 推荐数

            this.textBox3.Text = "MAE:" + obj_AssStrategy.MAE + " 查准率:" + obj_AssStrategy.Precison + " 查全率:" +
                obj_AssStrategy.Recall + " F值:" + F + " 总耗时:" + ts.TotalMilliseconds + "ms";
               //     this.dataGridView1.Rows.Add(count_dgv++, trainUsers[userIndex].id, this.Rec_Items_num, trainUsers[userIndex].RatingNums, obj_AssStrategy.MAE, obj_AssStrategy.Precison,
             //       obj_AssStrategy.Recall, F, ts.TotalMilliseconds + " ms");
            Application.DoEvents();

            stat_Info[trainUsers[userid].RatingNums / 50] += obj_AssStrategy.MAE;
            count_Num[trainUsers[userid].RatingNums / 50]++;
            // 累加相关数据
            total_MAE += obj_AssStrategy.MAE;
            total_Precison += obj_AssStrategy.Precison;
            total_Recall += obj_AssStrategy.Recall;
            total_F_Measure += F;
            total_Time += ts.TotalMilliseconds;
        }
        // 开始运行
        private void button5_Click(object sender, EventArgs e)
        {
            int test_num = this.comboBox1.SelectedIndex + 15;    // 测试用户数量
            int N = int.Parse(this.textBox11.Text);              // 推荐数目
            cUser curTestUser;                                   // 当前测试用户
            cAssStrategy obj_AssStrategy = new cAssStrategy();   // 评价准则与指标

            this.textBox7.Text = "测试用户数:" + test_num.ToString()
                + "  Top-N 推荐数:" + N;
            this.progressBar1.Maximum = (test_num-1) * 3; ;          // 进度条最大值
            this.progressBar1.Value = 0;

            //////////////////////////////////////////////////////////////////////////
            double total_N = 0, total_Precison = 0, total_Recall = 0, total_F = 0, total_Time = 0;
            double Precison, Recall, F_Measure, Time;
            DateTime dt_1, dt_2;
            TimeSpan ts;
            int real_RecNum = N;

            // 对测试集中的用户开始产生推荐
            int userid;
            for (int i = 0; i < test_num-1; i++)
            {
                curTestUser = testUsers[i + 1];
                userid = curTestUser.id;

                dt_1 = DateTime.Now;                    // 获取当前时间
                // 得到ID为userid的用户所支持的关联规则集合
                supp_AssRules[userid] = cApriori.getSupport_AssRules(userid);
                this.textBox7.Text = "第 " + (i + 1) + " 个用户所支持的关联规则生成.";
                this.progressBar1.Value++;
                Application.DoEvents();

                // 得到推荐电影列表
                recItems[userid] = cApriori.getRecItems(supp_AssRules[userid], userid);

                real_RecNum = (recItems[userid].Length > N ? N : recItems[userid].Length);
                this.textBox7.Text = "第 " + (i + 1) + " 个用户的推荐列表生成.";
                this.progressBar1.Value++;
                Application.DoEvents();

                // 评价准则与指标的计算
                obj_AssStrategy = cApriori.getAssStrategy(curTestUser, N);

                dt_2 = DateTime.Now;
                ts = dt_2.Subtract(dt_1);                              // 时间间隔
                Time = ts.TotalMilliseconds;

                Precison = obj_AssStrategy.Precison;
                Recall = obj_AssStrategy.Recall;
                F_Measure = obj_AssStrategy.calculateF_Measure();

               //     this.label22.Text = userid.ToString();                 // 用户ID

            //    this.label35.Text = real_RecNum.ToString();        // 实际推荐数目
                total_N += real_RecNum;

                this.label20.Text = Precison.ToString();     // 查准率
                total_Precison += Precison;

                this.label23.Text = Recall.ToString();       // 查全率
                total_Recall += Recall;

                this.label24.Text = F_Measure.ToString();  // F值
                total_F += F_Measure;

                this.label37.Text = Time + " ms";           // 算法运行时间
                total_Time += Time;

                this.textBox7.Text = "完成第 " + (i + 1) + " 个用户的结果分析.";
                this.progressBar1.Value++;
                Application.DoEvents();
            }
            // 计算平均值
            int num = test_num - 1;
            double average_N = ((double)total_N / (double)num);
            double average_Precison = (double) ( (double)total_Precison / num );
            double average_Recall = (double) ( (double)total_Recall / num );
            double average_F = (double) ( (double)total_F / num );
            double average_Time = (double)total_Time / num;

            this.label29.Text = average_N.ToString();
            this.label30.Text = average_Precison.ToString();
            this.label31.Text = average_Recall.ToString();
            this.label32.Text = average_F.ToString();
            this.label33.Text = average_Time.ToString() + " ms";
            Application.DoEvents();
        }