軟工作業2-詞頻統計

来源:https://www.cnblogs.com/wsywsy123/archive/2019/04/14/10707947.html
-Advertisement-
Play Games

軟工作業2 ——實現一個能夠對文本文件中的單詞的詞頻進行統計的控制台程式 1.Github地址: https://github.com/wangshiyaoyao/WordCont 2.PSP表格 PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際 ...


軟工作業2

                                                                                ——實現一個能夠對文本文件中的單詞的詞頻進行統計的控制台程式

1.Github地址:

https://github.com/wangshiyaoyao/WordCont

2.PSP表格

PSP2.1

Personal Software Process Stages

預估耗時(分鐘)

實際耗時(分鐘)

Planning

計劃

   

· Estimate

· 估計這個任務需要多少時間

   

Development

開發

   

· Analysis

· 需求分析 (包括學習新技術)

120

360

· Design Spec

· 生成設計文檔

30

30

· Design Review

· 設計覆審

10

10

· Coding Standard

· 代碼規範 (為目前的開發制定合適的規範)

20

20

· Design

· 具體設計

30

30

· Coding

· 具體編碼

120

120

· Code Review

· 代碼覆審

20

40

· Test

· 測試(自我測試,修改代碼,提交修改)

120

300

Reporting

報告

   

· Test Repor

· 測試報告

60

60

· Size Measurement

· 計算工作量

30

30

· Postmortem & Process Improvement Plan

· 事後總結, 並提出過程改進計劃

30

30

 

合計

590

1030

 

3.需求分析

    實現一個能夠對文本文件中的單詞的詞頻進行統計的控制台程式

       功能實現:

       讀取文件

              獲取文件名

              判斷獲取參數是否正確

              判斷文件是否可讀取,否則報錯處理

       根據文件內容進行分析處理

              統計字元個數

              統計有效行數

              統計詞頻

                     詞頻排序,獲取前十

              統計單詞數

       輸出結果

測試用例:

       創建臨時文件

根據一定規則隨機生成內容

記錄生成內容的有效單詞等各種你參數

                     功能測試

              測試統計字元個數

              測試統計有效行數

              測試統計詞頻

              測試統計單詞數

難點:

       單詞匹配,使用正則表達式,學習其語法

       測試套件的使用

       隨機生成文件內容

代碼規範:

       使用python3.7+ pycharm

       單函數單功能

       添加註釋,提高代碼可讀性

       代碼符合pep8規範,使用pylint進行檢查

       使用Profile進行性能檢測

4.代碼設計

   Get_argv函數:獲取並返回程式執行第一個參數,進行參數個數校驗,有誤返回空字元串,

   Main函數:接受一個文件名字元串,輸出分析結果,無返回

        創建文件分析實例,進行分析,獲取輸出結果,進行輸出

   _file_check函數:文件名檢查,若不能打開並讀取,進行報錯,程式異常退出

   FileHandler類:

       __init__:初始化用於保存結果的各類變數,接受文件名,調用函數進行檢查,調用分析函數進行分析

       _analysis:打開文件,讀取內容,對讀取內容調用歐冠具體函數進行分析,最後對詞頻排序

       _chars_analysis:字元統計,使用len函數

       _line_analysis:有效行統計,使用strip函數判斷有效行

       _word_analysis:詞頻統計,調用單詞檢查函數獲取合法單詞,使用lower函數統一為小寫

       _word_sum:單詞數統計,調用單詞檢查函數獲取合法單詞

       _sort_conatiner:詞頻結果排序,取前十結果

       介面函數:

       chars:獲取字元統計結果

       cotainer:獲取詞頻前10統計結果

   lines:獲取有效行統計結果

   words:獲取單詞數目統計結果

   _word_check_in_line:函數:獲取字元串中合法單詞,使用正則表達式匹配

 

   單元測試:

       創建臨時文件

     根據一定規則隨機生成內容

    記錄生成內容的有效單詞等各種你參數

       通過正則表達式反向匹配生成任意符合測試要求的內容,文件大小可控,覆蓋較全面。

                     功能測試

              測試統計字元個數

              測試統計有效行數

              測試統計詞頻

              測試統計單詞數

5.關鍵功能實現

文件檢查:

1 def _file_check(filename):
2     """判斷參數是一個可讀文件,否則報錯"""
3     try:
4         fd = open(filename)
5         fd.close()
6     except IOError:
7         logging.error("Invalid argument.\nNeed a readable file.")
8         sys.exit(1)

 

對文件進行嘗試可讀打開,失敗進行報錯,並異常退出

類初始化:

def __init__(self, filename, encoding='utf-8'):
    self._chars = 0                                               # 統計ascii
    self._container = {}                                          # 統計詞頻
    self._lines = 0                                               # 統計行數
    self._words = 0                                               # 統計單詞數
    self._sorted_container = []                                   # 輸出詞頻
    _file_check(filename)
    self._analysis(filename, encoding)

 

使用字典進行詞頻統計,避免重覆

文件預設使用utf-8打開

詞頻統計:

1 def _word_analysis(self, line):
2     """統計詞頻"""
3     for word_match in _word_check_in_line(line):
4         word = word_match.lower()
5         self._container[word] = self._container.get(word, 0) + 1

 

使用字典的get函數對初次添加做特殊初始化

合法單詞檢查:

1 def _word_check_in_line(line):
2     """單詞匹配"""
3     pattern = r'(?<![a-zA-Z0-9])([a-zA-Z][0-9a-zA-Z]*)'
4     result = re.findall(pattern, line)
5     # logging.debug('word check in line result:%s', result)
6     return result

 

       使用正則進行檢查

       匹配字元開頭後跟任意長度字元或數字,單詞前一字元不為字母數字

       使用findall函數獲取所有合法單詞,以列表存儲

 

詞頻結果處理:

1 def _sort_container(self):
2     """詞頻結果排序,獲取前10結果"""
3     self._sorted_container = sorted(self._container.items(), key=lambda x: (-x[1], x[0]))[:10]

 

       使用sorted函數對字典進行排序

    參數:key=lambda x: (-x[1], x[0])

           表示排序依據,先根據字典值大->小排序,後根據字典鍵按字典序排序

           [:10]:表示取前十個結果

 

生成用於測試的臨時文件:

 1 def touch_test_file(line_num, word_num):
 2     """創建測試文件,隨機生成字元,用於測試"""
 3 
 4     _x = Xeger()
 5     words = lambda: _x.xeger(r'[a-zA-Z][a-zA-Z0-9]*')       # 隨機生成有效單詞
 6     non_word = lambda: _x.xeger(r'\d[a-zA-Z0-9]*')          # 隨機生成開頭為數字的單詞
 7     separator = lambda: _x.xeger(r'[^a-zA-Z0-9\n\r]')       # 隨機生成非字母數字回車換行符的字元
 8     space = lambda: _x.xeger(r'\n[\s]*\n')                  # 隨機生成回車空白字元回車
 9 
10     # 統計生成的文件中字元、單詞、有效行、詞頻
11     result = {'chars': 0, 'words': word_num * line_num, 'lines': line_num, 'container': {}}
12 
13     # 創建文件,隨機生成字元
14     fd = open(temp_file, 'w')
15     for line in range(line_num):
16         for i in range(word_num):
17             word = words()
18             chars = word + separator() + non_word() + separator()
19             result['chars'] += len(chars)
20             result['container'][word.lower()] = result['container'].get(word.lower(), 0) + 1
21             fd.write(chars)
22         chars = space()
23         result['chars'] += len(chars)
24         fd.write(chars)
25     fd.close()
26 
27     # 獲取排序後的詞頻結果
28     sort_result = sorted(result['container'].items(), key=lambda x: (-x[1], x[0]))[:10]
29     result['container'] = sort_result
30     return result

使用第三方庫xeger,反向生成符合正則的任意字元串

創建好要生成的合法非法單詞,字元,空白字元等

創建臨時文件,隨機生成字元串寫入

將結果返回

6.代碼風格說明

  Unused variable 'line' (unused-variable):未使用的參數:for迴圈中,使用_代替

  Trailing newlines (trailing-newlines):文件末尾多餘空行,刪除

7.運行結果

 

測試運行:

 

8.性能分析結果及改進

使用cProfile

         182480 function calls (182313 primitive calls) in 0.207 seconds

 

   Ordered by: internal time

 

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)

     7382    0.057    0.000    0.057    0.000 {method 'findall' of 're.Pattern' objects}

        1    0.049    0.049    0.057    0.057 {built-in method builtins.sorted}

     3691    0.025    0.000    0.074    0.000 WordCont.py:64(_word_analysis)

        1    0.010    0.010    0.190    0.190 WordCont.py:74(_analysis)

    40049    0.008    0.000    0.008    0.000 {method 'get' of 'dict' objects}

    33382    0.008    0.000    0.008    0.000 WordCont.py:87(<lambda>)

    40006    0.006    0.000    0.006    0.000 {method 'lower' of 'str' objects}

     7385    0.005    0.000    0.010    0.000 re.py:271(_compile)

       13    0.004    0.000    0.004    0.000 {built-in method builtins.print}

     7382    0.004    0.000    0.068    0.000 re.py:215(findall)

     3691    0.004    0.000    0.040    0.000 WordCont.py:70(_word_sum)

     7382    0.004    0.000    0.072    0.000 WordCont.py:25(_word_check_in_line)

 

        1    0.003    0.003    0.060    0.060 WordCont.py:85(_sort_container)

     7681    0.002    0.000    0.002    0.000 {built-in method builtins.isinstance}

     3691    0.002    0.000    0.003    0.000 WordCont.py:59(_line_analysis)

       57    0.002    0.000    0.002    0.000 {built-in method nt.stat}

     3691    0.002    0.000    0.002    0.000 WordCont.py:55(_chars_analysis)

       10    0.002    0.000    0.002    0.000 {built-in method marshal.loads}

     3691    0.001    0.000    0.001    0.000 {method 'strip' of 'str' objects}

       10    0.001    0.000    0.001    0.000 {method 'read' of '_io.FileIO' objects}

7762/7732    0.001    0.000    0.001    0.000 {built-in method builtins.len}

       45    0.001    0.000    0.002    0.000 {built-in method builtins.__build_class__}

        1    0.001    0.001    0.207    0.207 WordCont.py:8(<module>)

           19/4    0.001    0.000    0.002    0.000 sre_parse.py:475(_parse)

…… …… ……

       Findall函數耗時最多,sorted其次,內建函數暫無法優化。

 

按執行次數分析:

         182480 function calls (182313 primitive calls) in 0.216 seconds

 

   Ordered by: call count

 

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)

    40049    0.009    0.000    0.009    0.000 {method 'get' of 'dict' objects}

    40006    0.006    0.000    0.006    0.000 {method 'lower' of 'str' objects}

    33382    0.008    0.000    0.008    0.000 WordCont.py:87(<lambda>)

7762/7732    0.001    0.000    0.001    0.000 {built-in method builtins.len}

     7681    0.003    0.000    0.003    0.000 {built-in method builtins.isinstance}

     7385    0.006    0.000    0.011    0.000 re.py:271(_compile)

     7382    0.004    0.000    0.076    0.000 WordCont.py:25(_word_check_in_line)

 

     7382    0.004    0.000    0.072    0.000 re.py:215(findall)

     7382    0.058    0.000    0.058    0.000 {method 'findall' of 're.Pattern' objects}

     3691    0.002    0.000    0.003    0.000 WordCont.py:55(_chars_analysis)

     3691    0.002    0.000    0.003    0.000 WordCont.py:59(_line_analysis)

     3691    0.025    0.000    0.078    0.000 WordCont.py:64(_word_analysis)

     3691    0.004    0.000    0.042    0.000 WordCont.py:70(_word_sum)

     3691    0.001    0.000    0.001    0.000 {method 'strip' of 'str' objects}

      411    0.000    0.000    0.000    0.000 sre_parse.py:233(__next)

       執行次數最多代碼:get函數,lower函數

 

按函數運行時間分析:

         182480 function calls (182313 primitive calls) in 0.201 seconds

 

   Ordered by: cumulative time

 

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)

     12/1    0.000    0.000    0.201    0.201 {built-in method builtins.exec}

        1    0.001    0.001    0.201    0.201 WordCont.py:8(<module>)

        1    0.000    0.000    0.190    0.190 WordCont.py:115(main)

        1    0.000    0.000    0.188    0.188 WordCont.py:46(__init__)

        1    0.010    0.010    0.187    0.187 WordCont.py:74(_analysis)

     3691    0.023    0.000    0.073    0.000 WordCont.py:64(_word_analysis)

     7382    0.004    0.000    0.070    0.000 WordCont.py:25(_word_check_in_line)

 

     7382    0.004    0.000    0.066    0.000 re.py:215(findall)

        1    0.003    0.003    0.060    0.060 WordCont.py:85(_sort_container)

        1    0.050    0.050    0.057    0.057 {built-in method builtins.sorted}

     7382    0.055    0.000    0.055    0.000 {method 'findall' of 're.Pattern' objects}

     3691    0.004    0.000    0.039    0.000 WordCont.py:70(_word_sum)

     14/3    0.000    0.000    0.012    0.004 <frozen importlib._bootstrap>:978(_find_and_load)

     14/3    0.000    0.000    0.011    0.004 <frozen importlib._bootstrap>:948(_find_and_load_unlocked)

     14/3    0.000    0.000    0.011    0.004 <frozen importlib._bootstrap>:663(_load_unlocked)

     10/3    0.000    0.000    0.010    0.003 <frozen importlib._bootstrap_external>:722(exec_module)

     18/3    0.000    0.000    0.010    0.003 <frozen importlib._bootstrap>:211(_call_with_frames_removed)

     7385    0.005    0.000    0.009    0.000 re.py:271(_compile)

       運行時間最多函數main函數,__init__初始化函數。

附:

ncalls:表示函數調用的次數;
tottime:表示指定函數的總的運行時間,除掉函數中調用子函數的運行時間;
percall:(第一個percall)等於 tottime/ncalls;
cumtime:表示該函數及其所有子函數的調用運行的時間,即函數開始調用到返回的時間;
percall:(第二個percall)即函數運行一次的平均時間,等於 cumtime/ncalls;
filename:lineno(function):每個函數調用的具體信息;

性能分析圖:

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 9、REINDEX API Reindex要求為源索引中的所有文檔啟用_source。 不會配置目標索引,不會複製源索引的設置。你需要在reindex之前先指定 ,分片數量,副本數量等選項。 最常用的一種方式是複製一個索引。下例會將twitter索引中的文檔複製到new_twitter索引中: 返回 ...
  • 我們今天繼續學習一下Numpy庫 接著前面幾次講的,Numpy中還有一些標準運算 exp表示求e的冪次方,比如上面看到的,e的0次方為1,e的2次方,2.7幾,以此類推 我們可以看到,exp就是求e的多少次方 而sqrt則表示根號,也就是進行開方運算 我們可以得到,0的開方為0,1 的開方為1,2的 ...
  • 靜態語言(C/C++、Java);腳本語言(python、JavaScript、PHP) IPO(Input、Process、Output) #:python中的註釋符號;‘’‘ ’‘’:多行註釋 python的35個保留字 數據類型:字元串、整數、浮點數、列表 整數類型:10011101 字元串類 ...
  • 上次使用了BeautifulSoup庫爬取電影排行榜,爬取相對來說有點麻煩,爬取的速度也較慢。本次使用的lxml庫,我個人是最喜歡的,爬取的語法很簡單,爬取速度也快。 本次爬取的豆瓣書籍排行榜的首頁地址是: https://www.douban.com/doulist/1264675/?start= ...
  • 新聞 "Hedgehog新站點" "Bolero 0.4發佈,增加遠程認證" "FsToolkit.ErrorHandling與Cvdm.ErrorHandling合併了" "F 里的3D圖形編程與游戲開發" "有趣的3D——瀏覽器里F 3D繪製" "F CNTK:變分自動編碼器例子——從2D隱空間 ...
  • 閱讀目錄 一、迭代器 1、迭代的概念 #迭代器即迭代的工具,那什麼是迭代呢? #迭代是一個重覆的過程,每次重覆即一次迭代,並且每次迭代的結果都是下一次迭代的初始值 代碼如下: 2、為何要用迭代器?什麼是可迭代對象?什麼是迭代器對象? 3、迭代器對象的使用 4、for迴圈 5、迭代器的優缺點 ...
  • 8、Bulk API 可以把多個 或`delete bulk API`中執行。這樣可以極大地提高索引速度。 API使用如下的JSON結構: 註意,最後一行數據必須要以 結尾。發送請求時,Content Type 標頭應設置為 application /x ndjson。 可以是 ,`create d ...
  • 一、引言 有了自動配置,springboot使web開發變得簡單,這個在springboot之旅中的第一篇中就有體現,實際的開發中當然不會這麼簡單,很多時候我們都需要自己去定製一些東西。web開發的東西比較多, 我們先掌握一些必要知識點,剩下的就是CRUD開發。 快速的創建一個springboot ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...