用 Python 挖掘事故報告中的死亡人數#
今天用 Python 寫一個函數,用來識別土木行業事故報告中的死亡人數。我的設計思路如下:
- 經過觀察,80% 的事故報告中有關死亡人數的記錄是有規律的,即「XX 人死亡」,其中 XX 可能是漢語數字也可能是阿拉伯數字。
- 於是我設計出一個正則表達式,
pattern_death = r'([\d\w]+)(人死亡|名工人死亡)'
用以識別出這種模式。 - 對安徽省的幾份調查報告的測試中,我發現這種識別模式會將「XX 人死亡」之前的文字也提取出來,比如「該工程有 5 人死亡」,直到遇到標點符號,因為
([\d\w]+)
的含義是提取任意數量的漢字或數字。 - 於是我又設計出第二個正則表達式,
pattern_death_num = r'(\d+|[零一二兩三四五六七八九十百千萬]+)(人死亡|名工人死亡)'
,用以識別出上一種模式識別出的句子中的數字(無論是中文還是阿拉伯的)。 - 之後我又下載一個第三方庫 cn2an ,將中文數字轉換為數學數字。
- 將識別到的數字存放到字典中,沒有識別到數字但文本中識別出「死亡」的做標記「待確認」。
雖然我在這裡描述的似乎很輕鬆,但是你無法知道的是,我從最開始的起點走到這個目的地用了多久,以及為了識別條件、避免報錯、存放識別出的數據等而為函數設計的邏輯化了多久時間。
在報了許多次錯誤、迭代了多次之後,這個程序基本上能運行起來了,這個思路已經可以從 393 個事故報告中提取 393-56 份 死亡人數了。
你可能會好奇,圖上顯示的分明是 57 份文件「待確認」,那麼已提取到數據的數量不應該是 383-57 嗎?
沒錯,這缺少的一份就是今天我要談論的主角。
一字之差的工作量#
這一份數據一直在報錯,我不得不在每個省份的文件之間依次測試,找出有問題的文件。
我發現出錯的原因是:程序的確識別出了「X 人死亡」,並且將「X」提取了出來,但報錯的那份文件用的不是「二人死亡」,而是是「兩人死亡」。cn2an 這個專門將表示數字的中文轉化為阿拉伯數字的庫,它只能識別「二」,無法識別「兩」。
於是我又要設計出一個新的邏輯語句,如果識別出了「兩」,就將它改為「二」,然後再用 cn2an
將其轉化為阿拉伯數字。
我找到這個導致錯誤的原因並寫出解決問題的語句,花了近半個小時。僅僅是一個字的偏差,為了使程序能夠適應這種情況,卻需要大量的測試。
我並非一個計算機專業的學生,我比較好奇的是,也許「大量時間花費在解決報錯上」就是軟件開發的常態?
言歸正傳,這是我們提取數據中很簡單的一步,為了適配所有可能性,它的工作量並不小。
如果是從文本中提取「事故性質」這樣的數據,也許描述「事故性質」的方式有多種多樣(暫時我們不確定),不過它一定比數字要複雜,並且上下文可能沒有特殊的格式,如果真是這樣,單憑正則表達式可能已經無法完成目的了。
如果正則表達式無法解決這個問題,根據我目前掌握的信息來看,我們就需要複雜的 NLP 技術去識別出命名實體的詞語、語義邏輯關係等,讓機器理解句子,再將事故原因做分類。而這套規則,需要預設已知的數據庫使代碼能夠理解。
如果我們真的使用 NLP 技術去提取所有事故報告中的「事故原因」,那麼為了做出一個適配所有情況的程序,其工作量一定非常大。
為什麼這麼費勁#
我們之所以在提取數據時這麼費勁,是什麼原因呢?
答案顯而易見,事故報告中大部分信息的記錄方式都沒有統一的格式,如果格式能夠統一,如果每個事故報告中都有一個統一的清單,那麼每一種數據只需要一個正則表達式就能夠提取出來了,並且對所有文件適配。
只可惜,在事故報告的格式上,沒有像秦始皇統一六國的偉大節點。
現在 ChatGPT-4 應該可以自動提取出你所需的數據,只是需要充錢。而我們老師想讓我們做一個自動識別的程序,只能說有點難,哈哈。
秦始皇統一六國#
秦始皇建立了中國歷史上第一個統一的中央集權的封建國家,他不僅僅同意了中國,更重要的是他使書同文、車同軌、行同輪,統一文字、貨幣。
這些統一,不僅有利於信息的傳遞、規格的統一,也有助於我們中華文化的傳承和發揚。
今天在寫代碼中遇到了這個「兩」字引起的報錯,以及對提取「事故性質」的工作量的思考,是否可以說明 ——統一的標準能在無形中解決許多問題呢?
我認為答案是肯定的。