|
@@ -0,0 +1,261 @@
|
|
|
|
+# coding: utf-8
|
|
|
|
+"""
|
|
|
|
+Rewritten from Github
|
|
|
|
+"""
|
|
|
|
+import jieba
|
|
|
|
+import matplotlib.pyplot as plt
|
|
|
|
+import numpy as np
|
|
|
|
+import random
|
|
|
|
+from PIL import Image
|
|
|
|
+from wordcloud import WordCloud
|
|
|
|
+from scipy.ndimage import gaussian_gradient_magnitude
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# Load
|
|
|
|
+text = """
|
|
|
|
+在我的筆電鍵盤上,F11 和 F12 一直都是調整螢幕亮度的快捷鍵,就像下面這張圖片一樣:
|
|
|
|
+不過這個圖示好看歸好看,但是在我的筆電上從來都沒辦法用他們來調整螢幕亮度 (正常的 F11、F12 功能還是可以用)。為了保險起見,我還使用 xev 測試看看有沒有抓到 Keycode,不過自然是抓得到的。
|
|
|
|
+今天想要紀錄的就是,我如何將這兩個按鍵設置為調整螢幕亮度的快捷鍵,搞不好會有一樣問題的人可以參考看看。
|
|
|
|
+在我的系統上,我的亮度設定是位於 “/sys/class/backlight/intel_backlight/” 這個路徑底下。你的路徑可能與我不同,不過大致上都會在 “/sys/class/backlight/” 底下。
|
|
|
|
+其中,max_brightness 是我系統上可以設定的亮度最大值,為 120000;brightness 則是我系統當前設定的值,只要更動這個檔案內的數值,我電腦螢幕的亮度也會隨之改變。
|
|
|
|
+所以要做的第一件事情,就是將 brightness 這份檔案設定權限,讓我可以在一般模式時就能寫入它。
|
|
|
|
+若是我要減少亮度,我可以使用以下指令:
|
|
|
|
+若是我要提昇亮度,則就將 “-” 換成 “+” 即可。
|
|
|
|
+確認這兩個指令沒有問題,就可以將其設定為快捷鍵了。
|
|
|
|
+其實設定快捷鍵也是相當簡單,在此我簡單做個示範、不過大部份桌面環境設定快捷鍵的方式都大同小異。
|
|
|
|
+基本上,搜尋 “Shortcut”,應該就能直接找到設定快捷鍵的地方。
|
|
|
|
+設定快捷鍵有三個參數要填入: Name、Command、Shortcut。
|
|
|
|
+Name: 無所謂,填入喜歡的名稱即可
|
|
|
|
+Command: 填入上方調整螢幕亮度的指令
|
|
|
|
+Shortcut: 按下你想要的快捷鍵,以我這裡為例便是 F11、F12
|
|
|
|
+完成設置後,我就能成功假裝我的按鍵是正常可以用的了 XDD
|
|
|
|
+在 Python 中,我們若是想要將一段文本依照『特定字元』來切割,讓文本變成一段段的 List 資料型態儲存著,我們可以簡單地使用 split() 這個函式來完成。
|
|
|
|
+而 splitlines() 這個函式與 split() 非常相像,不過 splitlines() 是專門處理換行符號的,並且在處理時還能選擇是否保留著換行符號,非常好用。
|
|
|
|
+假設我們有著以下這樣的文本:
|
|
|
|
+假設我們想要以空格符號 ” ” 為切割點,我們得到的結果應如下:
|
|
|
|
+for word in text.split():
|
|
|
|
+ print(word)
|
|
|
|
+Output:
|
|
|
|
+除了預設的以『空格符號』切割外,我們也可以自己選擇換行符號 “\n” 來進行切割。
|
|
|
|
+Today is a nice day.
|
|
|
|
+This is a good day.
|
|
|
|
+Hello! How are you?
|
|
|
|
+不過在以換行符號 “\n” 切割的時候,split() 是沒有比 splitlines() 方便的,以下我們就來看看 splitlines() 的範例。
|
|
|
|
+splitlines() 比 split() 優秀的地方在於,我們的文本中很有可能並不僅僅只存在著 “\n” 這樣單純的換行, “\r”、”\r\n”、”\n” 等等也都會被視作換行。
|
|
|
|
+根據我的經驗,同時考慮 “\r”、”\r\n”、”\n” 三種情況的切割點效果比較好,畢竟不會出現應該換行卻沒有被切割的句子。
|
|
|
|
+同時,splitlines() 還可以透過 keepends 參數決定是否在輸出結果中保留『換行符號』,在某些情況是非常有用的。
|
|
|
|
+'\n'
|
|
|
|
+'Today is a nice day.\n'
|
|
|
|
+'This is a good day.\n'
|
|
|
|
+'Hello! How are you?\n'
|
|
|
|
+這裡我使用了 pprint 來顯示換行符號。值得一提的是 keepends 若為 True 表示保留換行符號;反之,則不保留。
|
|
|
|
+使用 FastText 訓練詞向量
|
|
|
|
+FastText 是由 Facebook AI Research Lab (FAIR) 所開發的『詞嵌入』以及『文本分類』,支援 294 種語言,並且使用類神經網路訓練詞嵌入模型。
|
|
|
|
+基本上 FastText 的演算法是基於以下這兩篇論文:
|
|
|
|
+Enriching Word Vectors with Subword Information
|
|
|
|
+Bag of Tricks for Efficient Text Classification
|
|
|
|
+不過介紹了這麼多,今天我主要的目的是要介紹如何在 Python 中透過 Gensim 套件快速地調用 FastText 訓練一個 Word Embedding 的模型。基本上流程都與 Gensim 中本來訓練 Word2Vec 極度相像。
|
|
|
|
+以下就直接來看程式碼。值得一提的是,由於我之前寫過使用 Gensim 訓練 Word2Vec 模型,所以有部份相同的流程我是直接從那邊抄來的 XDD
|
|
|
|
+安裝 Gensim
|
|
|
|
+首先,如果你的環境裡沒有 Gensim,使用以下指令安裝:
|
|
|
|
+pip3 install gensim
|
|
|
|
+Python is the most popular programming language!
|
|
|
|
+前言
|
|
|
|
+FastText 是由 Facebook AI Research Lab (FAIR) 所開發的『詞嵌入』以及『文本分類』,支援 294 種語言,並且使用類神經網路訓練詞嵌入模型。
|
|
|
|
+基本上 FastText 的演算法是基於以下這兩篇論文:
|
|
|
|
+Enriching Word Vectors with Subword Information
|
|
|
|
+Bag of Tricks for Efficient Text Classification
|
|
|
|
+不過介紹了這麼多,今天我主要的目的是要介紹如何在 Python 中透過 Gensim 套件快速地調用 FastText 訓練一個 Word Embedding 的模型。基本上流程都與 Gensim 中本來訓練 Word2Vec 極度相像。
|
|
|
|
+以下就直接來看程式碼。值得一提的是,由於我之前寫過使用 Gensim 訓練 Word2Vec 模型,所以有部份相同的流程我是直接從那邊抄來的 XDD
|
|
|
|
+安裝 Gensim
|
|
|
|
+首先,如果你的環境裡沒有 Gensim,使用以下指令安裝:
|
|
|
|
+pip3 install gensim
|
|
|
|
+下載 WIKI 語料
|
|
|
|
+這裡以 Wiki 上的中文資料為訓練語料,Wiki 上的資料可是相當優秀的。不僅量多、而且詞彙涵蓋範圍廣,可以應用在許多不同的任務上。
|
|
|
|
+可以從這個網址找到下載處:https://zh.wikipedia.org/wiki/Wikipedia:%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%8B%E8%BD%BD
|
|
|
|
+進入之後可以直接選擇一個日期,那是不同時間點的資料備份。
|
|
|
|
+比如說我選擇了 20200101 這個時間點的資料,那麼,我要下載的資料則為:zhwiki-20200101-pages-articles-multistream.xml.bz2
|
|
|
|
+要注意的是,你的日期可能與我不同,不過同樣都是這份檔案。
|
|
|
|
+下載之後不用解壓縮,可以使用 Gensim 裡的工具直接提取文章。
|
|
|
|
+WikiCorpus
|
|
|
|
+WikiCorpus 是 Gensim 裡面的一個模組,專門用於清理 Wiki 資料庫中語料不必要的標籤,使其恢復成乾淨的文本。
|
|
|
|
+# coding: utf-8
|
|
|
|
+Extracted the content in the wiki_database
|
|
|
|
+from gensim.corpora import WikiCorpus
|
|
|
|
+# Load data
|
|
|
|
+wiki_corpus = WikiCorpus('../data/zhwiki-latest-pages-articles-multistream.xml.bz2', dictionary={})
|
|
|
|
+# Save data
|
|
|
|
+with open('wiki_text.txt', 'w', encoding='utf-8') as f:
|
|
|
|
+ print('Start to preprocess.')
|
|
|
|
+ for times, text in enumerate(wiki_corpus.get_texts()):
|
|
|
|
+ f.write(' '.join(text)+'\n')
|
|
|
|
+ if (times+1) % 10000 == 0:
|
|
|
|
+ print(times+1)
|
|
|
|
+順帶一提,WikiCorpus() 函式當中的路徑為我下載的語料資料,你的名稱可能與我不同、也需要對應到你下載的路徑。
|
|
|
|
+儲存之後的效果應如下:
|
|
|
|
+斷詞
|
|
|
|
+『斷詞』這項工作指的是文本分成以『詞』為單位的句子。斷詞的工具有很多種,基本上可以參考我之前寫過的:
|
|
|
|
+NLP 繁體中文斷詞的霸主 —— CKIP
|
|
|
|
+NLP 中文斷詞最方便的開源工具之一 —— Jieba
|
|
|
|
+中文自然語言分析的工具包 —— THULAC
|
|
|
|
+多功能的自然語言處理工具 —— HanLP
|
|
|
|
+如果想要對繁體中文斷詞效果最好,首推 CKIP;如果是要斷詞速度的話,那非 Jieba 莫屬。在這裡以 Jieba 示範。
|
|
|
|
+(註:Wiki 的資料當中許多地方是簡繁混雜的,可以考慮使用 OpenCC 這項工具來轉換。詳細的作法可以參閱我之前撰寫過的《中文繁簡轉換的便利工具 —— OpenCC》)
|
|
|
|
+# coding: utf-8
|
|
|
|
+Tokenize
|
|
|
|
+import jieba
|
|
|
|
+from opencc import OpenCC
|
|
|
|
+# Initial
|
|
|
|
+cc = OpenCC('s2t')
|
|
|
|
+# Tokenize
|
|
|
|
+with open('wiki_text_seg.txt', 'w', encoding='utf-8') as new_f:
|
|
|
|
+ with open('wiki_text.txt', 'r', encoding='utf-8') as f:
|
|
|
|
+ for data in f:
|
|
|
|
+ data = cc.convert(data)
|
|
|
|
+ data = jieba.cut(data)
|
|
|
|
+ data = [word for word in data if word != ' ']
|
|
|
|
+ data = ' '.join(data)
|
|
|
|
+
|
|
|
|
+ new_f.write(data)
|
|
|
|
+斷詞結果展示如下:
|
|
|
|
+歐幾
|
|
|
|
+裏
|
|
|
|
+得
|
|
|
|
+西元前
|
|
|
|
+三世
|
|
|
|
+紀的
|
|
|
|
+古希臘
|
|
|
|
+數學家
|
|
|
|
+現在
|
|
|
|
+被
|
|
|
|
+認為
|
|
|
|
+是
|
|
|
|
+幾何
|
|
|
|
+之父
|
|
|
|
+此畫
|
|
|
|
+為拉斐爾
|
|
|
|
+的
|
|
|
|
+作品
|
|
|
|
+雅典
|
|
|
|
+學院
|
|
|
|
+數學
|
|
|
|
+是
|
|
|
|
+利用
|
|
|
|
+…
|
|
|
|
+最後,終於來到呼叫 FastText 來訓練模型了。
|
|
|
|
+使用 FastText 訓練模型
|
|
|
|
+# coding: utf-8
|
|
|
|
+from gensim.models import word2vec, fasttext
|
|
|
|
+# Settings
|
|
|
|
+seed = 666
|
|
|
|
+sg = 0
|
|
|
|
+window_size = 10
|
|
|
|
+vector_size = 100
|
|
|
|
+min_count = 1
|
|
|
|
+workers = 8
|
|
|
|
+epochs = 5
|
|
|
|
+batch_words = 10000
|
|
|
|
+# Train
|
|
|
|
+train_data = word2vec.LineSentence('wiki_text_seg.txt')
|
|
|
|
+model = fasttext.FastText(
|
|
|
|
+ train_data,
|
|
|
|
+ min_count=min_count,
|
|
|
|
+ size=vector_size,
|
|
|
|
+ workers=workers,
|
|
|
|
+ iter=epochs,
|
|
|
|
+ window=window_size,
|
|
|
|
+ sg=sg,
|
|
|
|
+ seed=seed,
|
|
|
|
+ batch_words=batch_words,
|
|
|
|
+)
|
|
|
|
+model.save('fasttext.model')
|
|
|
|
+這裡也解釋一下模型中各個參數的意義:
|
|
|
|
+seed: 亂數種子
|
|
|
|
+sg: Word2Vec 有兩種算法,CBOW 以及 Skip-gram,這裡選擇了訓練比較快的 CBOW
|
|
|
|
+window_size: 周圍詞彙要看多少範圍
|
|
|
|
+size: 轉成向量的維度
|
|
|
|
+min_count: 詞頻少於 min_count 之詞彙不會參與訓練
|
|
|
|
+workers: 訓練的並行數量
|
|
|
|
+iter: 訓練的迭代次數
|
|
|
|
+batch_words:每次給予多少詞彙量訓練
|
|
|
|
+訓練結束以後,我將模型儲存為 “fasttext.model”。
|
|
|
|
+測試模型效果
|
|
|
|
+# coding: utf-8
|
|
|
|
+Test the w2v model
|
|
|
|
+from gensim.models import word2vec
|
|
|
|
+# Load the model
|
|
|
|
+model = word2vec.Word2Vec.load('models/fasttext.model')
|
|
|
|
+# Test
|
|
|
|
+print(model['生物'].shape)
|
|
|
|
+for item in model.most_similar('生物'):
|
|
|
|
+print(item)
|
|
|
|
+model.save('fasttext.model')
|
|
|
|
+Output:
|
|
|
|
+(100,)
|
|
|
|
+('若好', 0.9359757900238037)
|
|
|
|
+('身半', 0.9298930764198303)
|
|
|
|
+('過金', 0.9281899929046631)
|
|
|
|
+('低等生物', 0.9252755641937256)
|
|
|
|
+('腐生物', 0.9232699275016785)
|
|
|
|
+('過金魅', 0.9228056073188782)
|
|
|
|
+('生物能', 0.9225305914878845)
|
|
|
|
+('捉酸蟲', 0.9221773743629456)
|
|
|
|
+('非生物', 0.9185526371002197)
|
|
|
|
+('過金貝', 0.9147799015045166)
|
|
|
|
+不知道是不是我的錯覺,我覺得 Gensim 訓練 Word2Vec 模型感覺效果比較好。
|
|
|
|
+"""
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# Tokenize
|
|
|
|
+text = ' '.join(jieba.cut(text))
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# Mask image
|
|
|
|
+mask_color = np.array(Image.open('./parrot-by-jose-mari-gimenez2.jpg'))
|
|
|
|
+mask_color = mask_color[::3, ::3]
|
|
|
|
+mask_image = mask_color.copy()
|
|
|
|
+mask_image[mask_image.sum(axis=2) == 0] = 255
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# Edge detection
|
|
|
|
+edges = np.mean([gaussian_gradient_magnitude(mask_color[:, :, i]/255., 2) for i in range(3)], axis=0)
|
|
|
|
+mask_image[edges > .08] = 255
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# WordCloud
|
|
|
|
+wc = WordCloud(max_words=2000,
|
|
|
|
+ mask=mask_image,
|
|
|
|
+ # font_path='fonts/DFXingKaiStd-W5.otf',
|
|
|
|
+ max_font_size=40,
|
|
|
|
+ random_state=42,
|
|
|
|
+ relative_scaling=0)
|
|
|
|
+
|
|
|
|
+wc.generate(text)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# Create coloring from image
|
|
|
|
+def color_func(word, font_size, position, orientation, random_state=None, **kwargs):
|
|
|
|
+ return 'hsl(51, 100%%, %d%%)' % random.randint(40, 60)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+wc.recolor(color_func=color_func)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# Plot
|
|
|
|
+plt.figure()
|
|
|
|
+plt.axis('off')
|
|
|
|
+plt.imshow(wc)
|
|
|
|
+plt.show()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# Save
|
|
|
|
+plt.figure()
|
|
|
|
+plt.axis('off')
|
|
|
|
+fig = plt.imshow(wc, interpolation='nearest')
|
|
|
|
+fig.axes.get_xaxis().set_visible(False)
|
|
|
|
+fig.axes.get_yaxis().set_visible(False)
|
|
|
|
+plt.savefig('test.png',
|
|
|
|
+ bbox_inches='tight',
|
|
|
|
+ pad_inches=0,
|
|
|
|
+ format='png',
|
|
|
|
+ dpi=300)
|