精华内容
下载资源
问答
  • JAVA-简单实现文本相似度计算-余弦相似度
    千次阅读
    2019-07-25 15:51:42

    简介

    在下是刚毕业的小萌新,现在在一家股票资讯公司做Java开发。手上是一个消息监控的项目,需要实时把爬虫组爬到的新闻经过处理入库。今天来了个需求,需要对新闻做一个去重的处理,减少类似新闻的出现。我理性分析一波,应该就是要计算一下文本的相似度嗯嗯。。。那该怎么做呢。。。

    计算文本相似度方法

    文本的相似度计算方法可以分为两大类:基于深度学习的方法和基于非深度学习的方法。
    虽然小的我在自然语言处理与交互部,但我只是个开发,不是算法,所以这里采用简单的非深度学习的方法。
    常用的几个计算方法:余弦相似度、最小编辑距离。。。。。
    由于场景比较简单,所以并没有对文本进行分词,如果有需要,可以用jieba,hanlp等等

    余弦相似度

    private static double getSimilarity(String doc1, String doc2) {
    		if (StringUtils.isBlank(doc1) or StringUtils.isBlank(doc2)) {
    				return 0L;
    		}
    		Map<Character,int[]> algMap=new HashMap<>();
    		for (int i = 0; i<doc1.length(); i++) {
    				char d1 = doc1.charAt(i);
    				int[] fq = algMap.get(d1);
    				if (fq != null && fq.length == 2) {
    						fq[0]++;
    				} else {
    						fq = new int[2];
    						fq[0] = 1;
    						fq[1] = 0;
    						algMap.put(d1, fq);
    				}
    		}
    		for (int i = 0; i<doc2.length(); i++) {
    				char d2 = doc2.charAt(i);
    				int[] fq = algMap.get(d2);
    				if (fq != null && fq.length == 2) {
    						fq[1]++;
    				} else {
    						fq = new int[2];
    						fq[0] = 0;
    						fq[1] = 1;
    						algMap.put(d2, fq);
    				}
    		}
    		double sqdoc1 = 0;
    		double sqdoc2 = 0;
    		double denuminator = 0;
    		for (Map.Entry entry : algMap.entrySet()) {
    				int[] c = (int[]) entry.getValue();
    				denuminator += c[0] * c[1];
    				sqdoc1 += c[0] * c[0];
    				sqdoc2 += c[1] * c[1];
    		}
    		return denuminator / Math.sqrt(sqdoc1 * sqdoc2);
    }
    

    体会

    这只是比较简单的实现,对比最小编辑距离,貌似余弦向量更适合我的场景。简单的方法速度会快一点,但是这是脱离语义的计算,如果有更高级的场景,可以自行选择分词器,这边是对单个字符的计算

    参考

    1. 文本相似度计算_02
      https://segmentfault.com/a/1190000017469294?utm_source=tag-newest
    更多相关内容
  • Python3 实现的文章余弦相似度计算
  • GIS服务使用文本匹配算法,通过关键字、相似度等方式将输入地址与GIS地址库中的地址(POI)进行匹配,从而得到经纬度或平面坐标。 使用空间几何算法,计算出地址坐标位于哪个片区中。 等开源工具中包含了这些算法,...
  • 利用余弦相似度计算文本相似度

    万次阅读 2017-10-28 11:14:38
    利用余弦相似度计算文本相似度

    利用余弦相似度计算文本相似度

    1、Introduction
    针对文本相似判定,本文提供余弦相似度算法,并根据实际项目遇到的一些问题,给出相应的解决方法。经过实际测试表明:余弦相似度算法适合于短文本,而不适合于长文本。
    2、Related Work
    2.1 最长公共子序列(基于权值空间、词条空间)
    (1)将两个字符串分别以行和列组成矩阵。
    (2)计算每个节点行列字符是否相同,如相同则为1。
    (3)通过找出值为1的最长对角线即可得到最长公共子串。
    (4)为进一步提升该算法,我们可以将字符相同节点的值加上左上角(d[i-1,j-1])的值,这样即可获得最大公共子串的长度。如此一来只需以行号和最大值为条件即可截取最大子串。
    2.2 最小编辑距离算法(基于词条空间)
    (1)狭义编辑距离
    设A、B为两个字符串,狭义的编辑距离定义为把A转换成B需要的最少删除(删除A中一个字符)、插入(在A中插入一个字符)和替换(把A中的某个字符替换成另一个字符)的次数,用ED(A,B)来表示。直观来说,两个串互相转换需要经过的步骤越多,差异越大。
    (2)步骤
    a) 对两部分文本进行处理,将所有的非文本字符替换为分段标记“#”
    b) 较长文本作为基准文本,遍历分段之后的短文本,发现长文本包含短文本子句后在长本文中移除,未发现匹配的字句累加长度。
    c) 比较剩余文本长度与两段文本长度和,其比值为不匹配比率。
    3、Cosine Similarity
    余弦相似度 (Cosine Similarity) 通过计算两个向量的夹角余弦值来评估他们的相似度。余弦相似度将向量根据坐标值,绘制到向量空间中,如最常见的二维空间。
    3.1 Conception:
    将向量根据坐标值,绘制到向量空间中。如最常见的二维空间。求得他们的夹角,并得出夹角对应的余弦值,此余弦值就可以用来表征,这两个向量的相似性。夹角越小,余弦值越接近于1,它们的方向更加吻合,则越相似。
    因此,我们可以通过夹角的大小,来判断向量的相似程度。夹角越小,就代表越相似。
    3.2 Calculate:
    以二维空间为例,上图的a和b是两个向量,我们要计算它们的夹角θ。余弦定理告诉我们,可以用下面的公式求得:
    这里写图片描述
    这里写图片描述
    数学家已经证明,余弦的这种计算方法对n维向量也成立。假定A和B是两个n维向量,A是 [A1, A2, …, An] ,B是 [B1, B2, …, Bn] ,则A与B的夹角θ的余弦等于:
    这里写图片描述
    算法步骤
    (1) 向量对齐:
    由于在实际应用中,表征文本特征的两个向量的长度是不同的,因此必然需要对上述向量进行处理。
    a) 对文本进行预处理:去停用词(分词,介词,代词等)以及非文本符号
    b) 归并向量,并根据原向量是否在新向量(归并后的向量)存在,若存在则以该词汇的词频来表征,若不存在则该节点置为0
    c) 示例如下:
    Text1_1: It is a beautiful butterfly
    Text1_2: beautiful butterfly
    Text2_1: She is a beautiful girl
    Text2_2: beautiful girl
    Vector: beautiful butterfly girl
    Vector1 = (1, 1, 0)
    Vector2 = (1, 0, 1)
    (2) 样例:
    Test1_1、Test2_1为来自不同类型文章中的随机段落节选;Test1_2、Test2_2为去停用词和非文字符号后的文本
    Test1_1:In spite of the title, this article will really be on how not to grow old, which, at my time of life, is a much more important subject. My first advice would be to choose your ancestors carefully. Although both my parents died young, I have done well in this respect as regards my other ancestors. My maternal grandfather, it is true, was cut off in the flower of his youth at the age of sixty-seven, but my other three grandparents all lived to be over eighty. Of remoter ancestors I can only discover one who did not live to a great age, and he died of a disease which is now rare, namely, having his head cut off.
    Test1_2:spite title article grow old which time life subject advice choose ancestors carefully parents died young respect ancestors maternal grandfather true cut flower youth age sixty-seven grandparents lived eighty remoter ancestors discover live age died disease rare namely head cut off
    Test2_1:A good book may be among the best of friends. It is the same today that it always was, and it will never change. It is the most patient and cheerful of companions. It does not turn its back upon us in times of adversity or distress. It always receives us with the same kindness; amusing and instructing us in youth, and comforting and consoling us in age.
    Test2_2:book friends was change patient cheerful companions times adversity distress receives kindness amusing instructing youth comforting consoling age

    代码块

    ①Cos_Main
    package NLP_Cos;
    
    import java.io.*;
    
    public class CosMain {
    
        public static void main(String[] args) throws Exception {
            //第一步,预处理主要是进行分词和去停用词,分词。
            //第二步,列出所有的词。
            //公共词 
            //第三步,计算词频,写出词频向量。
    
            // 执行 
            Cos_Frame gui = new Cos_Frame();
    
            // 将结果保存到文件out.txt里
            File f=new File("out.txt");
            Cos_FileOperation.clearInfoForFile("out.txt");
            f.createNewFile();
            FileOutputStream fileOutputStream = new FileOutputStream(f);
            PrintStream printStream = new PrintStream(fileOutputStream);
            System.setOut(printStream);
            System.out.println("The fact is:");
        }  
    }
    ②Cos_Alogrithm
    package NLP_Cos;
    import java.util.*;
    
    public class Cos_Alogrithm {
    //数据结构解析:<单词,二维数组>,其中单词表示公共词,
           //  二维数组一维度表示句子一的向量,另一维度表示句子二的向量
        Map<String, int[]> vectorMap = new HashMap<String, int[]>();  
    
        int[] tempArray = null;  
    
        public Cos_Alogrithm(String[] string1, String[] string2) {  
            List<String> list1 = java.util.Arrays.asList(string1);
            for (String character1 :list1) {  
                if (vectorMap.containsKey(character1)) {  
                    vectorMap.get(character1)[0]++;  
                } else {  
                    tempArray = new int[2];  
                    tempArray[0] = 1;  
                    tempArray[1] = 0;  
                    vectorMap.put(character1, tempArray);  
                }  
            }  
            List<String> list2 = java.util.Arrays.asList(string2);
            for (String character2 : list2) {  
                if (vectorMap.containsKey(character2)) {  
                    vectorMap.get(character2)[1]++;  
                } else {  
                    tempArray = new int[2];  
                    tempArray[0] = 0;  
                    tempArray[1] = 1;  
                    vectorMap.put(character2, tempArray);  
                }  
            }
    
            for (Map.Entry<String, int[]> entry : vectorMap.entrySet()) {  
                System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()[0] +","+entry.getValue()[1]); 
            }  
        }  
        // 求余弦相似度  
        public double sim() {  
            double result = 0;  
            result = pointMulti(vectorMap) / sqrtMulti(vectorMap);  
            return result;  
        }  
    
        private double sqrtMulti(Map<String, int[]> vectorMap2) {  
            double result = 0;  
            result = squares(vectorMap2);  
            result = Math.sqrt(result);  
            return result;  
        }  
    
        // 求平方和  
        private double squares(Map<String, int[]> vectorMap2) {  
            double result1 = 0;  
            double result2 = 0;  
            Set<String> keySet = vectorMap2.keySet();  
            for (String character : keySet) {  
                int temp[] = vectorMap2.get(character);  
                result1 += (temp[0] * temp[0]);  
                result2 += (temp[1] * temp[1]);  
            }  
            return result1 * result2;  
        }  
    
        // 点乘法  
        private double pointMulti(Map<String, int[]> vectorMap2) {  
            double result = 0;  
            Set<String> keySet = vectorMap2.keySet();  
            for (String character : keySet) {  
                int temp[] = vectorMap2.get(character);  
                result += (temp[0] * temp[1]);  
            }  
            return result;  
        }  
    
    } 
    ③Cos_FileOperation
    package NLP_Cos;
    import java.io.*;
    import java.util.Scanner;
    
    public class Cos_FileOperation {
    
        public static String[] filework(String filename) throws IOException {
            //1.1文件1去行
            java.io.File file1_1 = new java.io.File("actest1_1.txt");
            clearInfoForFile("actest1_1.txt");
            java.io.PrintWriter output1_1 = new java.io.PrintWriter(file1_1);
            BufferedReader br1_1 = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
            String str1_1;
            while((str1_1=br1_1.readLine())!=null) {
                String s1_1 =str1_1;
                output1_1.print(s1_1);
                //output1.print(" ");
            }
            output1_1.close();
            br1_1.close();
    
        //1.2 文件test1操作
            String[] testString1_1;
            java.io.File cin1_1 = new java.io.File("actest1_1.txt");
            Scanner input1_1 = new Scanner(cin1_1);
            String line1_1 = input1_1.nextLine();
            line1_1 = line1_1.toLowerCase();
            testString1_1 = line1_1.split("[ ]");           //去掉空格
            input1_1.close();
    
        //1.3去除停用词
            for(int i=0; i<testString1_1.length; i++) {
                String temp1_1 = testString1_1[i];          //存放取出的单个单词
                char getchar1_1 = temp1_1.toCharArray()[0]; //取出单词首字母,以便于打开对应文件
                java.io.File tempfile1_1 = new java.io.File(getchar1_1+"_StopWord.txt");
                Scanner tempinput1_1= new Scanner(tempfile1_1);
                while(tempinput1_1.hasNext()) {
                    String templine1 = tempinput1_1.nextLine();
                    if(templine1.equals(temp1_1)) {
                        testString1_1[i] = "#";     
                        break;
                    }
                }
                tempinput1_1.close();
            }
    
        //1.4去标点符号
            for(int j=0; j<testString1_1.length; j++) {
                char temp[] = (testString1_1[j]).toCharArray();
                StringBuilder stringBuilder1_1 = new StringBuilder();
                stringBuilder1_1.append(testString1_1[j]);
                if(temp[(stringBuilder1_1.length()-1)]== ',' || temp[stringBuilder1_1.length()-1]== '.' || temp[stringBuilder1_1.length()-1]== '(' || temp[stringBuilder1_1.length()-1]== ')' ) {
                    stringBuilder1_1.deleteCharAt(stringBuilder1_1.length()-1);
                    testString1_1[j] = stringBuilder1_1.toString();
                }
            }
    
        //1.5去除标记符号“#”,并将整合好的字符串重新录入文件“actest1_2”中
            StringBuilder stringBuilder1_2 = new StringBuilder();
            for(int i=0; i<testString1_1.length; i++) {
                if(!testString1_1[i].equals("#")) {
                    stringBuilder1_2.append(testString1_1[i]);
                    stringBuilder1_2.append(' ');
                }
            }
            String str1_2 = stringBuilder1_2.toString();
            java.io.File file1_2 = new java.io.File("actest1_2.txt");
            clearInfoForFile("actest1_2");
            java.io.PrintWriter output1_2 = new java.io.PrintWriter(file1_2);
            output1_2.print(str1_2);
            output1_2.close();
    
        //1.6读取文件“actest1_2”,读取出 testString1_2
            String[] testString1_2;
            java.io.File cin1_2 = new java.io.File("actest1_2.txt");
            Scanner input1_2 = new Scanner(cin1_2);
            String line1_2 = input1_2.nextLine();
            testString1_2 = line1_2.split("[ ]");           //去掉空格
    
            input1_2.close();
    
            return testString1_2;
        }
    
        //清空文档中已有内容
        public static void clearInfoForFile(String fileName) {
            File file =new File(fileName);
            try {
                if(!file.exists()) {
                    file.createNewFile();
                }
                FileWriter fileWriter =new FileWriter(file);
                fileWriter.write("");
                fileWriter.flush();
                fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }
    
    ④Cos_ChooseFile
    package NLP_Cos;
    
    import java.io.File;
    import java.util.Scanner;
    
    import javax.swing.JFileChooser;
    
    public class Cos_ChooseFile {
    
        public static String readFile() throws Exception {
            // TODO Auto-generated method stub
            String filename = null;
            JFileChooser jfc=new JFileChooser();
            if(jfc.showOpenDialog(null)==JFileChooser.APPROVE_OPTION){
                File file=jfc.getSelectedFile();
                Scanner input=new Scanner(file);
                filename = file.getName();
                input.close();
                //System.out.println("Successfully Opened"+filename);
                return filename;
            }
            else
                System.out.println("No file is selected!");
            return filename;
    
        }
    
    }
    ⑤Cos_Frame
    package NLP_Cos;
    
    import java.awt.*;
    import java.io.File;
    import javax.swing.*;
    
    public class Cos_Frame extends JFrame{
        String[] str1, str2;
        public Cos_Frame() {
            //1.创建JFrame
            this.setSize(600, 450);
            //2.创建布局
            GridLayout layout1 = new GridLayout(2, 1);
            //3.将布局应用于容器上
            this.setLayout(layout1);
            //4.创建面板
            JPanel p1 = new JPanel();
            JPanel p2 = new JPanel();
            //5.将面板放到Frame上
            this.add(p1);
            this.add(p2);
            //6.创建组件
            JLabel title = new JLabel("计算文本相似度",JLabel.CENTER);
            title.setForeground(Color.BLACK);
            Font font = new Font("宋体", Font.BOLD, 18);
            title.setFont(font);
            JButton choose = new JButton("Choose Files");
            choose.addActionListener(new doActionListener());
            JButton calculate = new JButton("Calculate");
            //匿名类
            calculate.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    Cos_Alogrithm similarity = new Cos_Alogrithm(str1, str2);  
                    System.out.println(similarity.sim());  
                    dispose();
                    File f=new File("out.txt");
                    try {
                        new Cos_DisplayFact(f);
                    } catch (Exception e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            });
            //7.将组件添加到容器上
            p1.add(title);
            p2.add(choose);
            p2.add(calculate);
            //8.显示窗口
            this.setVisible(true);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
        //内部类
            class doActionListener implements ActionListener{
    
            @Override
            public void actionPerformed(ActionEvent e) {
                String filename1, filename2;
                try {
                    filename1 = Cos_ChooseFile.readFile();
                    filename2 = Cos_ChooseFile.readFile();
                    str1 = Cos_FileOperation.filework(filename1);
                    str2 = Cos_FileOperation.filework(filename2);
    
                } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }   
            }   
            }
    }
    
    ⑥Cos_DisplayFact
    package NLP_Cos;
    
    import java.io.*;
    import javax.swing.*;
    
    public class Cos_DisplayFact extends JFrame{
    
        JTextArea textArea = null;
        JScrollPane scrollPane = null; 
    
        public Cos_DisplayFact(File file) throws Exception {
            this.setVisible(true);
            this.setSize(800,650);
            this.setDefaultCloseOperation(EXIT_ON_CLOSE);
            textArea = new JTextArea();
            scrollPane = new JScrollPane(textArea);
            textArea.setText(null);
            BufferedReader buf = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
            String str = null;
            while( (str = buf.readLine()) != null ){
                textArea.append(str);
                textArea.append("\r\n");
            }
            add(scrollPane);
            validate();
        }
    }
    展开全文
  • 文章目录自然语言处理系列三十一文本相似度算法余弦相似度Python代码实现总结 自然语言处理系列三十一 文本相似度算法 在自然语言处理中,我们经常需要判定两个东西是否相似。比如,在微博的热点话题推荐那里,我们...

    注:此文章内容均节选自充电了么创始人,CEO兼CTO陈敬雷老师的新书《分布式机器学习实战》(人工智能科学与技术丛书)【陈敬雷编著】【清华大学出版社】

    自然语言处理系列三十一

    文本相似度算法

    在自然语言处理中,我们经常需要判定两个东西是否相似。比如,在微博的热点话题推荐那里,我们需要比较微博之间的相似度,让相似度高的微博聚集在一起形成一个簇,提出一个主题。在问答系统中,比如说人工客服,我们需要提前准备好问题和一些答案,让用户输入的问题与题库中的问题进行相似度的比较,最后输出答案。
    在推荐系统中,我们需要提取一个用户的所有物品,在根据这个物品找到对应的用户群,比较两个用户之间的相似性,在进行相应的推荐(协同过滤)。在对语料进行预处理的时候,我们需要给予文本的相似度,把相似度高的重复主题过滤掉。
    总之,相似度是一种非常有用的工具,可以帮助我们解决很多问题。一般来说,是比较两个物体(商品,文本)之间的相似度。这里的相似度是一个抽象的值,它可以抽象成估计的百分比。在推荐工程中,计算相似度是为了给用户推送一定量的物品。即把所有的相似度排序,然后选出最高的那几个物品。
    人是很容易判断出物品的相似度的,人们会在心里有一个考量。那么程序如何判断呢?
    如果是文本分析,它首先就要用到分词技术,然后去掉不必要的词(语气词,连接词)。然后对词给一个抽象的量表示权重,最后在用一些方法去统计出整体的相似度。如果是其他的,可能首先也需要进行数据清洗的工作,留下那些关键的能够表示物体特征的部分,对这些部分定权值,再去估计整体。
    下面给大家介绍几种常见的文本相似度算法,比如字符串编辑距离、余弦相似度等。

    余弦相似度

    余弦相似度一般比字符串编辑距离的效果要好一些,下面我们介绍其原理,并同时用Java和Python代码实现。

    Python代码实现

    余弦相似度Python实现代码如下:

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    #__author__ = '陈敬雷'
    import numpy as np
    import re
    print("充电了么App官网:www.chongdianleme.com")
    print("充电了么App - 专注上班族职业技能提升充电学习的在线教育平台")
    """ 
    字符串余弦相似度
    """
    def get_word_vector(s1, s2):
        """
        :param s1: 字符串1
        :param s2: 字符串2
        :return: 返回字符串切分后的向量
        """
        # 字符串中文按字分,英文按单词,数字按空格
        regEx = re.compile('[\\W]*')
        res = re.compile(r"([\u4e00-\u9fa5])")
        p1 = regEx.split(s1.lower())
        str1_list = []
        for str in p1:
            if res.split(str) == None:
                str1_list.append(str)
            else:
                ret = res.split(str)
                for ch in ret:
                    str1_list.append(ch)
        # print(str1_list)
        p2 = regEx.split(s2.lower())
        str2_list = []
        for str in p2:
            if res.split(str) == None:
                str2_list.append(str)
            else:
                ret = res.split(str)
                for ch in ret:
                    str2_list.append(ch)
        # print(str2_list)
        list_word1 = [w for w in str1_list if len(w.strip()) > 0]  # 去掉为空的字符
        list_word2 = [w for w in str2_list if len(w.strip()) > 0]  # 去掉为空的字符
        # 列出所有的词,取并集
        key_word = list(set(list_word1 + list_word2))
        # 给定形状和类型的用0填充的矩阵存储向量
        word_vector1 = np.zeros(len(key_word))
        word_vector2 = np.zeros(len(key_word))
        # 计算词频
        # 依次确定向量的每个位置的值
        for i in range(len(key_word)):
            # 遍历key_word中每个词在句子中的出现次数
            for j in range(len(list_word1)):
                if key_word[i] == list_word1[j]:
                    word_vector1[i] += 1
            for k in range(len(list_word2)):
                if key_word[i] == list_word2[k]:
                    word_vector2[i] += 1
    
        # 输出向量
        return word_vector1, word_vector2
    
    def cos_dist(vec1, vec2):
        """
        :param vec1: 向量1
        :param vec2: 向量2
        :return: 返回两个向量的余弦相似度
        """
        dist1 = float(np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2)))
        return dist1
    
    if __name__ == '__main__':
        str1 = "充电了么App - 专注上班族职业技能提升充电学习的在线教育平台"
        str2 = "充电了么是专注上班族职业技能提升充电学习的在线教育平台"
        v1, v2 = get_word_vector(str1,str2)
        print(cos_dist(v1,v2))
    

    总结

    此文章有对应的配套视频,其它更多精彩文章请大家下载充电了么app,可获取千万免费好课和文章,配套新书教材请看陈敬雷新书:《分布式机器学习实战》(人工智能科学与技术丛书)

    【新书介绍】
    《分布式机器学习实战》(人工智能科学与技术丛书)【陈敬雷编著】【清华大学出版社】
    新书特色:深入浅出,逐步讲解分布式机器学习的框架及应用配套个性化推荐算法系统、人脸识别、对话机器人等实战项目

    【新书介绍视频】
    分布式机器学习实战(人工智能科学与技术丛书)新书【陈敬雷】
    视频特色:重点对新书进行介绍,最新前沿技术热点剖析,技术职业规划建议!听完此课你对人工智能领域将有一个崭新的技术视野!职业发展也将有更加清晰的认识!

    【精品课程】
    《分布式机器学习实战》大数据人工智能AI专家级精品课程

    【免费体验视频】:
    人工智能百万年薪成长路线/从Python到最新热点技术

    从Python编程零基础小白入门到人工智能高级实战系列课

    视频特色: 本系列专家级精品课有对应的配套书籍《分布式机器学习实战》,精品课和书籍可以互补式学习,彼此相互补充,大大提高了学习效率。本系列课和书籍是以分布式机器学习为主线,并对其依赖的大数据技术做了详细介绍,之后对目前主流的分布式机器学习框架和算法进行重点讲解,本系列课和书籍侧重实战,最后讲几个工业级的系统实战项目给大家。 课程核心内容有互联网公司大数据和人工智能那些事、大数据算法系统架构、大数据基础、Python编程、Java编程、Scala编程、Docker容器、Mahout分布式机器学习平台、Spark分布式机器学习平台、分布式深度学习框架和神经网络算法、自然语言处理算法、工业级完整系统实战(推荐算法系统实战、人脸识别实战、对话机器人实战)、就业/面试技巧/职业生涯规划/职业晋升指导等内容。

    【充电了么公司介绍】

    充电了么App是专注上班族职业培训充电学习的在线教育平台。

    专注工作职业技能提升和学习,提高工作效率,带来经济效益!今天你充电了么?

    充电了么官网
    http://www.chongdianleme.com/

    充电了么App官网下载地址
    https://a.app.qq.com/o/simple.jsp?pkgname=com.charged.app

    功能特色如下:

    【全行业职位】 - 专注职场上班族职业技能提升

    覆盖所有行业和职位,不管你是上班族,高管,还是创业都有你要学习的视频和文章。其中大数据智能AI、区块链、深度学习是互联网一线工业级的实战经验。

    除了专业技能学习,还有通用职场技能,比如企业管理、股权激励和设计、职业生涯规划、社交礼仪、沟通技巧、演讲技巧、开会技巧、发邮件技巧、工作压力如何放松、人脉关系等等,全方位提高你的专业水平和整体素质。

    【牛人课堂】 - 学习牛人的工作经验

    1.智能个性化引擎:

    海量视频课程,覆盖所有行业、所有职位,通过不同行业职位的技能词偏好挖掘分析,智能匹配你目前职位最感兴趣的技能学习课程。

    2.听课全网搜索

    输入关键词搜索海量视频课程,应有尽有,总有适合你的课程。

    3.听课播放详情

    视频播放详情,除了播放当前视频,更有相关视频课程和文章阅读,对某个技能知识点强化,让你轻松成为某个领域的资深专家。

    【精品阅读】 - 技能文章兴趣阅读

    1.个性化阅读引擎:

    千万级文章阅读,覆盖所有行业、所有职位,通过不同行业职位的技能词偏好挖掘分析,智能匹配你目前职位最感兴趣的技能学习文章。

    2.阅读全网搜索

    输入关键词搜索海量文章阅读,应有尽有,总有你感兴趣的技能学习文章。

    【机器人老师】 - 个人提升趣味学习

    基于搜索引擎和智能深度学习训练,为您打造更懂你的机器人老师,用自然语言和机器人老师聊天学习,寓教于乐,高效学习,快乐人生。

    【精短课程】 - 高效学习知识

    海量精短牛人课程,满足你的时间碎片化学习,快速提高某个技能知识点。

    上一篇:自然语言处理系列三十》文本相似度算法》余弦相似度》Java代码实现
    下一篇:

    展开全文
  • TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术。TF意思是词频(Term Frequency),IDF... * 直接匹配2个文本 * * @author rock * */ public class GetText {

    TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术。TF意思是词频(Term Frequency),IDF意思是逆向文件频率(Inverse Document Frequency)。

    思想:对文本进行分词,然后用tfidf算法得到文本对应的词向量,然后利用余弦算法求相似度
    需要的jar :je-analysis-1.5.3.jar ,lucene-core-2.4.1.jar(高于4的版本会有冲突)

    /**
     * 直接匹配2个文本
     * 
     * @author rock
     *
     */
    public class GetText {
        private static List<String> fileList = new ArrayList<String>();
        private static HashMap<String, HashMap<String, Double>> allTheTf = new HashMap<String, HashMap<String, Double>>();
        private static HashMap<String, HashMap<String, Integer>> allTheNormalTF = new HashMap<String, HashMap<String, Integer>>();
        private static LinkedHashMap<String, Double[]> vectorMap = new LinkedHashMap<String, Double[]>();
    
        /**
         * 分词
         * 
         * @author create by rock
         */
        public static String[] TextcutWord(String text) throws IOException {
            String[] cutWordResult = null;
            MMAnalyzer analyzer = new MMAnalyzer();
            String tempCutWordResult = analyzer.segment(text, " ");
            cutWordResult = tempCutWordResult.split(" ");
            return cutWordResult;
        }
    
        public static Map<String, HashMap<String, Integer>> NormalTFOfAll(String key1, String key2, String text1,
                String text2) throws IOException {
            if (allTheNormalTF.get(key1) == null) {
                HashMap<String, Integer> dict1 = new HashMap<String, Integer>();
                dict1 = normalTF(TextcutWord(text1));
                allTheNormalTF.put(key1, dict1);
            }
            if (allTheNormalTF.get(key2) == null) {
                HashMap<String, Integer> dict2 = new HashMap<String, Integer>();
                dict2 = normalTF(TextcutWord(text2));
                allTheNormalTF.put(key2, dict2);
            }
            return allTheNormalTF;
        }
    
        public static Map<String, HashMap<String, Double>> tfOfAll(String key1, String key2, String text1, String text2)
                throws IOException {
                allTheTf.clear();
                HashMap<String, Double> dict1 = new HashMap<String, Double>();
                HashMap<String, Double> dict2 = new HashMap<String, Double>();
                dict1 = tf(TextcutWord(text1));
                dict2 = tf(TextcutWord(text2));
                allTheTf.put(key1, dict1);
                allTheTf.put(key2, dict2);
                return allTheTf;
        }
    
        /**
         * 计算词频
         * 
         * @author create by rock
         */
        public static HashMap<String, Double> tf(String[] cutWordResult) {
            HashMap<String, Double> tf = new HashMap<String, Double>();// 正规化
            int wordNum = cutWordResult.length;
            int wordtf = 0;
            for (int i = 0; i < wordNum; i++) {
                wordtf = 0;
                if (cutWordResult[i] != " ") {
                    for (int j = 0; j < wordNum; j++) {
                        if (i != j) {
                            if (cutWordResult[i].equals(cutWordResult[j])) {
                                cutWordResult[j] = " ";
                                wordtf++;
                            }
                        }
                    }
                    tf.put(cutWordResult[i], (new Double(++wordtf)) / wordNum);
                    cutWordResult[i] = " ";
                }
            }
            return tf;
        }
    
        public static HashMap<String, Integer> normalTF(String[] cutWordResult) {
            HashMap<String, Integer> tfNormal = new HashMap<String, Integer>();// 没有正规化
            int wordNum = cutWordResult.length;
            int wordtf = 0;
            for (int i = 0; i < wordNum; i++) {
                wordtf = 0;
                if (cutWordResult[i] != " ") {
                    for (int j = 0; j < wordNum; j++) {
                        if (i != j) {
                            if (cutWordResult[i].equals(cutWordResult[j])) {
                                cutWordResult[j] = " ";
                                wordtf++;
                            }
                        }
                    }
                    tfNormal.put(cutWordResult[i], ++wordtf);
                    cutWordResult[i] = " ";
                }
            }
            return tfNormal;
        }
    
        public static Map<String, Double> idf(String key1, String key2, String text1, String text2)
                throws FileNotFoundException, UnsupportedEncodingException, IOException {
            // 公式IDF=log((1+|D|)/|Dt|),其中|D|表示文档总数,|Dt|表示包含关键词t的文档数量。
            Map<String, Double> idf = new HashMap<String, Double>();
            List<String> located = new ArrayList<String>();
    
            NormalTFOfAll(key1, key2, text1, text2);
    
            float Dt = 1;
            float D = allTheNormalTF.size();// 文档总数
            List<String> key = fileList;// 存储各个文档名的List
    
            String[] keyarr = new String[2];
            keyarr[0] = key1;
            keyarr[1] = key2;
    
            for(String item :keyarr) {
                if (!fileList.contains(item)) {
                     fileList.add(item);
                }
            }
    
            Map<String, HashMap<String, Integer>> tfInIdf = allTheNormalTF;// 存储各个文档tf的Map
    
            for (int i = 0; i < D; i++) {
                HashMap<String, Integer> temp = tfInIdf.get(key.get(i));
                for (String word : temp.keySet()) {
                    Dt = 1;
                    if (!(located.contains(word))) {
                        for (int k = 0; k < D; k++) {
                            if (k != i) {
                                HashMap<String, Integer> temp2 = tfInIdf.get(key.get(k));
                                if (temp2.keySet().contains(word)) {
                                    located.add(word);
                                    Dt = Dt + 1;
                                    continue;
                                }
                            }
                        }
                        idf.put(word, (double) Log.log((1 + D) / Dt, 10));
                    }
                }
            }
            return idf;
        }
    
        public static Map<String, HashMap<String, Double>> tfidf(String key1, String key2, String text1, String text2)
                throws IOException {
            Map<String, Double> idf = idf(key1, key2, text1, text2);
            tfOfAll(key1, key2, text1, text2);
            for (String key : allTheTf.keySet()) {
                Map<String, Double> singelFile = allTheTf.get(key);
                int length = idf.size();
                Double[] arr = new Double[length];
                int index = 0;
    
                for (String word : singelFile.keySet()) {
                    singelFile.put(word, (idf.get(word)) * singelFile.get(word));
                }
    
                for (String word : idf.keySet()) {  
                    arr[index] = singelFile.get(word) != null ?singelFile.get(word):0d;
                    index++;
                }
                vectorMap.put(key, arr);
            }
            return allTheTf;
        }
    
        /* 得到词向量以后,用余弦相似度匹配 */
        public static Double sim(String key1, String key2) {
            Double[] arr1 = vectorMap.get(key1);
            Double[] arr2 = vectorMap.get(key2);
            int length = arr1.length;
            Double result1 = 0.00; // 向量1的模
            Double result2 = 0.00; // 向量2的模
            Double sum = 0d;
            if (length == 0) {
                return 0d;
            }
            for (int i = 0; i < length; i++) {
                result1 += arr1[i] * arr1[i];
                result2 += arr2[i] * arr2[i];
                sum += arr1[i] * arr2[i];
            }
            Double result = Math.sqrt(result1 * result2);
            System.out.println(key1 + "和" + key2 + "相似度" + sum / result);
    
            return sum / result;
    
        }
    
    }
    

    匹配多个文件

    /**
     * 从语料仓库去匹配
     * @author rock
     *
     */
    public class ReadFiles {
    
        private static List<String> fileList = new ArrayList<String>();
        private static HashMap<String, HashMap<String, Float>> allTheTf = new HashMap<String, HashMap<String, Float>>();
        private static HashMap<String, HashMap<String, Integer>> allTheNormalTF = new HashMap<String, HashMap<String, Integer>>();
        private static LinkedHashMap<String, Float[]> vectorMap = new LinkedHashMap<String, Float[]>();
        /**
         * 读取语料仓库
         * @author create by rock
         */
        public static List<String> readDirs(String filepath) throws FileNotFoundException, IOException {
            try {
                File file = new File(filepath);
                if (!file.isDirectory()) {
                    System.out.println("输入的参数应该为[文件夹名]");
                    System.out.println("filepath: " + file.getAbsolutePath());
                } else if (file.isDirectory()) {
                    String[] filelist = file.list();
                    for (int i = 0; i < filelist.length; i++) {
                        File readfile = new File(filepath + "\\" + filelist[i]);
                        if (!readfile.isDirectory()) {
                            fileList.add(readfile.getAbsolutePath());
                        } else if (readfile.isDirectory()) {
                            readDirs(filepath + "\\" + filelist[i]);
                        }
                    }
                }
    
            } catch (FileNotFoundException e) {
                System.out.println(e.getMessage());
            }
            return fileList;
        }
    
        /**
         * 读取txt文件
         * @author create by rock
         */
        public static String readFiles(String file) throws FileNotFoundException, IOException {
            StringBuffer sb = new StringBuffer();
            InputStreamReader is = new InputStreamReader(new FileInputStream(file), "utf-8");
            BufferedReader br = new BufferedReader(is);
            String line = br.readLine();
            while (line != null) {
                sb.append(line).append("\r\n");
                line = br.readLine();
            }
            br.close();
            return sb.toString();
        }
    
        /**
         * 分词
         * @author create by rock
         */
        public static String[] cutWord(String file) throws IOException {
            String[] cutWordResult = null;
            String text = ReadFiles.readFiles(file);
            MMAnalyzer analyzer = new MMAnalyzer();
            String tempCutWordResult = analyzer.segment(text, " ");
            cutWordResult = tempCutWordResult.split(" ");
            return cutWordResult;
        }
    
    
    
        /**
         * 计算词频
         * @author create by rock
         */
        public static HashMap<String, Float> tf(String[] cutWordResult) {
            HashMap<String, Float> tf = new HashMap<String, Float>();//正规化
            int wordNum = cutWordResult.length;
            int wordtf = 0;
            for (int i = 0; i < wordNum; i++) {
                wordtf = 0;
                for (int j = 0; j < wordNum; j++) {
                    if (cutWordResult[i] != " " && i != j) {
                        if (cutWordResult[i].equals(cutWordResult[j])) {
                            cutWordResult[j] = " ";
                            wordtf++;
                        }
                    }
                }
                if (cutWordResult[i] != " ") {
                    tf.put(cutWordResult[i], (new Float(++wordtf)) / wordNum);
                    cutWordResult[i] = " ";
                }
            }
            return tf;
        }
    
    
        public static HashMap<String, Integer> normalTF(String[] cutWordResult) {
            HashMap<String, Integer> tfNormal = new HashMap<String, Integer>();//没有正规化
            int wordNum = cutWordResult.length;
            int wordtf = 0;
            for (int i = 0; i < wordNum; i++) {
                wordtf = 0;
                if (cutWordResult[i] != " ") {
                    for (int j = 0; j < wordNum; j++) {
                        if (i != j) {
                            if (cutWordResult[i].equals(cutWordResult[j])) {
                                cutWordResult[j] = " ";
                                wordtf++;
    
                            }
                        }
                    }
                    tfNormal.put(cutWordResult[i], ++wordtf);
                    cutWordResult[i] = " ";
                }
            }
            return tfNormal;
        }
    
        public static Map<String, HashMap<String, Float>> tfOfAll(String dir) throws IOException {
            List<String> fileList = ReadFiles.readDirs(dir);
            for (String file : fileList) {
                HashMap<String, Float> dict = new HashMap<String, Float>();
                dict = ReadFiles.tf(ReadFiles.cutWord(file));
                allTheTf.put(file, dict);
            }
            return allTheTf;
        }
    
        /**
         * 自定义文档内容
         * @author create by rock
         */
        public static Map<String, HashMap<String, Float>> tfOfAll(String[] files) throws IOException {
            for (String file : files) {
                HashMap<String, Float> dict = new HashMap<String, Float>();
                dict = ReadFiles.tf(ReadFiles.cutWord(file));
                allTheTf.put(file, dict);
            }
            return allTheTf;
        }
    
    
        public static Map<String, HashMap<String, Integer>> NormalTFOfAll(String dir) throws IOException {
            List<String> fileList = ReadFiles.readDirs(dir);
            for (int i = 0; i < fileList.size(); i++) {
                HashMap<String, Integer> dict = new HashMap<String, Integer>();
                dict = ReadFiles.normalTF(ReadFiles.cutWord(fileList.get(i)));
                allTheNormalTF.put(fileList.get(i), dict);
            }
            return allTheNormalTF;
        }
    
        public static Map<String, Float> idf(String dir) throws FileNotFoundException, UnsupportedEncodingException, IOException {
            //公式IDF=log((1+|D|)/|Dt|),其中|D|表示文档总数,|Dt|表示包含关键词t的文档数量。
            Map<String, Float> idf = new HashMap<String, Float>();
            List<String> located = new ArrayList<String>();
            NormalTFOfAll(dir);
    
            float Dt = 1;
            float D = allTheNormalTF.size();//文档总数
            List<String> key = fileList;//存储各个文档名的List
            Map<String, HashMap<String, Integer>> tfInIdf = allTheNormalTF;//存储各个文档tf的Map
    
            for (int i = 0; i < D; i++) {
                HashMap<String, Integer> temp = tfInIdf.get(key.get(i));
                for (String word : temp.keySet()) {
                    Dt = 1;
                    if (!(located.contains(word))) {
                        for (int k = 0; k < D; k++) {
                            if (k != i) {
                                HashMap<String, Integer> temp2 = tfInIdf.get(key.get(k));
                                if (temp2.keySet().contains(word)) {
                                    located.add(word);
                                    Dt = Dt + 1;
                                    continue;
                                }
                            }
                        }
                        idf.put(word, Log.log((1 + D) / Dt, 10));
                    }
                }
            }
            return idf;
        }
    
        public static Map<String, HashMap<String, Float>> tfidf(String dir) throws IOException {
            Map<String, Float> idf = ReadFiles.idf(dir);
            Map<String, HashMap<String, Float>> tf = ReadFiles.tfOfAll(dir);
            for (String file : tf.keySet()) {
                Map<String, Float> singelFile = tf.get(file);
                int length = idf.size();
                Float[] arr = new Float[length];
                int index = 0;
                for (String word : singelFile.keySet()) {
                    singelFile.put(word, (idf.get(word)) * singelFile.get(word));
                }
                for(String word : idf.keySet()) {
                    if(singelFile.get(word) != null) {
                        arr[index] = singelFile.get(word);
                    }else {
                        arr[index] = 0f;
                    }
                    index++;
                }
                vectorMap.put(file, arr);
            }    
            return tf;
        } 
    
    
    
        public static double sim(String file1,String file2) {
            Float [] arr1 = vectorMap.get(file1);
            Float [] arr2 = vectorMap.get(file2);
             int length = arr1.length;
             double result1 = 0.00;  //向量1的模
             double result2 = 0.00;  //向量2的模
             Float sum = 0f;
    
            for(int i =0;i<length;i++) {
                result1 += arr1[i]*arr1[i];
                result2 += arr2[i]*arr2[i];
                sum+=arr1[i]*arr2[i];
            }
            double result = Math.sqrt(result1*result2);
            System.out.println(sum/result);
            return sum/result;
    
        }
    
    }
    展开全文
  • 一、 余弦相似概述余弦相似性通过测量两个向量的夹角的余弦值来度量它们之间的相似性。0度角的余弦值是1,而其他任何角度的余弦值都不大于1;并且其最小值是-1。从而两个向量之间的角度的余弦值确...
  • 文本相似度检测之余弦相似度

    千次阅读 2020-08-31 19:23:44
    探究余弦相似度计算文本相似度的问题,代码实现,以及思考优缺点
  • 余弦相似度和调整的余弦相似度

    千次阅读 2019-06-19 10:41:49
    余弦相似度和adjust 余弦相似度 ...余弦相似度文本挖掘和信息检索中常用的基于向量的相似度度量方法。该方法将比较字符串转化为向量空间,利用欧几里德余弦规则计算相似度。这种方法通常与其他方法相结合来限...
  • 词向量余弦算法,是将文本作为一个多维空间的向量,计算两个文本的相识度即计算判断两个向量在这个多维空间中的方向是否是一样的。而这个多维空间的构成是通过将文本进行分词,每个分词代表空间的一个维度。 下面...
  • 文本相似度,顾名思义是指两个文本(文章)之间的相似度,在搜索引擎、推荐系统、论文鉴定、机器翻译、自动应答、命名实体识别、拼写纠错等领域有广泛的应用。 与之相对应的,还有一个概念——文本距离——指的是两...
  • 余弦文本相似度匹配

    2022-05-05 09:47:56
    python连接sqlserver对数据进行文本相似度匹配 from sqlalchemy import create_engine,Table,Column,Date,Integer,String,ForeignKey from fuzzywuzzy import process
  • 余弦相似度计算的实现方式

    千次阅读 多人点赞 2020-11-21 14:01:19
    一、余弦相似度计算方式 1、python 2、sklearn 3、scipy 4、numpy 5、pytorch 6、faiss 二、规模暴增计算加速 1、numpy矩阵计算GPU加速——cupy 2、pytorch框架cuda加速 3、faiss的加速方法 总结 在做文本匹配、文本...
  • 文章目录自然语言处理系列三十文本相似度算法余弦相似度Java代码实现总结 自然语言处理系列三十 文本相似度算法 在自然语言处理中,我们经常需要判定两个东西是否相似。比如,在微博的热点话题推荐那里,我们需要...
  • 主要为大家详细介绍了TF-IDF与余弦相似性的应用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 在自然语言处理中,文本相似度是一种...基于此,现将几种常见的文本相似度计算方法做一个简单总结,以便后续查阅,本文所有源码均已上传到github。1.字符串相似度字符串相似度指的是比较两个文本相同字符个数,...
  • JAVA代码之余弦相似度

    2017-01-04 11:20:55
    余弦相似度基本思路是:如果这两句话的用词越相似,它们的内容就应该越相似。因此,可以从词频入手,计算它们的相似程度。 第一步,预处理主要是进行中文分词和去停用词,分词。 第二步,列出所有的词。 第三步,...
  • text_to_vector(text1) vector2 = text_to_vector(text2) cosine = get_cosine(vector1, vector2) print 'Cosine:', cosine 印刷品: Cosine: 0.861640436855 这里所用的余弦公式描述这里。 这不包括通过tf-idf对...
  • 而在语言中,处于相同语境中的不同词语也会出现类似的意义,向量语义正是分布假设的实例化,即将文本的符号表示转换为语义空间中的向量表示。根据词语所处语境,通过无监督方式学习到该词语的语义表示。 词语义   ...
  • 1. 文本相似度问题与应用 2. 文本相似度模型介绍 3. 实战:基于Python实现编辑距离 4. 实战:基于simhash实现相似文本判断 5. 实战:词向量Word AVG 1. 文本相似度问题与应用 文本相似度问题 文本相似度问题...
  • 文章目录自然语言处理系列二十九文本相似度算法余弦相似度算法原理总结 自然语言处理系列二十九 文本相似度算法 在自然语言处理中,我们经常需要判定两个东西是否相似。比如,在微博的热点话题推荐那里,我们需要...
  • 文本匹配(语义相似度/行为相关性)技术综述

    万次阅读 多人点赞 2019-01-13 13:08:39
    NLP 中,文本匹配技术,不像 MT、MRC、QA 等属于 end-to-end 型任务,通常以文本相似度计算、文本相关性计算的形式,在某应用系统中起核心支撑作用,比如搜索引擎、智能问答、知识检索、信息流推荐等。本篇将纵览...
  • 四、Java通过SimHash计算文本内容相似度代码示例 一)、新增依赖包 二)、过滤特殊字符 三)、计算单个分词的Hash值 四)、分词计算向量 五)、获取标题内容的海明距离 六)、获取标题内容的相似度 七)、...
  • 计算两个向量之间的余弦相似度 :param vector_a: 向量 a :param vector_b: 向量 b :return: sim """ vector_a = np . mat ( vector_a ) vector_b = np . mat ( vector_b ) num = float ( vector_a...
  • 转自相似度算法之余弦相似度 余弦距离,也称为余弦相似度,是用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小的度量。 余弦值越接近1,就表明夹角越接近0度,也就是两个向量越相似,这就叫"余弦相似...
  • 传统的文本相似度计算大多基于词匹配的方法,忽略了词汇语义信息,计算结果很大程度上取决于...因此,利用词汇相似度改进了基于余弦公式的文本相似度计算方法。实验表明该方法在F1值和准确度评价标准上优于其他方法。
  • 比如我们需要计算相似度的时候,可以使用余弦相似度,或者使用 e x p ( − ∣ ∣ h l e f t − h r i g h t ∣ ∣ ) exp({-||h^{left}-h^{right}||)} exp(−∣∣hleft−hright∣∣)来确定向量的距离。 孪生神经网络...
  • 本节介绍 基于ngram-tf-idf的余弦距离计算相似度。 本节将介绍两种实现:基于sklearn 和 基于gensim 基于sklearn的方式如下: import os import re import jieba import pickle import logging import numpy
  • 本篇博客,主要是描述一种计算文本相似度的算法,基于TF-IDF算法和余弦相似性。算法的描述请务必看阮一峰的博客,不然看不懂本篇博客,地址:在这里,主要讨论具体的代码的实现。过程如下:使用TF-IDF算法,找出两篇...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,044
精华内容 1,217
关键字:

基于余弦相似度的文本匹配

友情链接: loader Ali 3510-A-C-E.rar