个人项目作业-论文查重

|这个课程属于哪个课程 | 软件工程2024-双学位 (广东工业大学)|第二次作业
|-- |-- |
|这个作业要求在哪里 |个人项目作业-论文查重 |
|这个作业的目标 |代码实现、性能分析、单元测试、异常处理说明、记录PSP表格 |

本项目已上传到Gitcode



需求

题目:论文查重

描述如下:

设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。

  • 原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
  • 抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。

要求输入输出采用文件输入输出,规范如下:

  • 从命令行参数给出:论文原文的文件的绝对路径。
  • 从命令行参数给出:抄袭版论文的文件的绝对路径。
  • 从命令行参数给出:输出的答案文件的绝对路径。

我们提供一份样例(提取码:nwjr),使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。

注意:答案文件中输出的答案为浮点型,精确到小数点后两位。



开发环境

编程语言 Python
IDE PyCharm Community Edition 2023.3.4
Python版本 3.10.11

依赖库

  • coverage == 7.4.3
  • jieba == 0.42.1
  • line-profiler == 4.1.2
  • line-profiler-pycharm == 1.1.0
  • numpy == 1.26.4



代码实现

接口设计

jieba分词

def tokenize(stopwords_file, text):
    stopwords = set()
    with open(stopwords_file, 'r', encoding='utf-8') as file:
        stopwords = set(line.strip() for line in file.readlines())
    words = jieba.cut(text)  # 使用jieba库的cut接口分词进行分词
    return [word for word in words if word.strip() and word not in stopwords]

文本转换为词向量

def count_words(tokens, total_unique_words):
    word_counts = Counter(tokens)
    vector = [word_counts.get(word, 0) for word in total_unique_words]
    return vector

numpy计算余弦相似度

def cosine_similarity(vec1, vec2):
    dot_product = np.dot(vec1, vec2)
    norm_vec1 = np.linalg.norm(vec1)
    norm_vec2 = np.linalg.norm(vec2)
    return dot_product / (norm_vec1 * norm_vec2)

命令行参数

parser = argparse.ArgumentParser()
    parser.add_argument('source_file', help='原文文件的绝对路径')
    parser.add_argument('target_file', help='抄袭版本文件的绝对路径')
    parser.add_argument('res_file', help='输出答案文件的绝对路径')
    args = parser.parse_args()

main函数

def main(args):
    stopwords_file = 'test_stopwords.txt'

    with open(args.source_file, 'r', encoding='utf-8') as f:
        source_text = f.read()
    with open(args.target_file, 'r', encoding='utf-8') as f:
        target_text = f.read()

    # 对原文和抄袭版本文本进行分词处理
    source_tokens = tokenize(stopwords_file, source_text)
    target_tokens = tokenize(stopwords_file, target_text)

    # 获取总词汇表
    total_words = list(set(source_tokens + target_tokens))

    # 将分词后的文本转换为词向量
    source_vector = count_words(source_tokens, total_words)
    target_vector = count_words(target_tokens, total_words)

    # 计算余弦相似度
    similarity = cosine_similarity(source_vector, target_vector)
    similarity_percentage = similarity * 100

    with open(args.res_file, 'w', encoding='utf-8') as f:
        f.write('相似度为:%.2f%%' % similarity_percentage)

执行结果





单元测试

导入unittest模块,编写测试单元。

被测试函数:

  • tokenize
  • count_words
  • cosine_similarity
import unittest
from main import tokenize, count_words, cosine_similarity


class TestTextSimilarity(unittest.TestCase):

    def test_tokenize(self):
        # 测试 tokenize 函数
        stopwords_file = 'test_stopwords.txt'
        text_with_stopwords = "这是一个测试文本"

        expected_tokens_with_stopwords = ['这是', '一个', '测试', '文本']

        tokens_with_stopwords = tokenize(stopwords_file, text_with_stopwords)

        # 验证每个标记是否正确
        self.assertEqual(tokens_with_stopwords[0], expected_tokens_with_stopwords[0])
        self.assertEqual(tokens_with_stopwords[1], expected_tokens_with_stopwords[1])
        self.assertEqual(tokens_with_stopwords[2], expected_tokens_with_stopwords[2])
        self.assertEqual(tokens_with_stopwords[3], expected_tokens_with_stopwords[3])

    def test_count_words(self):
        # 测试 count_words 函数
        tokens = ['a', 'b', 'a', 'c']
        total_unique_words = ['a', 'b', 'c', 'd']
        expected_vector = [2, 1, 1, 0]

        vector = count_words(tokens, total_unique_words)

        self.assertEqual(vector, expected_vector)

    def test_cosine_similarity(self):
        # 测试 cosine_similarity 函数
        vec1 = [1, 2, 3]
        vec2 = [2, 3, 4]
        expected_similarity = 0.9925833339709303

        similarity = cosine_similarity(vec1, vec2)

        self.assertAlmostEqual(similarity, expected_similarity, places=4)


if __name__ == '__main__':
    unittest.main()

代码性能

性能分析

利用python的cProfile库对其进行性能分析。

代码覆盖率

利用coverage工具实现覆盖率测试。

通过命令

coverage run main.py

生成测试文件。



可以看出test.py的代码覆盖率为百分之百,但main.py的代码覆盖率只有52%,我们检查下原因。

可以看出是因为我们的main函数依赖命令行输入文件地址才可以运行,不影响其性能。


PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 30
Estimate 估计这个任务需要多少时间 30 20
Development 开发 80 100
Analysis 需求分析 (包括学习新技术) 120 150
Design Spec 生成设计文档 30 30
Design Review 设计复审 20 20
Coding Standard 代码规范 (为目前的开发制定合适的规范) 20 20
Design 具体设计 30 30
Coding 具体编码 90 120
Code Review 代码复审 30 20
Test 测试(自我测试,修改代码,提交修改) 80 100
Reporting 报告 100 80
Test Repor 测试报告 100 90
Size Measurement 计算工作量 30 30
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 30 30
合计 810 850
posted @ 2024-03-16 16:04  BondBondG  阅读(32)  评论(0编辑  收藏  举报