JAVA使用W2V计算语义相似度(java实现)

本文介绍了如何在SpringBoot项目中使用Maven引入预训练的Word2Vec模型,通过Java实现分词和计算句子之间的余弦相似度,以评估语义相似度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在SpringBoot项目中,将预训练好的W2V模型bin文件放到项目中,引入依赖,使用java的方法分词、计算余弦相似度,计算出两个句子的语义相似度。注意bin模型要自己训练或下载。

1. 引入pom依赖

      常用想要的依赖这里都有:

Maven Repository: Search/Browse/Explore (mvnrepository.com)icon-default.png?t=N7T8https://mvnrepository.com/

       这里引入了深度学习库和分词库:

        <dependency>
			<groupId>org.deeplearning4j</groupId>
			<artifactId>deeplearning4j-nlp</artifactId>
			<version>1.0.0-beta7</version>
		</dependency>
		<dependency>
			<groupId>org.nd4j</groupId>
			<artifactId>nd4j-native-platform</artifactId>
			<version>1.0.0-beta7</version>
		</dependency>
		<dependency>
			<groupId>com.huaban</groupId>
			<artifactId>jieba-analysis</artifactId>
			<version>1.0.2</version>
		</dependency>

2. 写Word2Vector方法类

        分词——停用部分分词以提升效果——计算余弦相似度

package com.example.demo.service.Impl.data;

import org.deeplearning4j.models.embeddings.loader.WordVectorSerializer;
import org.deeplearning4j.models.word2vec.Word2Vec;
import com.huaban.analysis.jieba.JiebaSegmenter;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

public class SentenceSimilarityCalculator {

    private Word2Vec word2Vec;
    private JiebaSegmenter segmenter;
    private Set<String> stopwords;

    public SentenceSimilarityCalculator(String modelPath) {
        word2Vec = WordVectorSerializer.readWord2VecModel(modelPath);
        segmenter = new JiebaSegmenter();
        initializeStopwords(); // 初始化停用词
    }

    private void initializeStopwords() {
        // 设置分词的停用词,以提升效果,这里示例停用了(),
        stopwords = new HashSet<>();
        stopwords.add(")");
        stopwords.add("(");
        stopwords.add(",");
    }

    // 过滤和加权分词结果
    private List<String> filterAndWeightWords(List<String> words) {
        List<String> filteredWords = new ArrayList<>();
        for (String word : words) {
            // 过滤掉停用词和特定符号
            if (!stopwords.contains(word) && !word.matches("[\\pP\\pS]+")) {
                // 这里可以做加权处理
                filteredWords.add(word);
            }
        }
        return filteredWords;
    }

    public double calculateSimilarity(String sentence1, String sentence2) {
        List<String> words1 = segmenter.sentenceProcess(sentence1);
        List<String> words2 = segmenter.sentenceProcess(sentence2);

        // 过滤和加权处理分词结果
        List<String> filteredWords1 = filterAndWeightWords(words1);
        List<String> filteredWords2 = filterAndWeightWords(words2);

        String[] arrayWords1 = filteredWords1.toArray(new String[0]);
        String[] arrayWords2 = filteredWords2.toArray(new String[0]);

        double[] vector1 = calculateAverageVector(arrayWords1);
        double[] vector2 = calculateAverageVector(arrayWords2);

        double cosineSimilarity = cosineSimilarity(vector1, vector2);
        return cosineSimilarity;
    }

    private double[] calculateAverageVector(String[] words) {
        double[] sumVector = new double[word2Vec.getWordVector(word2Vec.vocab().wordAtIndex(0)).length];

        for (String word : words) {
            double[] wordVector = word2Vec.getWordVector(word);
            if (wordVector != null) {
                for (int i = 0; i < wordVector.length; i++) {
                    sumVector[i] += wordVector[i];
                }
            }
        }

        for (int i = 0; i < sumVector.length; i++) {
            sumVector[i] /= words.length;
        }
        System.out.println("Words: " + Arrays.toString(words));
        System.out.println("SumVector: " + Arrays.toString(sumVector));
        //上面打印出来,方便在控制台观察W2V分词相似等情况
        return sumVector;
    }

    private double cosineSimilarity(double[] vector1, double[] vector2) {
        double dotProduct = 0.0;
        double norm1 = 0.0;
        double norm2 = 0.0;

        for (int i = 0; i < vector1.length; i++) {
            dotProduct += vector1[i] * vector2[i];
            norm1 += Math.pow(vector1[i], 2);
            norm2 += Math.pow(vector2[i], 2);
        }

        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }

    //当结果需要拉伸变幻时
    //如果相似度在0.0到0.2之间,将线性映射到-1.0到0.2的范围
    public static double mapSimilarity(double similarity) {//(实际范围)/实际范围差*映射范围差+映射起点
        if (similarity >= 0.2) {
            return similarity;
        } else {
           return (similarity - 0.0) / (0.2 - 0.0) * (0.2 - (-1.0)) + (-1.0);
        }
    }
}

3. 在需要计算的地方引用计算方法

String modelPath = "src/main/java/com/example/demo/service/Impl/data/pretrained_word2vec.bin";//自己的路径
                SentenceSimilarityCalculator calculator = new SentenceSimilarityCalculator(modelPath);
                sentenceSimilarity = calculator.calculateSimilarity(sentence1, sentence2); 
                double mappedSimilarity = calculator.mapSimilarity(sentenceSimilarity);
                mappedSimilarity *= 100;   

        如果需要打印观察结果

String modelPath = "src/main/java/com/example/demo/service/Impl/data/pretrained_word2vec.bin";
                SentenceSimilarityCalculator calculator = new SentenceSimilarityCalculator(modelPath);
                sentenceSimilarity = calculator.calculateSimilarity(sentence1, sentence2); 
                System.out.println("sentenceSimilarity between the two sentences: " + sentenceSimilarity);
                double mappedSimilarity = calculator.mapSimilarity(sentenceSimilarity);
                System.out.println("mappedSimilarity between the two sentences: " + mappedSimilarity);
                mappedSimilarity *= 100;
                System.out.println("FinalMappedSimilarity between the two sentences: " + mappedSimilarity);

4. 输入或从其他地方接入需要计算语义相似度的句子

String sentence1 = "比利时大个子费莱尼,传奇轰炸机";
String sentence2 = "泰山老队长费莱尼,来时英雄去时传奇";

        运行结果不再赘述,方法可行,效果尚佳。

### Java实现 Word2Vec 的方法 在 NLP 领域中,Word2Vec 是一种常用的词嵌入技术,能够将单词转换为连续向量表示。为了在 Java实现 Word2Vec,可以借助现有的开源工具和库来简化开发过程。 #### 使用 Deeplearning4j (DL4J) 实现 Word2Vec Deeplearning4j 是一个功能强大的机器学习框架,支持多种神经网络模型的构建与训练,其中包括 Word2Vec 模型的支持。以下是基于 DL4J 的 Word2Vec 示例代码: ```java import org.deeplearning4j.models.word2vec.Word2Vec; import org.deeplearning4j.text.sentenceiterator.BasicLineIterator; import org.deeplearning4j.text.sentenceiterator.SentenceIterator; import org.deeplearning4j.text.tokenization.tokenizerfactory.DefaultTokenizerFactory; import org.deeplearning4j.text.tokenization.tokenizerfactory.TokenizerFactory; import java.io.File; public class Word2VecExample { public static void main(String[] args) throws Exception { // 定义输入文件路径 File inputFile = new File("path/to/your/input.txt"); // 创建 SentenceIterator 来读取文本数据 SentenceIterator sentenceIterator = new BasicLineIterator(inputFile); // 设置 TokenizerFactory 进行分词操作 TokenizerFactory tokenizerFactory = new DefaultTokenizerFactory(); // 构建 Word2Vec 模型配置 Word2Vec word2Vec = new Word2Vec.Builder() .minWordFrequency(5) // 最小词频阈值 .iterations(1) // 训练迭代次数 .layerSize(100) // 向量维度大小 .seed(42) // 随机种子 .windowSize(5) // 上下文窗口大小 .iterate(sentenceIterator) // 数据源 .tokenizerFactory(tokenizerFactory) // 分词器工厂 .build(); // 执行模型训练 word2Vec.fit(); // 输出相似度最高的词语 String targetWord = "example"; System.out.println("Most similar words to '" + targetWord + "' are:"); for (String similar : word2Vec.wordsNearest(targetWord, 5)) { System.out.println(similar); } } } ``` 上述代码展示了如何利用 DL4J 库加载文本数据并训练 Word2Vec 模型[^1]。`SentenceIterator` 和 `TokenizerFactory` 负责处理原始文本数据,将其转化为适合模型训练的形式。通过调整参数(如层尺寸、最小词频等),可以根据需求优化模型性能。 #### 关键概念解析 - **嵌入**:嵌入是一种通用的技术,用于将离散的数据单元(如单词或字符)映射到低维空间中的稠密向量[^2]。 - **Word2Vec 特性**:作为嵌入的具体实例之一,Word2Vec 提供了一种有效的方法来捕捉单词之间的语义关系。 #### 注意事项 当使用外部库时,请确保已正确安装依赖项。对于 Maven 用户,可以在项目的 `pom.xml` 文件中添加以下依赖声明: ```xml <dependency> <groupId>org.nd4j</groupId> <artifactId>nd4j-native-platform</artifactId> <version>1.0.0-beta7</version> </dependency> <dependency> <groupId>org.deeplearning4j</groupId> <artifactId>deeplearning4j-nlp</artifactId> <version>1.0.0-beta7</version> </dependency> ``` 此设置允许开发者轻松集成 Word2Vec 功能至其应用程序中[^3]。 ---
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值