一、基本信息
1.1、编译环境、作者、项目名称
# 编译环境:Pycharm2017、Python3.7 # 项目名称:词频统计——增强功能 # 作者:1613072015:候玉权 # 1613072014:卢杰
1.2本次作业地址
https://edu.cnblogs.com/campus/ntu/Embedded_Application/homework/2088
二、项目分析
Task 1. 接口封装 —— 将基本功能封装成(类或独立模块)
将基本功能:统计文本总词数,统计文本最多的十个单词及其词频这两个方法封装在类countword中
import re
class Countword():
def __init__(self, doc, m, n, o): # 类Countword的构造方法doc:文件路径;m:每个词组长度;n:输出的单词数量;o:设定生成文件的存储路径
self.doc = doc
self.m = m
self.n = n
self.o = o
def process_file(self): # 读取文件
f = open(self.doc, "r")
lines = len(open(self.doc, \'r+\').readlines()) # 借助readlines可以获得文本的行数
bvffer = f.read()
return bvffer, lines
def process_wordNum(self, bvffer):
if bvffer:
bvffer = bvffer.lower() # 将文本中的大写字母转换为小写
for ch in \'{}!"#%()*+-,-.\/:;<=>?&@“”[]^_|\':
bvffer = bvffer.replace(ch, " ") # 将文本中非法字符转化为空格
words = bvffer.split() # 用空格分割字符串
if words:
wn = []
words_select = \'[a-z]{4}(\w)*\'
for i in range(len(words)):
word = re.match(words_select, words[i]) # 如果不匹配,返回NULL类型
if word:
wn.append(word.group())
word_freq = {}
for word in wn: # 将正则匹配的结果进行统计
word_freq[word] = word_freq.get(word, 0) + 1
return wn, word_freq
def process_p(self, bvffer): # 查找m个单词组成的词组
if bvffer:
model = \'\'
for i in range(self.m):
model += \'[a-z]+\'
if i < self.m - 1:
model += \'\s\'
result = re.findall(model, bvffer) # 正则查找词组
word_freq = {}
for word in result: # 将正则匹配的结果进行统计
word_freq[word] = word_freq.get(word, 0) + 1
return word_freq
def output_result(self, word_freq):
if word_freq:
sorted_word_freq = sorted(word_freq.items(), key=lambda v: v[1], reverse=True)
for item in sorted_word_freq[:self.n]: # 输出前n个频率最高的单词
print(\'<\' + str(item[0]) + \'>:\' + str(item[1]))
return sorted_word_freq[:self.n]
def print_result(self):
print(\'查询路径为:\' + str(self.doc) + \'的文本\')
print(\'统计词组长度为:\' + str(self.m) + \'且词频前\' + str(self.n) + \'的单词\')
bvffer, lines = Countword.process_file(self)
lines = \'lines:\' + str(lines)
wn, word_freq = Countword.process_wordNum(self, bvffer)
sw = len(wn)
phrase_freq = Countword.process_p(self, bvffer)
show_words = \'words:\' + str(sw)
print(show_words) # 显示文章单词总数
print(lines) # 显示文章的行数
itemsWord = Countword.output_result(self, word_freq)
itemsPhrase = Countword.output_result(self, phrase_freq)
with open(self.o, \'w+\') as w:
w.write(lines + \'\n\')
w.write(show_words + \'\n\')
# 输出单词
for itemWord in itemsWord:
item = \'<\' + str(itemWord[0]) + \'>:\' + str(itemWord[1]) + \'\n\'
w.write(item)
# 输出词组
for itemPhrase in itemsPhrase:
item = \'<\' + str(itemPhrase[0]) + \'>:\' + str(itemPhrase[1]) + \'\n\'
w.write(item)
print(\'写入\' + self.o + \'文件已完成!\')
w.close()
编写一个测试代码,确定上述的封装类是否正确
import countword
if __name__ == \'__main__\': pr = Countword(\'Gone_with_the_wind.txt\', 2, 10, \'jieguo.txt\') pr.print_result()
Task 2. 增加新功能
词组统计:能统计文件夹中指定长度的词组的词频。
自定义输出:能输出用户指定的前n多的单词与其数量。
看看countword的代码:
import re
class Countword():
def __init__(self, doc, m, n, o): # 类Countword的构造方法doc:文件路径;m:每个词组长度;n:输出的单词数量;o:设定生成文件的存储路径
self.doc = doc
self.m = m
self.n = n
self.o = o
def process_file(self): # 读取文件
f = open(self.doc, "r")
lines = len(open(self.doc, \'r+\').readlines()) # 借助readlines可以获得文本的行数
bvffer = f.read()
return bvffer, lines
def process_wordNum(self, bvffer):
if bvffer:
bvffer = bvffer.lower() # 将文本中的大写字母转换为小写
for ch in \'{}!"#%()*+-,-.\/:;<=>?&@“”[]^_|\':
bvffer = bvffer.replace(ch, " ") # 将文本中非法字符转化为空格
words = bvffer.split() # 用空格分割字符串
if words:
wn = []
words_select = \'[a-z]{4}(\w)*\'
for i in range(len(words)):
word = re.match(words_select, words[i]) # 如果不匹配,返回NULL类型
if word:
wn.append(word.group())
word_freq = {}
for word in wn: # 将正则匹配的结果进行统计
word_freq[word] = word_freq.get(word, 0) + 1
return wn, word_freq
def process_p(self, bvffer): # 查找m个单词组成的词组
if bvffer:
model = \'\'
for i in range(self.m):
model += \'[a-z]+\'
if i < self.m - 1:
model += \'\s\'
result = re.findall(model, bvffer) # 正则查找词组
word_freq = {}
for word in result: # 将正则匹配的结果进行统计
word_freq[word] = word_freq.get(word, 0) + 1
return word_freq
def output_result(self, word_freq):
if word_freq:
sorted_word_freq = sorted(word_freq.items(), key=lambda v: v[1], reverse=True)
for item in sorted_word_freq[:self.n]: # 输出前n个频率最高的单词
print(\'<\' + str(item[0]) + \'>:\' + str(item[1]))
return sorted_word_freq[:self.n]
def print_result(self):
print(\'查询路径为:\' + str(self.doc) + \'的文本\')
print(\'统计词组长度为:\' + str(self.m) + \'且词频前\' + str(self.n) + \'的单词\')
bvffer, lines = Countword.process_file(self)
lines = \'lines:\' + str(lines)
wn, word_freq = Countword.process_wordNum(self, bvffer)
sw = len(wn)
phrase_freq = Countword.process_p(self, bvffer)
show_words = \'words:\' + str(sw)
print(show_words) # 显示文章单词总数
print(lines) # 显示文章的行数
itemsWord = Countword.output_result(self, word_freq)
itemsPhrase = Countword.output_result(self, phrase_freq)
with open(self.o, \'w+\') as w:
w.write(lines + \'\n\')
w.write(show_words + \'\n\')
# 输出单词
for itemWord in itemsWord:
item = \'<\' + str(itemWord[0]) + \'>:\' + str(itemWord[1]) + \'\n\'
w.write(item)
# 输出词组
for itemPhrase in itemsPhrase:
item = \'<\' + str(itemPhrase[0]) + \'>:\' + str(itemPhrase[1]) + \'\n\'
w.write(item)
print(\'写入\' + self.o + \'文件已完成!\')
w.close()
if __name__ == \'__main__\':
pr = Countword(\'Gone_with_the_wind.txt\', 2, 10, \'jieguo.txt\')
pr.print_result()
测试代码:
import WordCount
import argparse
import cProfile
import pstats
def main():
parser = argparse.ArgumentParser(description="your script description") # description参数可以用于插入描述脚本用途的信息,可以为空
parser.add_argument(\'--i\', \'-i\', type=str, default=\'Gone_with_the_wind.txt\', help="读取文件路径")
parser.add_argument(\'--m\', \'-m\', type=int, default=3, help="输出的单个词组数量")
parser.add_argument(\'--n\', \'-n\', type=int, default=4, help="输出的频率前n个的单词和词组数量")
parser.add_argument(\'--o\', \'-o\', type=str, default=\'result.txt\', help="读取文件路径")
args = parser.parse_args() # 将变量以键-值的字典形式存入args字典
doc = args.i
m = args.m
n = args.n
o = args.o
pr =WordCount.WordCount(doc, m, n, o)
pr.print_result()
if __name__ == \'__main__\':
cProfile.run("main()", "pstats_result")
# 把分析结果保存到文件中,不过内容可读性差...需要调用pstats模块分析结果
p = pstats.Stats("pstats_result") # 创建Stats对象
p.strip_dirs().sort_stats("call").print_stats() # 按照调用的次数排序
p.strip_dirs().sort_stats("cumulative").print_stats() # 按执行时间次数排序
下面是部分截图:
三、性能分析
根据调用次数分析
根据调用时间分析
性能分析:
四、PSP 表格
五、事后分析与总结
1.传递参数有三种方法:1、参数通过sys.argv传递,它的类型是一个list类型,其中的元素为字符串。2、通过getopt模块解析Python传入的参数,它能解析带\'-\'和\'--\'格式的参数。它的函数原型为:getopt.getopt(args, options[, long_options])。3、使用argparse模块解析命令行参数。通过我和谭琪的讨论,我们选择了argparse模块来传参,因为argparse是一个可以自动生成帮助信息和错误信息的模块,有利于命令行传参的调试分析。
2.评价 (1)卢杰评价侯玉权:侯玉权同学学习能力强、对于不熟悉的方法上手很快。而且他做事认真且有条理、但是严谨性需加强。提出 使用nltk中的方法,思考角度为“不重复造轮子”,并且该工具包已经发展成熟,
在使用过程中并不会产生程序问题。美中不足的是对编写程序背后的逻辑方面,不够严谨,希望以后能够多加思考。 (2)侯玉权评价卢杰:卢杰同学思维活跃、常常想出好的方法。不过他的基础代码能力欠缺,需要继续努力。使用正则表达式,针对2个词汇的短语,与3个词汇的短语编写正则表达式,从文本中找出
符合要求的短语集合之后,进行短语统计(类似词频统计)。在完成任务的同时,积极帮助我解答疑问,受益匪浅,期待下一次的合作。
3.关于结对过程的建议 (1)可以以自由结对编程的形式开展,同学自主寻找的结对伙伴彼此比较熟悉能够更有效率地开展结对编程工作;当然,不太熟悉的人结对编程也有一定好处,如可以锻炼个人的与他人交流沟通、相处之道。
4.其他 “三人行必有我师”,相互学习对方的技能,可以提升自己水平。工作及时得到同伴的肯定,自信心和成就感会增强,觉得工作很愉快,很愿意很partner一起工作,这样就会提高生产率。在编程中,相互讨论,可能更快更有效地解决问题。
5、结对照片