一、基本信息
1.1 本次作业地址:https://edu.cnblogs.com/campus/ntu/Embedded_Application/homework/2088
1.2 项目的Git地址:https://gitee.com/ntucs/PairProg
1.3合作:1613072005 蒋晓明 1613072006 陈扬
二、项目分析
2.1程序运行模块(方法、函数)介绍
Task1:基本任务
(1)统计文件的有效行数
def process_lines(dst):#读取行数 f = open("result.txt",'w') count = 0 for index, line in enumerate(open(dst, 'r')):#利用enumerate函数读取行数 count += 1 print("lines:",count,file=f) print("lines:",count) f.close()
(2)统计文件的单词总数
def process_count(bvffer):#统计总词数数 f = open("result.txt", 'a') count=bvffer.count(" ")+1 #空格数加一为单词总数 print("words:",count,file=f) print("words:",count) f.close()
(3)定义单词并为各符合定义的单词计数
def process_buffer(bvffer):#包括定义单词和计数 if bvffer: word_freq = {} # 下面添加处理缓冲区 bvffer代码,统计每个单词的频率,存放在字典word_freq bvffer=bvffer.lower() #大小写转换,将大写字母转化为小写字母 for s in '“”!?,.;:$': bvffer=bvffer.replace(s,' ') #将找出的特殊符替换为空格 list=re.findall(r'[a-z]{4}\w*',bvffer)#利用re模块的查找功能与正则表达式相结合,找出符合单词定义的单词,存入list for str in list: word_freq[str] = word_freq.get(str, 0) + 1 #计数 return word_freq
(4)输出频率最高的十个单词
def output_result(word_freq): f = open("result.txt", 'a') if word_freq: sorted_word_freq = sorted(word_freq.items(), key=lambda v: v[1], reverse=True) for item in sorted_word_freq[:10]: # 输出 Top 10 的单词 print("<%s>:%d" %(item[0],item[1]),file=f) print("<%s>:%d" % (item[0],item[1])) f.close()
(5)将结果输出到文件中
f = open("result.txt", 'a') ...... print("....",....,file=f) f.close()
在每个函数运行时直接打开result.txt文件,除了第一个读取行数的函数以“w”模式进行覆盖式写入,余下的函数都以“a”模式进行附加式写入
Task2:任务进阶
(1)支持 stop words
1.创建停词表
def stopwordslist(filepath):#从外部读取停词表 stopwords = [line.strip() for line in open(filepath, 'r', encoding='utf-8').readlines()] print("stopwords:",stopwords) return stopwords
2.根据停词表处理缓冲区代码,去除停词表中的单词
def process_stopwords(bvffer,a): if bvffer: # 下面添加处理缓冲区 bvffer代码,统计每个单词的频率,存放在字典word_freq bvffer=bvffer.lower() #大小写转换,将大写字母转化为小写字母 for s in '“”‘’·-!?,.;: $\n\t': bvffer=bvffer.replace(s,' ') #将找出的特殊符替换为空格 for str in a: bvffer = bvffer.replace(' '+str+' ',' ' ) return bvffer
考虑到要与后续的查看高频词组代码拼接,我们决定先不将处理好的代码统计入字典,而保留为单词与空格相间隔的模式,统一格式,方便利用正则表达式查询词组
(2)查看高频短语
def process_higth2(bvffer): #统计两个单词词组 Phrase = [] Phrase_freq = {} words = bvffer.strip().split()#单词分割 for y in range(len(words) - 1): if words[y][-1] in '’“‘!;,.?”' or words[y + 1][0] in '’“‘!;,.?”': # 判断两个单词之间是否有其他符号 continue elif words[y][0] in '’“‘!;,.?”': # 判断第一个单词前是否有符号 words[y] = words[y][1:] elif words[y + 1][-1] in '’“‘!;,.?”': # 判断第二个单词后是否有符号 words[y + 1] = words[y + 1][:len(words[y + 1]) - 1] Phrase.append(words[y] + ' ' + words[y + 1]) # 录入列表Phrase for ph in Phrase: Phrase_freq[ph] = Phrase_freq.get(ph, 0) + 1 # 生成词组字典 return Phrase_freqdef process_higth3(bvffer):#统计三个单词词组 Phrase = [] Phrase_freq1 = {} words = bvffer.strip().split() # 单词分割 for y in range(len(words) - 2): if words[y][-1] in '’“‘!;,.?”' or words[y + 1][0] in '’“‘!;,.?”': continue elif words[y + 1][-1] in '’“‘!;,.?”' or words[y + 2][0] in '’“‘!;,.?”': continue elif words[y][0] in '’“‘!;,.?”': words[y] = words[y][1:] elif words[y + 1][-1] in '’“‘!;,.?”': words[y + 2] = words[y + 2][:len(words[y + 2]) - 1] Phrase.append(words[y] + ' ' + words[y + 1] + ' ' + words[y + 2]) # 录入列表Phrase for ph in Phrase: Phrase_freq1[ph] = Phrase_freq1.get(ph, 0) + 1 # 生成词组字典 return Phrase_freq1
这是与我搭档的陈扬同学负责编写的代码,由于我们的合作方式是,先各自完成相应的功能,再将各功能合并到一起,这就不可避免的导致了代码的兼容性较差。陈扬的这段代码是基于直接对导入的文本信息进行处理,而我一开始的停词功能需要将文本信息进行处理,去除掉标点符号,并且写入字典。结果两段程序产生了冲突,因为进行停词处理的信息并不符合这段代码的要求。后来我想到利用正则表达式来查找高频词组,我们经过讨论,决定将停词功能对文本信息的处理停留于仅仅去除标点并去停词的程度,这恰好能满足此段代码的运行要求,并且也方便进行正则表达式的查找。以下是我写的利用正则表达式查找短语的代码:
def process_words2(bvffer): word_freq={} list = re.findall(r'[a-z]+\s+[a-z]+', bvffer) #正则表达式定义二词短语 for str in list: word_freq[str] = word_freq.get(str, 0) + 1 # 计数 return word_freqdef process_words3(bvffer): word_freq={} list = re.findall(r'[a-z]+\s+[a-z]+\s+[a-z]+', bvffer) #正则表达式定义三词短语 for str in list: word_freq[str] = word_freq.get(str, 0) + 1 # 计数 return word_freq
相较而言,我写的代码较为简洁,但适用范围小,要配合停词功能使用。而陈扬的代码普适性大,可以直接对文本信息进行处理。
2.2程序算法的时间、空间复杂度分析
def process_words2(bvffer): word_freq={} list = re.findall(r'[a-z]+\s+[a-z]+', bvffer) #正则表达式定义二词短语 for str in list: word_freq[str] = word_freq.get(str, 0) + 1 # 计数 return word_freq
以任务2中的查看高频短语为例,在时间复杂度上,主要在于查找定义的短语和for循环,假设文本共有N个单词,由于findall方法为遍历,所以时间复杂度为O(N),若找出的短语共有n条,for循环的时间复杂度为O(n),总的时间复杂度为O(N+n)。空间复杂度考虑到辅助空间的大小,由list和word_freq{}组成,为O(2n)。
2.3程序运行截图:
1.命令行运行代码
2.停词功能
3.查看高频短语
三、性能分析
这是陈扬的代码,虽然功能强大,适应性强,但是需要1.5秒的运行时间
这是调用次数前十,可见process_higth2()和process_higth3()调用次数非常之高
运行时间方面也体现了同样的问题
我的函数则只需0.5秒,快了将近1秒
这是调用前十
这是耗时前十
运行效率大大提高了,但是函数的适应性极差,无法重用于其他程序
四、其他
4.1结对编程时间开销
由于之前没有接触过python,大部分的时间用于学习python的各种函数应用,以及正则表达式,大概用时半个礼拜,查阅资料,一边做,一边学。
4.2结对编程照片
五、事后分析与总结
5.1简述结对编程时,针对某个问题的讨论决策过程。
在实现查看高频短语的功能时,陈扬的代码与我的代码一度产生冲突,停词功能与查看高频短语功能无法统一,导致程序无法执行。后来我们经过讨论,修改了停词功能的过程,来统合两个功能。
5.2评价对方:请评价一下你的合作伙伴,又哪些具体的优点和需要改进的地方。 这个部分两人都要提供自己的看法。
(1)蒋晓明对陈扬的评价:陈扬同学积极主动,十分好学,在我们学习python的时候理解的很快也理解的很好,马上就可以学以致用,和他合作感到很舒服。
(2)陈扬对蒋晓明的评价:蒋晓明同学的编程能力很强,在编程的时候有遇到很多问题,讨论的时候大多是蒋晓明同学提出了比较好的想法。同时蒋小明同学的语言表达能力也很好,很容易能让别人理解自己在想些什么。期待下次和蒋晓明同学的合作。
5.3评价整个过程:关于结对过程的建议
评价:
由于我们两个不在同一个宿舍,平时的作息和活动时间也不尽相同,这就令互相交流产生了困难,于是我们决定以分工合作的方式来完成任务,各自负责程序的一部分功能,最后统筹为一个程序。编写过程遇到困难就一同讨论,这样一来不仅解决了交流问题,还令工作效率大大提高,不必按部就班的编写代码,较大避免了卡壳的现象。当然,这样做也有缺陷,就是在最后统合的时候,可能出现两个函数的逻辑冲突,解决函数之间的冲突花了较大的时间。
建议:
大学的这几年时间里结对编程的项目其实很少,适量的结对编程对于我们来说还是有很大的锻炼的。习惯了自己一个人敲代码,偶尔的结对编程也能锻炼自己的语言表达能力,学会如何向同伴表达出自己的想法,在遇到困难时也能很好地交流,两个人共同解决一个问题终究是比一个人来得快,毕竟三个臭皮匠顶个诸葛亮。
另一方面,将来工作也是几个人共同编程的,提前了解结对编程也是很好的一个适应过程。希望以后还会有小组编程,慢慢像工作的模式靠拢。5.4其它
在平时的学习中我们还是需要多扩展知识的,如果在平时的学习中能提前了解像python这样的常用语言,在真正遇到困难时就不会像这次花大量的时间在学习python上了。编程时间也会缩短很少。