这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/Networkengineering1834 |
---|---|
----------------- | --------------- |
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/Networkengineering1834/homework/11146 |
这个作业的目标 | 学会使用PSP表格规划项目各步骤开发时间,学习Git commit规范,使用Git管理代码 |
一、github仓库地址:
https://github.com/smietao/smietao/tree/master/3118005337/checkPaperRepeat
二、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 25 |
· Estimate | 估计这个任务需要多少时间 | 15 | 20 |
Development | 开发 | 360 | 460 |
· Analysis | 需求分析 (包括学习新技术) | 120 | 180 |
· Design Spec | 生成设计文档 | 40 | 50 |
· Design Review | 设计复审 | 20 | 20 |
· Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 10 | 10 |
· Design | 具体设计 | 60 | 60 |
· Coding | 具体编码 | 150 | 200 |
· Code Review | 代码复审 | 60 | 30 |
· Test | 测试(自我测试,修改代码,提交修改) | 60 | 60 |
Reporting | 报告 | 150 | 200 |
·Test Report | 测试报告 | 90 | 150 |
·Size Measurement | 计算工作量 | 10 | 10 |
·Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 10 | 20 |
Total | 合计 | 1185 | 1495 |
三、算法设计
3.1 算法思路
这次使用的是比较简单的算法——直接用jieba分词,并计算各个词的TF-IDF值(停用词表采用的是jieba自带的,TF-IDF语料库也是采用jieba自带的),再用TF-IDF值构造词向量,最后计算余弦相似度。
TF-IDF参考阮一峰老师的两篇博客:
3.2 流程图
四、计算模块的设计以及实现过程
4.1 项目结构体系
其中APP为主启动类,main方法在其中;keyword包下是分词类以及计算TF-IDF值的类;util包下是读取文本和计算余弦相似度的工具类;共计五个类。
4.2 类调用关系
App
类首先调用ReadTxt
类读取txt文件中的内容,将其转化为String类型的字符串。之后使用TFIDFAnalyzer
类的analyze方法进行分词操作,将结果封装成List<KeyWord>
集合。最后将两个List集合传入CalculateCosSim
类的静态方法calculateCosineSimilarity
计算余弦相似度,最后通过IO流将结果输出到指定路径的txt文件中。
4.3 算法关键
- jieba分词
- 计算关键词词频
- 循环找到相同的关键词
- 利用余弦相似度公式计算结果
五、计算模块接口部分的性能改进
for (Keyword oriKeyword : originalList) {
for (Keyword plaKeyword : plagiarizeList) {
if (oriKeyword.getName().equals(plaKeyword.getName())) {
double oriTfidfvalue = oriKeyword.getTfidfvalue();
double plaTfidfvalue = plaKeyword.getTfidfvalue();
// 如果高频词相等,计算
v1 += oriTfidfvalue * oriTfidfvalue;
v2 += plaTfidfvalue * plaTfidfvalue;
v += oriTfidfvalue * plaTfidfvalue;
// 计算完后跳出内层循环,找下一个词
break;
}
}
}
在使用foreach循环找到了高频词后通过break跳出循环,避免了多余的循环计算。
六、计算模块部分单元测试展示
6.1 单元测试框架:Junit5
6.2 单元测试结果(仅展示部分)
-
分词测试
@Test public void testTfidfAnalyzer() { String content = "今天是星期天,天气晴,今天晚上我要去看电影"; // 定义关键词个数 int topN = 5; // 提取文章中的20个关键词和词频 TFIDFAnalyzer tfidfAnalyzer = new TFIDFAnalyzer(); List<Keyword> keywordList = tfidfAnalyzer.analyze(content, topN); if (keywordList != null && keywordList.size() != 0) { for (Keyword keyword : keywordList) { System.out.println("关键词为【" + keyword.getName() + "】,词频为【" + keyword.getTfidfvalue() + "】"); } } }
测试结果:
-
txt文件读取转化为String字符串测试
@Test public void testTxtRead() { File orgFile = new File("D:/org.txt"); // 读取txt文件中的内容 转化为String类型 String original = ReadTxt.txt2String(orgFile).trim(); System.out.println(original); }
测试结果:
-
余弦相似度计算测试:
@Test public void testCalculate() { String original = "今天是星期天,天气晴,今天晚上我要去看电影"; String plagiarize = "今天是周天,天气晴朗,我晚上要去看电影"; // 定义关键词个数 int topN = 5; // 提取文章中的5个关键词和词频 TFIDFAnalyzer tfidfAnalyzer = new TFIDFAnalyzer(); List<Keyword> originalList = tfidfAnalyzer.analyze(original, topN); List<Keyword> plagiarizeList = tfidfAnalyzer.analyze(plagiarize, topN); Double repetitiveRate = CalculateCosSim.calculateCosineSimilarity(originalList, plagiarizeList); System.out.println("两段文本的余弦相似度为:" + repetitiveRate); }
测试结果:
-
代码覆盖率
七、计算模块部分异常处理说明
public class CustomException extends RuntimeException {
private String message;
public CustomException(String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
自定义运行时异常,在计算模块部分两个地方抛出:
-
命令行参数不是预期的三个
int length = args.length; if (length != 3) { // 参数不是三个,说明命令入参错误 throw new CustomException("命令行入参数量有误!"); }
-
读取的文本内容为空
if (original.length() == 0) { throw new CustomException("原文文本内容为空!"); } if (plagiarize.length() == 0) { throw new CustomException("抄袭文文本内容为空!"); }