zoukankan      html  css  js  c++  java
  • 第一次个人编程作业


    part.Ⅰ GitHub

    my github

    part.Ⅱ PSP表格
    PSP2.1 Personal Software
    Process Stages
    预估耗时
    (分钟)
    实际耗时
    (分钟)
    Planning 计划 40 50
    · Estimate · 估计这个任务需要多少
    时间
    40 60
    Development 开发 420 450
    · Analysis · 需求分析 (包括学习新
    技术)
    280 300
    · Design Spec · 生成设计文档 40 40
    · Design Review · 设计复审 60 80
    · Coding Standard · 代码规范 (为目前的开
    发制定合适的规范)
    60 60
    · Design · 具体设计 100 120
    · Coding · 具体编码 180 200
    · Code Review · 代码复审 30 60
    · Test · 测试(自我测试,修改
    代码,提交修改)
    40 60
    Reporting 报告 70 80
    · Test Repor · 测试报告 40 40
    · Size Measurement · 计算工作量 30 30
    · Postmortem & Process
    Improvement Plan
    · 事后总结, 并提出过程
    改进计划
    40 60
    · 合计 1470 1670
    part.Ⅲ 计算模块接口的设计与实现过程

    在查阅一些资料后,我就决定使用余弦相似度来做。
    基本思路是:如果这两句话的用词越相似,它们的内容就应该越相似。因此,可以从词频入手,计算它们的相似程度。
    第一步,分词。

      句子A:我/喜欢/看/电视,不/喜欢/看/电影。

      句子B:我/不/喜欢/看/电视,也/不/喜欢/看/电影。

    第二步,列出所有的词。

      我,喜欢,看,电视,电影,不,也。

    第三步,计算词频。

      句子A:我 1,喜欢 2,看 2,电视 1,电影 1,不 1,也 0。

      句子B:我 1,喜欢 2,看 2,电视 1,电影 1,不 2,也 1。

    第四步,写出词频向量。

      句子A:[1, 2, 2, 1, 1, 1, 0]

      句子B:[1, 2, 2, 1, 1, 2, 1]

    余弦值越接近1,就表明夹角越接近0度,也就是两个向量越相似,这就叫"余弦相似性"。

    首先我是用jieba.lcut将两篇文章分词,并计算对应的词频向量,然而相似度算出来都是0.99+,于是我查看了分词的结果

    原来是"我","了","的","在"这种词语频率太高了,我第一反应是降低这些词语的权重,后面查阅了一些资料,发现在NLP中,这些词被称为停用词,于是我从网上下载了一个停用词库,对于在停用词库里的词乘一个较小的比例系数,相似度结果有所好转。
    然而,我看到了作业的一条提醒:凡提交的可执行文件、出现下列情况之一者,作业以0分计:
    ...
    尝试读写其他文件
    ...
    ,所以这个想法只能放弃。
    然后我又通过查资料找到一个jieba.analyse.textrank()函数,格式是keywords = jieba.analyse.textrank(content, topK=5, withWeight=True, allowPOS=('ns', 'n', 'vn', 'v')),
    即关键词仅提取地名、名词、动名词、动词。结果挺符合我的期望,但当我import time库去计算程序运行时间的时候,结果时间都是5s以上,放弃+1.
    最后我选择使用jieba.analyse.extract_tags()函数,它的allows参数默认为[""],不会过滤词性。而textrank()需要构造图,复杂度高,时间自然就长。虽然extract_tags()的效果会差亿点,不过时间却少了很多,总的来说差强人意。

    流程图

    函数介绍(没进行异常处理)

    # 余弦相似度算法适合短文本,所以短文本的关键词数/总词数可以尽量大些
    def wordsNum(num):
        if num<10:
            return num
        elif num<200:
            return ceil(num/2)
        else:
            return ceil(num/3)
    def extractKeywords(path):
        s = open(path, 'r', encoding='utf-8')
        line = s.read()
        # punctuation是从zhon.hanzi导入的包含很多符号的字符串,punctuation += '
     '(有个空格),再用正则表达式替换就能得到一个纯中文字符串
        line = re.sub(r"[%s]+" % punctuation, "", line) 
        # 根据词语数量来确定提取关键词数量,用set去除重复元素
        wordSum = jieba.lcut(line)
        length = len(set(wordSum))
        # 利用jieba.analyse.extract_tags()函数,返回关键词及其权重(需要设置withWeight=True)
        keyWords = jieba.analyse.extract_tags(line, wordsNum(length), True)
        s.close()
        # 原来的keyWords是一个列表,里面的元素都是元组,转成字典有利用后续操作
        return dict(keyWords)
    
    # 求两个关键词并集,先用集合去重,返回list是为了方便遍历
    def mergeWords(d1, d2):
        wordSet = set(d1.keys()).union(d2.keys())
        return list(wordSet)
    
    # 求关键词向量
    def calVector(d, wordlist):
        length = len(wordlist)
        vector = [0] * length
        keys = d.keys()
        for i in range(length):
            if wordlist[i] in keys:
                vector[i] = d[wordlist[i]]
        return vector
    
    # 求余弦相似度
    def calCos(v1, v2):
        vectorLength = len(v1)
        B = sum(v1[i]*v2[i] for i in range(vectorLength))
        A1 = sum(i**2 for i in v1)
        A2 = sum(i**2 for i in v2)
        A = sqrt(A1*A2)
        return B/A
    
    # 将结果写入指定文件
    def saveData(path,data):
        with open(path, 'w') as file_object:
            file_object.write(format(data, ".2f"))
            file_object.close()
            print("写入"+path+"文件完成")
    
    # 主函数
    if __name__ == "__main__":
        # sys.argv[0] : main.py
        filePath1,filePath2,savePath = sys.argv[1],sys.argv[2],sys.argv[3]
        # 加上换行和空格,结合正则表达式可去除所有非中文的字符
        punctuation += '
     '
        # 分别提取两篇文本的关键词及其权重
        t1 = extractKeywords(filePath1)
        t2 = extractKeywords(filePath2)
        # 求出关键词并集
        words = mergeWords(t1, t2)
        # 分计算词向量
        v1 = calVector(t1, words)
        v2 = calVector(t2, words)
        # 计算余弦相似度
        cos = calCos(v1, v2)
        # 在指定路径存储数据
        saveData(savePath,cos)
        print('相似度为 = ' + format(cos, ".2f"))
        # 评测结束返回0
        sys.exit(0)
    
    part.Ⅳ 计算模块接口部分的性能改进

    使用pycharm的性能分析

    时间花费最多的是提取关键词函数

    总时间

    part.Ⅴ 计算模块部分单元测试展示
    import unittest
    from mainfunc import maintest
    # 部分
    class MyTest(unittest.TestCase):
    
        orig = 'C:imagesim_0.8orig.txt'
        folderpath = 'C:imagesim_0.8\'
    
        def test_add(self):
            fileName = "orig_0.8_add.txt"
            cosValue = maintest.calCos(self.orig, self.folderpath+fileName)
            print(fileName+"的相似度为:"+format(cosValue, ".3f"))
    
        def test_dis_1(self):
            fileName = "orig_0.8_dis_1.txt"
            cosValue = maintest.calCos(self.orig, self.folderpath+fileName)
            print(fileName+"的相似度为:"+format(cosValue, ".3f"))
    
        def test_dis_3(self):
            fileName = "orig_0.8_dis_3.txt"
            cosValue = maintest.calCos(self.orig, self.folderpath+fileName)
            print(fileName+"的相似度为:"+format(cosValue, ".3f"))
    
        def test_rep(self):
            fileName = "orig_0.8_rep.txt"
            cosValue = maintest.calCos(self.orig, self.folderpath+fileName)
            print(fileName+"的相似度为:"+format(cosValue, ".3f"))
    
    if __name__ == "__main__":
        unittest.main()
    
    

    测试结果

    part.Ⅵ 计算模块部分异常处理说明
    我认为异常处理主要有三点:
    1.命令行输入参数不正确
    2.要读取的文件不存在
    3.读取的文件是空文本
    # 前两个我在主函数用try-exception处理,如果发生异常,就打印错误原因
        try:
            ...
        except Exception as e:
            print(e)
            print("请输入正确的参数")
        finally:
            # 程序结束,返回0
            sys.exit(0)
    # 读取的文件是空文本,会出现除0的错误,就返回余弦相似度为0
    try:
    def calCos(v1, v2):
        try:
            vectorLength = len(v1)
            B = sum(v1[i]*v2[i] for i in range(vectorLength))
            A1 = sum(i**2 for i in v1)
            A2 = sum(i**2 for i in v2)
            A = sqrt(A1*A2)
            return B/A
        except ZeroDivisionError as e:
            print(e)
            return 0
    

    1.命令行参数不正确

    2.要读取的文件不存在

    3.读取的文件是空文本

    最终代码重用率为

    part.Ⅶ 总结

    一开始看到这个题目,就感觉到快,有催人跑的意思,所以我们现在正合适做这样的题。通过此次面向百度编程,我新认识了许多东西,github,性能分析,单元测试等等。很惭愧,too young too simple,sometimes naive!就做了一点微小的工作。最后用鹅城张牧之的一句话勉励一下自己:雄关漫道真如铁,而今迈步从头越。

  • 相关阅读:
    八个方便C#开发的省时的国外工具
    从babel-polyfill的一个坑而起
    Universal Link
    微信机器人
    微信手记
    Elasticsearch手记
    小游戏引擎手记
    【数学基础】3D数学基础-左右手坐标系
    【linux基础】linux误改sudoers权限之后的恢复及配置sudoers
    【c/c++基础】struct/typedef struct的用法详解总结
  • 原文地址:https://www.cnblogs.com/baiii/p/13688096.html
Copyright © 2011-2022 走看看