当前位置: 首页 > news >正文

java实现计算ROUGE-L指标(一)

ROUGE (Recall-Oriented Understudy for Gisting Evaluation) 是用于评估自动文摘或机器翻译的一种评估方法,其中的ROUGE-L指标是基于最长公共子序列(Longest Common Subsequence,LCS)来计算的

我们做AI问答系统,需要一些量化指标来作为优化人工智能大模型的指导标准,经过调查Rouge-L的特征测量是量化指标的手段之一。

为了采用更精确的分词算法、词性还原和停用词处理,我借助一些自然语言处理的库,以下是我引入的maven依赖:

<dependency>  <groupId>edu.stanford.nlp</groupId>  <artifactId>stanford-corenlp</artifactId>  <version>3.9.2</version>  
</dependency>  
<dependency>  <groupId>edu.stanford.nlp</groupId>  <artifactId>stanford-corenlp</artifactId>  <version>3.9.2</version>  <classifier>models</classifier>  
</dependency>  
<dependency>  <groupId>junit</groupId>  <artifactId>junit</artifactId>  <version>4.12</version>  <scope>test</scope>  
</dependency>

然后是我的具体代码实现,因为词性标注和词性还原需要借助本地模型实现,为了快速落地量化指标,我暂时不使用词性标注和词性还原。

(Recall-Oriented Understudy for Gisting Evaluation) 是用于评估自动文摘或机器翻译的一种评估方法,其中的ROUGE-L指标是基于最长公共子序列(Longest Common Subsequence,LCS)来计算的。它主要关注词序列的匹配程度,不依赖于词性标注和词性还原。
因此,即使不使用词性标注和词性还原,只要确保分词正确,你仍然可以得到有效的ROUGE-L指标。

以下是我的代码具体实现:

package com.xxx.zjtest.testtest.test;import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.pipeline.*;
import edu.stanford.nlp.util.CoreMap;import java.util.*;/**** 不使用词性标注和词性还原直接计算ROUGE-L指标本身不会产生问题。**/
public class RougeLCalculator {private static final Set<String> STOP_WORDS = new HashSet<>(Arrays.asList("的", "了", "和", "是", "就", "都", "而", "及", "与", "在")); // 中文停用词示例列表public static double calculateRougeL(String referenceText, String hypothesisText) {// 创建Stanford CoreNLP管道Properties props = new Properties();props.setProperty("annotators", "tokenize, ssplit"); //加, pos, lemma 会报错props.setProperty("ssplit.eolonly", "true");StanfordCoreNLP pipeline = new StanfordCoreNLP(props);// 处理参考答案和假设答案Annotation referenceAnnotation = new Annotation(referenceText);Annotation hypothesisAnnotation = new Annotation(hypothesisText);pipeline.annotate(referenceAnnotation);pipeline.annotate(hypothesisAnnotation);// 获取参考答案和假设答案的词性还原后的单词列表/*List<String> referenceWords = getLemmatizedWords(referenceAnnotation, STOP_WORDS);List<String> hypothesisWords = getLemmatizedWords(hypothesisAnnotation, STOP_WORDS);*/// 获取参考答案和假设答案的分词列表List<String> referenceWords = getTokenizedWords(referenceAnnotation, STOP_WORDS);List<String> hypothesisWords = getTokenizedWords(hypothesisAnnotation, STOP_WORDS);// 计算ROUGE-L指标return calculateLongestCommonSubsequence(referenceWords, hypothesisWords);}//词性标注和词性还原部分,此部分需要使用大模型,无法实现/*private static List<String> getLemmatizedWords(Annotation annotation, Set<String> stopWords) {List<String> words = new ArrayList<>();for (CoreMap sentence : annotation.get(CoreAnnotations.SentencesAnnotation.class)) {for (CoreLabel token : sentence.get(CoreAnnotations.TokensAnnotation.class)) {String word = token.word(); // 获取分词后的单词String pos = token.get(CoreAnnotations.PartOfSpeechAnnotation.class); // 获取词性标注String lemma = token.get(CoreAnnotations.LemmaAnnotation.class); // 获取词性还原后的单词if (!stopWords.contains(word) && !pos.equalsIgnoreCase("PUNCT")) { // 过滤停用词和标点符号words.add(lemma);}}}return words;}*/private static List<String> getTokenizedWords(Annotation annotation, Set<String> stopWords) {List<String> words = new ArrayList<>();for (CoreMap sentence : annotation.get(CoreAnnotations.SentencesAnnotation.class)) {for (CoreLabel token : sentence.get(CoreAnnotations.TokensAnnotation.class)) {String word = token.word(); // 获取分词后的单词if (!stopWords.contains(word)) { // 过滤停用词words.add(word);}}}return words;}//计算公共最长子序列private static double calculateLongestCommonSubsequence(List<String> referenceWords, List<String> hypothesisWords) {int[][] dp = new int[referenceWords.size() + 1][hypothesisWords.size() + 1];for (int i = 1; i <= referenceWords.size(); i++) {for (int j = 1; j <= hypothesisWords.size(); j++) {if (referenceWords.get(i - 1).equals(hypothesisWords.get(j - 1))) {dp[i][j] = dp[i - 1][j - 1] + 1;} else {dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);}}}int lcs = dp[referenceWords.size()][hypothesisWords.size()];double precision = (double) lcs / hypothesisWords.size();double recall = (double) lcs / referenceWords.size();double rougeL = 2 * precision * recall / (precision + recall);System.out.println(rougeL);return rougeL;}public static double calculateAverageRougeL(List<String> referenceTexts, List<String> hypothesisTexts) {if (referenceTexts.size() != hypothesisTexts.size()) {throw new IllegalArgumentException("参考文本列表和假设文本列表的长度必须相等");}double totalRougeL = 0;for (int i = 0; i < referenceTexts.size(); i++) {totalRougeL += calculateRougeL(referenceTexts.get(i), hypothesisTexts.get(i));}return totalRougeL / referenceTexts.size();}public static void main(String[] args) {String yTest1 = "客户专用网络的使用应注意以下几点:\n" +"\n" +"实施方案应由公司网络管理员组织制定,并与客户共同协商制定实施方案。\n" +"禁止将客户要求隔离的网络与未经客户许可的网络连通。\n" +"禁止将客户要求使用的网络与公司内部网络连通。\n" +"禁止在客户专用网络中搭建无线网络。\n" +"禁止在客户专用网络中使用笔记本电脑。\n" +"禁止在客户专用网络中未经过客户允许进行互联网访问。\n" +"禁止在客户专用网络中未按照客户要求执行设备要求。";String nTest1 = "根据已知信息,客户专用网络的注意事项有以下几点:\n" +"\n" +"禁止将客户要求隔离的网络与未经客户许可的网络连通。\n" +"禁止将客户要求使用的网络与公司内部网络连通。\n" +"禁止在客户专用网络中搭建无线网络。\n" +"禁止在客户专用网络中使用笔记本电脑。\n" +"禁止在客户专用网络中未经过客户允许进行互联网访问。\n" +"禁止在客户专用网络中未按照客户要求执行设备要求。\n" +"客户专用网络的申请与构建应由公司网络管理员组织制定,并与客户共同协商制定实施方案。\n" +"客户专用网络的规划与实施应由公司网络管理员与申请部门共同执行,如在实施过程中需要第三方参与,公司网络管理员应进行监督,并与申请部门共同验收。\n" +"若需使用客户的内部网络,必须事先获得客户批准,并严格遵守客户的网络安全规定,只能从事和业务相关的工作,不得私自查看其它计算机或客户内部网络上的任何保密信息,禁止任何令客户网络严重增加负载或容易引起网络故障的行为。\n" +"若需在客户现场访问Internet,必须事先获得客户批准,并按照客户的要求采取必要的安全措施。";String yTest2 = "禁止将公司资料、私人信息以及敏感内容存储在个人邮箱中,避免信息泄露。\n" +"及时删除接收的邮件,避免信息被他人获取。\n" +"禁止使用私人邮箱用于工作中的业务往来,避免信息泄露。\n" +"谨慎使用电子邮件,避免感染病毒,确保邮件发送保密信息。\n" +"禁止使用工作手机号码进行非工作目的的网站注册。\n" +"及时将工作手机的操作系统升级至最新版本。\n" +"工作手机信息安全管理要求,包括保密性、完整性、可用性等方面。";String nTest2="不要将公司资料、私人信息以及敏感内容存储在个人邮箱中,避免信息泄露。\n" +"及时删除接收的邮件,避免信息被他人获取。\n" +"禁止使用私人邮箱用于工作中的业务往来。\n" +"谨慎使用电子邮件,避免感染病毒,确保邮件发送保密信息。\n" +"禁止使用工作手机号码进行非工作目的的网站注册。\n" +"及时将工作手机的操作系统升级至最新版本。\n" +"遵守公司电子邮件尺寸规定,不得发送超大邮件。\n" +"收到不明电子邮件尽量不要回信,含有可疑附件时不得打开,并应立即删除该邮件。\n" +"发送电子邮件时,应认真核对收件人地址,避免误传送。\n" +"若发生电子邮件误传送时,应立即再发一封致歉信,声明发错,并请对方将已收到的邮件删除。\n" +"若邮件含有公司敏感信息,应立即向部门领导及业务安全部汇报。\n" +"当收到别人发错的电子邮件时,应立即通知提醒发件人,若该邮件含有改善敏感信息,应将邮件彻底删除。\n" +"禁止使用手机VPN进行加密。\n" +"禁止使用工作手机接收邮件。\n" +"禁止使用私人邮箱进行邮件收发。\n" +"禁止使用手机接收或发送邮件时点击或打开可疑链接或附件,避免被恶意攻击导致信息泄露。";//计算单个值//System.out.println(calculateRougeL(yTest1,nTest1));// 计算平均值List<String> referenceTexts = Arrays.asList(yTest1, yTest2);List<String> hypothesisTexts = Arrays.asList(nTest1, nTest2);double averageRougeL = calculateAverageRougeL(referenceTexts, hypothesisTexts);System.out.println("平均ROUGE-L值: " + averageRougeL);}
}
  • tokenize: 这个注解器用于将文本分解成单词或标记(tokens)。例如,对于句子"Hello world!",tokenize会将其分解为两个标记:“Hello"和"world!”。
  • ssplit: 这个注解器用于句子分割,即将文本分割成句子。它根据标点符号和其他线索来确定句子的边界。
  • ssplit.eolonly: 这是一个特定的句子分割选项。当设置为true时,它只根据行尾(end-of-line)符号来分割句子,忽略其他标点符号。这通常用于那些每行只有一个句子的文本。

相关文章:

java实现计算ROUGE-L指标(一)

ROUGE (Recall-Oriented Understudy for Gisting Evaluation) 是用于评估自动文摘或机器翻译的一种评估方法&#xff0c;其中的ROUGE-L指标是基于最长公共子序列&#xff08;Longest Common Subsequence&#xff0c;LCS&#xff09;来计算的 我们做AI问答系统&#xff0c;需要一…...

LLM之RAG实战(二十九)| 探索RAG PDF解析

对于RAG来说&#xff0c;从文档中提取信息是一种不可避免的场景&#xff0c;确保从源文件中提取出有效的内容对于提高最终输出的质量至关重要。 文件解析过程在RAG中的位置如图1所示&#xff1a; 在实际工作中&#xff0c;非结构化数据比结构化数据丰富得多。如果这些海量数据无…...

C while 和 do while 区别

while 和 do while 都是 C 语言中的循环语句&#xff0c;它们的主要区别在于循环体执行的顺序。 while 循环首先检查循环条件&#xff0c;只有当条件为真时才执行循环体。因此&#xff0c;如果条件一开始就为假&#xff0c;那么循环体将永远不会执行。而如果条件一直为真&…...

力扣每日一题 在受污染的二叉树中查找元素 哈希 DFS 二进制

Problem: 1261. 在受污染的二叉树中查找元素 思路 &#x1f468;‍&#x1f3eb; 灵神题解 &#x1f496; 二进制 时间复杂度&#xff1a;初始化为 O ( 1 ) O(1) O(1)&#xff1b;find 为 O ( m i n ( h , l o g 2 t a r g e t ) O(min(h,log_2target) O(min(h,log2​targ…...

安卓Java面试题 91- 100

91. 请描述一下Intent 和 IntentFilter ?Intent是组件的通讯使者,可以在组件间传递消息和数据。 IntentFilter是intent的筛选器,可以对intent的action,data,catgory,uri这些属性进行筛选,确定符合的目标组件🚀🚀🚀🚀🚀🚀92. 阐述什么是IntentService?有何优…...

BM1684X搭建sophon c++环境

1:首先安装编译好sophon-sail 比特大陆BM1684X开发环境搭建--SOC mode-CSDN博客 2:在将之前配置的soc-sdk拷贝一份到sdk根目录&#xff0c;将交叉编译好的sail中的build_soc拷贝至soc-sdk文件夹内&#xff1b; cp -rf build_soc/sophon-sail/inlcude soc-sdk cp -rf build_soc…...

UDP通讯测试

参考资料:UNIX网络编程 实验平台:PC为client,RaspberryPi为server 基本类型和接口函数,参考man手册 #include <sys/socket.h>struct sockaddr {sa_family_t sa_family; /* Address family */char sa_data[]; /* Socket address */};#inclu…...

Linux - 进程间通信

1、进程间通信介绍 1.1、进程间通信目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程&#xff1b;资源共享&#xff1a;多个进程之间共享同样的资源&#xff1b;通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#xff0c;通知它&#xff08;…...

代码随想录算法训练营第七天|454. 四数相加 II

454. 四数相加 II 已解答 中等 相关标签 相关企业 给你四个整数数组 nums1、nums2、nums3 和 nums4 &#xff0c;数组长度都是 n &#xff0c;请你计算有多少个元组 (i, j, k, l) 能满足&#xff1a; 0 < i, j, k, l < nnums1[i] nums2[j] nums3[k] nums4[l] 0 示例 …...

蓝桥杯刷题(五)

[蓝桥杯 2022 省 B] 刷题统计 题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示 题目描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a a…...

mysql语句中想要查询某一月每一天日期的平均值 ,SSM框架如何实现

mysql语句中想要查询某一月每一天日期的平均值 为了查询某一月份每一天的平均值&#xff0c;你可以使用以下SQL查询语句。这里假设你有一个表格data_table&#xff0c;它有一个日期时间列date_column和一个需要计算平均值的数值列value_column。 SELECTDATE_FORMAT(date_colum…...

前端框架的发展历程

文章目录 前言 一、静态页面时代 二、JavaScript的兴起 三、jQuery的出现 四、前端框架的崛起 1.AngularJS 2.React 3.Vue.js 五、面向组件化的发展趋势 总结 前言 前端框架的发展史就是一个不断进化的过程&#xff0c;它的发展和进化一定程度…...

【LeetCode 算法专题突破】---二分查找(⭐⭐⭐)

前言 我在算法题目的海洋中畅游已久&#xff0c;也曾在算法竞赛中荣获佳绩。然而&#xff0c;我发现自己对于算法的学习&#xff0c;还缺乏一个系统性的总结和归类。尽管我已经涉猎过不少算法类型&#xff0c;但心中仍旧觉得有所欠缺&#xff0c;未能形成完整的算法体系。 因…...

一个简单的HTML 个人网页

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>个人网页</title> <style> body { f…...

【SpringCloud微服务实战05】Feign 远程调用

Feign是一个由Netflix开发的轻量级RESTful HTTP服务客户端,用于简化和优雅地调用HTTP API。它允许用户通过Java接口注解来发起请求,而不必像传统方式那样手动构建HTTP请求报文。Feign支持Spring Cloud解决方案,使得服务消费者能够像调用本地接口方法一样调用远程服务。使得开…...

LiveGBS流媒体服务器中海康摄像头GB28181公网语音对讲、语音喊话的配置

LiveGBS海康摄像头国标语音对讲大华摄像头国标语音对讲GB28181语音对讲需要的设备及服务准备 1、背景2、准备2.1、服务端必备条件&#xff08;注意&#xff09;2.2、准备语音对讲设备2.2.1、不支持跨网对讲示例2.2.2、 支持跨网对讲示例 3、开启音频开始对讲4、搭建GB28181视频…...

【前端】尚硅谷Webpack教程笔记

文章目录 1. 基本使用1.1 功能介绍1.2 开始使用 参考视频:尚硅谷Webpack5入门到原理 课件地址 【前端目录贴】 1. 基本使用 1.1 功能介绍 Webpack 是一个静态资源打包工具。 它会以一个或多个文件作为打包的入口&#xff0c;将我们整个项目所有文件编译组合成一个或多个文件输…...

Java泛型使用及局限

Java泛型的局限和使用经验 泛型的局限 任何基本类型不能作为类型参数 经过类型擦除后&#xff0c;List中包含的实际上还是Object的域&#xff0c;而在Java类型系统中Object和基本类型是两套体系&#xff0c;需要通过“自动装包、拆包机制”来进行交互。 2.任何在运行时需要…...

Sklearn线性回归

Scikit-learn 中的线性回归是一个用于监督学习的算法&#xff0c;它用于拟合数据集中的特征和目标变量之间的线性关系。以下是使用 Scikit-learn 实现线性回归的基本步骤&#xff1a; 1. 导入所需库 首先&#xff0c;你需要导入所需的库和模块。 import numpy as np import …...

APP中互联网公司的必备知识

APP中互联网公司的必备知识 敏捷开发&#xff08;scrum&#xff09;模型角色工作流程 项目上线发布策略发布流程灰度发布 APP发布APP软件包类型APP客户端&#xff08;内部&#xff09;发布平台APP客户端&#xff08;线上&#xff09;发布平台 熟悉APP项目&#xff08;tpshop&am…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...