Springboot+vue.js+協(xié)同過濾推薦+余弦相似度算法實(shí)現(xiàn)新聞推薦系統(tǒng)

針對海量的新聞資訊數(shù)據(jù),如何快速的根據(jù)用戶的檢索需要,完成符合用戶閱讀需求的新聞資訊推薦?本篇文章主要采用余弦相似度及基于用戶協(xié)同過濾算法實(shí)現(xiàn)新聞推薦,通過余弦相似度算法完成針對不同新聞數(shù)據(jù)之間的相似性計(jì)算,實(shí)現(xiàn)分類標(biāo)簽。通過協(xié)同過濾算法發(fā)現(xiàn)具備相似閱讀習(xí)慣的用戶,展開個性化推薦。
本次新聞推薦系統(tǒng):

主要包含技術(shù):springboot,mybatis,mysql,javascript,vue.js,html,css
主要包含算法:余弦相似度,基于用戶協(xié)同過濾推薦

一、系統(tǒng)設(shè)計(jì)

系統(tǒng)采用前后端分離的開發(fā)模式完成,系統(tǒng)前端主要采用Vue.js,javascript,html,CSS等技術(shù)實(shí)現(xiàn)。系統(tǒng)后端框架采用springboot+mybatis+mysql數(shù)據(jù)庫搭建,針對海量的新聞資訊數(shù)據(jù)采用分表操作,完成數(shù)據(jù)存儲分析。系統(tǒng)前后端數(shù)據(jù)交互,采用Ajax異步調(diào)用傳輸JSON實(shí)現(xiàn)。系統(tǒng)架構(gòu)主要分為基礎(chǔ)數(shù)據(jù)存儲,新聞資訊爬蟲,新聞分析計(jì)算,新聞網(wǎng)站前端四個層面,其中爬蟲主要定時采集互聯(lián)網(wǎng)各大新聞網(wǎng)站的公開資訊數(shù)據(jù),完成數(shù)據(jù)清洗,過濾等操作。系統(tǒng)主要架構(gòu)設(shè)計(jì)如下如:


image.png

二、效果實(shí)現(xiàn)

登錄界面

image.png

系統(tǒng)主頁

image.png

推薦列表

image.png

新聞搜索

image.png

新聞詳情

image.png

瀏覽歷史

image.png

其他效果省略

三、系統(tǒng)算法介紹

余弦相似度算法

余弦相似度,又稱為余弦相似性,是通過計(jì)算兩個向量的夾角余弦值來評估他們的相似度。余弦相似度將向量根據(jù)坐標(biāo)值,繪制到向量空間中,如最常見的二維空間。
余弦相似度衡量的是2個向量間的夾角大小,通過夾角的余弦值表示結(jié)果,因此2個向量的余弦相似度為:


image.png

分子為向量A與向量B的點(diǎn)乘,分母為二者各自的L2相乘,即將所有維度值的平方相加后開方。
余弦相似度的取值為[-1,1],值越大表示越相似。

余弦相似度java代碼實(shí)現(xiàn)

 public static double getSimilarity(String doc1, String doc2) {
       if (doc1 != null && doc1.trim().length() > 0 && doc2 != null && doc2.trim().length() > 0){
            Map<Integer, int[]> AlgorithmMap = new HashMap<Integer, int[]>();
            //將兩個字符串中的中文字符以及出現(xiàn)的總數(shù)封裝到,AlgorithmMap中
            for (int i = 0; i < doc1.length(); i++) {
                char d1 = doc1.charAt(i);
                if (isHanZi(d1)) {//標(biāo)點(diǎn)和數(shù)字不處理
                    int charIndex = getGB2312Id(d1);//保存字符對應(yīng)的GB2312編碼
                    if (charIndex != -1) {
                        int[] fq = AlgorithmMap.get(charIndex);
                        if (fq != null && fq.length == 2) {
                            fq[0]++;//已有該字符,加1
                        } else {
                            fq = new int[2];
                            fq[0] = 1;
                            fq[1] = 0;
                            AlgorithmMap.put(charIndex, fq);//新增字符入map
                        }
                    }
                }
            }
            for (int i = 0; i < doc2.length(); i++) {
                char d2 = doc2.charAt(i);
                if (isHanZi(d2)) {
                    int charIndex = getGB2312Id(d2);
                    if (charIndex != -1) {
                        int[] fq = AlgorithmMap.get(charIndex);
                        if (fq != null && fq.length == 2) {
                            fq[1]++;
                        } else {
                            fq = new int[2];
                            fq[0] = 0;
                            fq[1] = 1;
                            AlgorithmMap.put(charIndex, fq);
                        }
                    }
                }
            }
            Iterator<Integer> iterator = AlgorithmMap.keySet().iterator();
            double sqdoc1 = 0;
            double sqdoc2 = 0;
            double denominator = 0;
            while (iterator.hasNext()) {
                int[] c = AlgorithmMap.get(iterator.next());
                denominator += c[0] * c[1];
                sqdoc1 += c[0] * c[0];
                sqdoc2 += c[1] * c[1];
            }
            double v = denominator / Math.sqrt(sqdoc1 * sqdoc2);//余弦計(jì)算
            v = Double.isNaN(v) ? 0d : v;
            return v;
        } else {
            throw new NullPointerException(" the Document is null or have not cahrs!!");
        }
    }

協(xié)同過濾推薦算法

協(xié)同過濾算法是一個大類,主要有基于用戶、基于物品、兩者結(jié)合等分支,這里我主要介紹的是基于用戶的協(xié)同過濾算法。主要的思想也很簡單,中國有一句俗語“物以類聚,人以群分”,我們可以有很大的把握認(rèn)為一個和你很相似的用戶喜歡的物品也大概率也是你喜歡的物品,這就是基于用戶的協(xié)同過濾推薦算法的思想。實(shí)現(xiàn)基于用戶協(xié)同過濾推薦,主要包含以下幾個步驟:

1.計(jì)算用戶相似度
2.獲取需要推薦給用戶的物品(本系統(tǒng)內(nèi)主要是新聞數(shù)據(jù))

基于用戶協(xié)同推薦算法實(shí)現(xiàn)

/***
     * 協(xié)同過濾算法
     * 1. 找到與目標(biāo)用戶興趣相似的用戶集合
     * 2. 找到這個集合中用戶喜歡的、并且目標(biāo)用戶沒有聽說過的新聞推薦給目標(biāo)用戶
     * @param userInfos
     * @param recommendUser
     * @return
     */
    public static List<GPair<String, Double>> XtglNewsTj(List<GPair<String, List<String>>> userInfos, String recommendUser) {
        int N = userInfos.size();
        //建立用戶稀疏矩陣,用于用戶相似度計(jì)算【相似度矩陣】
        int[][] sparseMatrix = new int[N][N];
        //存儲每個用戶對應(yīng)的不同總數(shù)eg: A 3
        Map<String, Integer> userItemLength = new HashMap<>();
        //建立新聞到用戶的倒排表 eg: a A B
        Map<String, Set<String>> itemUserCollection = new HashMap<>();
        Set<String> items = new HashSet<>();//輔助存儲新聞集合
        Map<String, Integer> userID = new HashMap<>();//輔助存儲每一個用戶的用戶ID映射
        Map<Integer, String> idUser = new HashMap<>();//輔助存儲每一個ID對應(yīng)的用戶映射
        for(int i = 0; i < N ; i++){//依次處理N個用戶 輸入數(shù)據(jù)  以空格間隔
            userItemLength.put(userInfos.get(i).getKey(), userInfos.get(i).getValue().size());//eg: A 3
            userID.put(userInfos.get(i).getKey(), i);//用戶ID與稀疏矩陣建立對應(yīng)關(guān)系
            idUser.put(i, userInfos.get(i).getKey());
            //建立新聞--用戶倒排表
            for(int j = 0; j < userInfos.get(i).getValue().size(); j ++){
                if(items.contains(userInfos.get(i).getValue().get(j))){//如果已經(jīng)包含對應(yīng)的新聞--用戶映射,直接添加對應(yīng)的用戶
                    itemUserCollection.get(userInfos.get(i).getValue().get(j)).add(userInfos.get(i).getKey());
                }else{//否則創(chuàng)建對應(yīng)新聞--用戶集合映射
                    items.add(userInfos.get(i).getValue().get(j));
                    itemUserCollection.put(userInfos.get(i).getValue().get(j), new HashSet<String>());//創(chuàng)建新聞--用戶倒排關(guān)系
                    itemUserCollection.get(userInfos.get(i).getValue().get(j)).add(userInfos.get(i).getKey());
                }
            }
        }
        System.out.println(itemUserCollection.toString());
        //計(jì)算相似度矩陣【稀疏】
        Set<Map.Entry<String, Set<String>>> entrySet = itemUserCollection.entrySet();
        Iterator<Map.Entry<String, Set<String>>> iterator = entrySet.iterator();
        while(iterator.hasNext()){
            Set<String> commonUsers = iterator.next().getValue();
            for (String user_u : commonUsers) {
                for (String user_v : commonUsers) {
                    if(user_u.equals(user_v)){
                        continue;
                    }
                    sparseMatrix[userID.get(user_u)][userID.get(user_v)] +=1;
                }
            }
        }
        /計(jì)算用戶之間的相似度【余弦相似性】
        int recommendUserId = userID.get(recommendUser);
        List<GPair<String, Double>> res = new ArrayList<>();
        for (int j = 0;j < sparseMatrix.length; j++) {
            if(j != recommendUserId){
                System.out.println(idUser.get(recommendUserId)+"--"+idUser.get(j)+"相似度:"+sparseMatrix[recommendUserId][j]/Math.sqrt(userItemLength.get(idUser.get(recommendUserId))*userItemLength.get(idUser.get(j))));
            }
        }
        //計(jì)算指定用戶recommendUser的新聞推薦度
        List<GPair<String, Double>> recommondInfos = new ArrayList<>();
        for(String item: items){//遍歷每一件新聞
            Set<String> users = itemUserCollection.get(item);//得到 當(dāng)前新聞的所有用戶集合
            if(!users.contains(recommendUser)){//如果被推薦用戶當(dāng)前新聞,則進(jìn)行推薦度計(jì)算
                double itemRecommendDegree = 0.0;
                for(String user: users){
                    itemRecommendDegree += sparseMatrix[userID.get(recommendUser)][userID.get(user)]/Math.sqrt(userItemLength.get(recommendUser)*userItemLength.get(user));//推薦度計(jì)算
                }
                recommondInfos.add(new GPair<>(item, itemRecommendDegree));
            }
        }
        recommondInfos.sort(new Comparator<GPair<String, Double>>() {
            @Override
            public int compare(GPair<String, Double> o1, GPair<String, Double> o2) {
                return o2.getValue().compareTo(o1.getValue());
            }
        });
        return combine(recommendUser, userInfos,recommondInfos);
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容