Java实现简易论文查重
软件工程 | https://edu.cnblogs.com/campus/gdgy/CSGrade21-12 |
---|---|
作业要求 | 个人项目 |
作业目标 | 学习PSP表格,简易实现论文查重功能 |
github链接 | https://github.com/HelpmeOOUT/RWL/tree/main/3121005006 |
PSP
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 30 |
-Estimate | -估计这个任务需要多少时间 | 30 | 50 |
Development | 开发 | 430 | 470 |
-Analysis | -需求分析 (包括学习新技术) | 150 | 90 |
-Design Spec | -生成设计文档 | 60 | 60 |
-Design Review | -设计复审 | 20 | 20 |
-Coding Standard | -代码规范 (为目前的开发制定合适的规范) | 30 | 20 |
-Design | -具体设计 | 40 | 30 |
-Coding | -具体编码 | 160 | 180 |
-Code Review | -代码复审 | 20 | 40 |
Test | 测试(自我测试,修改代码,提交修改) | 200 | 280 |
-Reporting | -报告 | 100 | 120 |
-Test Report | -测试报告 | 50 | 60 |
-Size Measurement | -计算工作量 | 40 | 60 |
-Postmortem & Process Improvement Plan | -事后总结, 并提出过程改进计划 | 30 | 40 |
合计 | 1380 | 1600 |
需求
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
从命令行参数给出:论文原文的文件的绝对路径。
从命令行参数给出:抄袭版论文的文件的绝对路径。
从命令行参数给出:输出的答案文件的绝对路径。
我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位
模块接口
算法模块
方法 | 说明 |
---|---|
public class TfIdf | 计算文本中词集的Tf(词频),Idf(逆文本频率指数),及Tf-Idf并以数组形式返回 |
public class CosAlgorithm implements CheckAlgorithm | 使用余弦定理计算相似度 |
具体代码
TfIdf算法
TF指词语在文档中出现的频率,即该词语在文档中出现的次数除以文档的总词语数。TF的值越大,表示词语在文档中的重要性越高。
IDF指词语的逆文档频率,即该词语在整个文档集中出现的频率的倒数。IDF的值越大,表示词语在整个文档集中的重要性越低。
TF-IDF的计算公式为 TF-IDF = TF * IDF。通过计算词语在文档中的TF值和在整个文档集中的IDF值,可以得到词语的TF-IDF值。TF-IDF值越大,表示该词语在当前文档中的重要性越高,并且在整个文档集中的共性越低。
public class TfIdf {
public static double countTf(String word, List<String> words){int tf = 0;
for (String s:words) {
tf += word.equals(s) ? 1 : 0;
}
return tf;
}
public static List<Double> countTfs(List<String> words){
ArrayList<Double> tfs = new ArrayList<>();
for (String s:words) {
tfs.add(countTf(s, words));
}
return tfs;
}
public static double countIdf(String word, List<List<String>> papers){
double paperContainingWord = 0;
for(List<String> words : papers) {
paperContainingWord += words.contains(word) ? 1 : 0;
}
return Math.log(papers.size() / paperContainingWord);
}
public static List<Double> countIdfs(List<String> words, List<List<String>> papers){
List<Double> idfs = new ArrayList<>();
for(String word : words) {
idfs.add(countIdf(word, papers));
}
return idfs;
}
public static double countTfIdf(double tf, double idf){
return tf * idf;
}
public static List<Double> countTfIdfs(List<String> words, List<List<String>> papers){
List<Double> tfIdfs = new ArrayList<>();
List<Double> tfs = countTfs(words);
List<Double> idfs = countIdfs(words, papers);
for(int i=0;i<tfs.size();i++){
tfIdfs.add(TfIdf.countTfIdf(tfs.get(i), idfs.get(i)));
}
return tfIdfs;
}
}
余弦相似度算法
在文本相似度计算中,通常将文本表示为词频向量或TF-IDF向量,然后使用余弦定理相似度来计算文本之间的相似度。通过比较不同文本之间的相似度,可以实现文本匹配、推荐系统和文本聚类等任务。
public class CosAlgorithm implements CheckAlgorithm {
public double check() {
return 0;
}
public double check(List<Double> v1, List<Double> v2){
//点积
double dotProduct = 0.0;
double normA = 0.0;
double normB = 0.0;
for (int i = 0; i < Math.min(v1.size(), v2.size()); i++) {
dotProduct += v1.get(i) * v2.get(i);
normA += Math.pow(v1.get(i), 2);
normB += Math.pow(v2.get(i), 2);
}
//模积
double magnitude = (Math.sqrt(normA) * Math.sqrt(normB));
return magnitude-0<0.0000001 ? 1 : dotProduct / magnitude;
}
}
运行结果
原文
copy
结果
模块接口部分的性能改进
调用最多的是分词依赖相关的char[]和分词后的处理String