2019年2月25日 星期一

深度學習 - LSTM生成文本 - 唐詩 - 文本預處理

深度學習 - LSTM生成文本 - 唐詩 - 文本預處理

經過LSTM 生成文本練習過後,我就想來實踐一下李宏毅老師在上課時曾說過,有研究生演示過 LSTM 生成唐詩,還蠻有趣的!!
於是上網找了一下,已經有人發布至 Github 了,我們拿來練習一下吧!!
首先下載文本全唐诗.txt ,我個人不喜歡簡中,我寫了個翻譯程式(用Colab實現),把文本丟進根目錄後,就可以翻譯成繁體中文文檔,下載來用。
先來看一下文本樣貌:
其中包含了 主標題"全唐詩 捲一" 與 子標題"捲1_1【帝京篇十首】李世民"

目標 : 我們要將每首詩存成list

思路 : 將標題去掉,且每首詩皆被空行包覆,所以只要逐行讀取一首詩到空格時跳到下一首詩。

如何將標題去掉!? 以下代碼練習將過程紀錄:
先將文件逐行讀取。
with open(poetry_file, "r" ,encoding="utf-8") as f: for i in range(0, 3): line = f.readline() print(line,end="") print(len(line))
全唐詩 捲一
8

1
  捲1_1【帝京篇十首】李世民
17
第一行為何是8? google 了一下 “python3 編碼轉換” 使用 json 可以幫助我們了解,修改程式碼如下:
import json with open(poetry_file, "r" ,encoding="utf-8") as f: for i in range(0, 3): line = f.readline() u = json.dumps(line) print(u) print(line,end="") print(len(line))
"\ufeff\u5168\u5510\u8a69 \u6372\u4e00\n"
全唐詩 捲一
8
"\n"

1
"\u3000\u3000\u63721_1\u3010\u5e1d\u4eac\u7bc7\u5341\u9996\u3011\u674e\u4e16\u6c11\n"
  捲1_1【帝京篇十首】李世民
17
可以從輸出觀察到,空格" “& 換行”\n" 都算一個list的元素。
大概了解之後的第一件事,我們要去除主標題,但是主標題到底多長? 隨便找個最長的看看print出來看看
print(len("全唐詩 捲八百四十三"))
10
import json x= u'】' u= json.dumps(x) print(u)
"\u3011"
子標題呢!? 我們可以看到子標題皆含有"【","】" 特殊符號,從剛剛透過 json 印出來可以知道這兩個特殊符號是 “\u3010” & “\u3011”,所以在逐行讀取時,只要找到這兩個符號,就可以跳過。
利用正則表達示來尋找"\u3010" & “\u3011” ,用以下程式碼 test 看看,逐行讀取,如果有找到特殊符號就 print : “True”。
import re with open(poetry_file, "r" ,encoding="utf-8") as f: for i in range(0, 5): line = f.readline() if re.search(u'\u3010', line): print("True",line) else : print('Flase',line)
Flase 全唐詩 捲一
Flase 
True   捲1_1【帝京篇十首】李世民
Flase 
Flase 秦川雄帝宅,函榖壯皇居。綺殿韆尋起,離宮百雉?。
知道這些特殊符號,可以利用正則表達式 Regular expression operations來清理文本資料,也可以說利用正則表達式抓出我們要的資料,可參考regex教學
在了解文檔內容要如何清理後,我們將文本資料建立list。
以下是清理文本的代碼,也是參考原著再修改。
# *-* coding:utf-8 *-* poetry = [] #用來存詩的list old_line = '' #判斷該行是空行還是詩。 import re with open(poetry_file, "r" ,encoding="utf-8") as f: while 1: line = f.readline() #跳過主標題&子標題,遇到空行時重置old_line if len(line)<2 or"全唐詩"in line or":" in line or "【"in line: old_line = '' #逐行詩丟進list中 elif old_line == '': if "-" in line: #將有些詩後面會用 "--"備註詩人,將取其前面。 line = line.split("-")[0] if "□" in line: #將有□過濾掉,這是翻譯後產生的... line = re.sub('□',"",line) if "?" in line: line = line.replace("?","") #翻譯後有些"?",刪掉。 if re.search('[a-zA-Z0-9]',line): #有些詩的開頭會有英文!? 刪掉。 line = re.sub('[a-zA-Z0-9]',"",line) poetry.append(line[0:-1]) #將該行丟進list中 old_line = line #下一行還是同一首詩的line,加到同一個list中,表同一首詩。 else: if "-" in line: line = line.split("-")[0] if "□" in line: line = re.sub('□',"",line) if "?" in line: line = line.replace("?","") if re.search('[a-zA-Z0-9]',line): line = re.sub('[a-zA-Z0-9]',"",line) poetry[-1] = poetry[-1]+line[0:-1] old_line = line if not line: break #最後將文章內有()註解都刪掉 i=0 for poem in poetry: if "(" and ")" in poem: poem = poem.split("(")[0] + poem.split(")")[1] poetry[i] = poem i = i + 1 #有些遺留單個誇號註解(少量),整行刪掉 final_poetry = poetry.copy() j = 0 for poem in poetry: if "(" in poem or ")" in poem: final_poetry.pop(j) j = j-1 j = j+1
看看剩下多少詩可以訓練
print('poetry :',len(poetry)) print('final_poetry :',len(final_poetry))
poetry : 48209
final_poetry : 48125
還有剩下48125 首詩,夠我們訓練模型。
最後將 final_poetry 輸出存檔。
pre_process_poetry_file = os.path.join(data_dir, 'pre_process_poetry.txt') with open(pre_process_poetry_file, "w",encoding="utf-8") as w: for i in final_poetry : w.write(i+"\n")
呼…接下來就是將文字轉換成向量了。

沒有留言:

張貼留言