aiacademy: 自然語言處理 NLP 1.
Tags: aiacademy, nlp, text-mining
NLP Basics - Meaning Representation
-
Meaning Representations
-
Defintion of “Meaning”
- the idea that is represented by a word, phrase, etc.
- the idea that a person wants to express by using words, signs, etc.
- the idea that is expressed in a word of writing, art, etc
-
-
Meaning Representations in Computers
- Knowledge-Based Representation
- 有一本辭典,一位老師,去查特徵
- Corpus-Based Representation
- 靠 big data 去認字,從前後文去猜
"某字"
- 靠 big data 去認字,從前後文去猜
- Knowledge-Based Representation
Knowledge-Based Representation
- Hypernyms (is-a) relationships of WordNet
NLP Basics - Corpus Based Representation
Meaning Representations in Compters
-
Corpus-Based Representation
-
Windoe-Based Co-occurrence Matrix
- sparsity (資料內很多0)
-
Low-Dimensional Dense Word Vector
-
Summary
- Knowledge-based representation
- Corpus-based representation
- Atomic symbol
- Neighbors
- High-dimensional sparse word vector
- Low-dimensional dense word vector
- Method 1 - dimension reduction
- Method 2 - direct learning
text mining 文字探勘
-
甚麼是文字探勘?
- 從文本產生有價值的訊息
- 從非結構化到結構化
- 分析結構化並得到有價值的訊息
- 從文本產生有價值的訊息
-
文字探勘應用
- 垃圾郵件檢測
- 情感分析
- 命名實體辨識
- 文本摘要
中文分詞
-
與英文文字類似,差別在於需要做斷詞處理
text mining preprocess
-
PTT 資料及爬蟲
文章斷詞
-
- 號稱最好的 Python 中文斷詞套件
- 支持四種斷詞引擎
- 最大概率法、隱式法爾科夫模型、混合模型、索引模型
- 可以標註詞性
-
- 號稱地表最強中文斷詞系統(96% 精準度)
- 自動標註詞性
- 需要申請…
jieba 斷詞
-
設定 字典辭庫 與 stopwords 辭庫
- stop_words
- EX:
了、阿、吧、我們...
- 很常出現的字,但沒特別意義
- EX:
- set_dictionary
- 把繁體中文字典加入
- stop_words
## set dictionary (can define yourself)
jieba.set_dictionary('jieba/dict.txt.big')
stop_words = open('jieba/stop_words.txt', encoding='utf8').read().splitlines()
data = pd.read_csv('data/article_preprocessed.csv')
data = data['content'].tolist()
sentences = []
for i, text in enumerate(tqdm_notebook(data)):
line = []
for w in jieba.cut(text, cut_all=False):
## remove stopwords and digits
## can define your own rules
if w not in stop_words and not bool(re.match('[0-9]+', w)):
line.append(w)
sentences.append(line)
print(sentences[0:5])
[['韓瑜', '協志', '前妻', '正', '女演員', '周子', '瑜', 'TWICE', '團裡裡面', '台灣', '人', '正', '兩個', '要當', '鄉民', '老婆', '選', '五樓', '真', '勇氣'], ['dear', 'all', '逢甲', '碟仙', '發生', '民國', '七十五年', '三月中', '事情', '一堆', '大學生', '玩', '碟仙', '後發', 'bbs', '成功', '預測', '地震', '小弟', '預言', '都還沒', '出生', '後面', '說', '預言', '一百', '一十六年', '兩岸', '統一', '統一', '對岸', '對岸', '統一', '應該', '不用', '猜', '真的', '存在', '預言', '這種', '事情', '倒底', '被統', '知道', '資料庫', '發文', '日期', '輕鬆', '改變', '拍照', '狀況', '下', '碟仙', '真的假', '有沒有', '科學', '經驗', '法則', '破解', '謠言', '真實', '八卦'], ['晚上', '好', '預備', '唱', '風雲', '山河', '動', '國軍', '早上', '唱', '有沒有', '相關', '八卦', 'Sent', 'from', 'JPTT', 'on', 'my', 'Xiaomi', 'Redmi', 'Note'], ['明天', '早起', '睡覺', '旁邊', 'Youtube', '眼睛', '壞掉', '有沒有', '方法', '早點', '睡', '掛', 'Sent', 'from', 'JPTT', 'on', 'my', 'HTC', 'D10i'], ['一段時間', '注意', 'LOL', '發現', '各大', 'LOL', '討論區', '人數', '明顯', '下降', '趨勢', '實在', '令人', '驚訝', '曾經', '一時', '遊戲', '霸主', '漸漸', '過氣', 'LOL', '確實', '撐', '久', '現在', '算', '厲害', '遊戲', '玩久', '會膩']]
posseg (詞性)
from jieba import posseg as pseg
for w, j in pseg.cut(data[0]):
print(w, ' ', j)
韓瑜 nr
是 v
協志 n
的 uj
前妻 n
x
也 d
是 v
很正 a
的 uj
女演員 x
x
周子瑜 nr
是 v
TWICE eng
團裡 q
裡面 f
的 uj
台灣 ns
人 n
x
也 d
是 v
很正 d
x
這 zg
兩個 x
要 v
當 p
鄉民 x
的 uj
老婆 n
, x
你 r
要 v
怎麼 x
選 v
呢 y
? x
? x
x
五 m
樓 n
你 r
真 d
有 v
勇氣 x
feature engineering
-
定義 y
- 發文收到的推比噓多則 1,反之 0
- 中間地帶 (定一個 threshold)
-
推噓文數量差異不超過 threshold 則剔除資料
-
-
-
文本可以產生甚麼特徵?
- 基本資訊
- 字數、標點符號數、中文字比例、”問號”佔字數比例、…
- 關鍵字
- 有/無某關鍵字、關鍵字出現比例/佔比、…
- 關鍵字詞組
- 名詞、正面情緒詞、…
- 文本情緒分數
- …
- 基本資訊
-
基本資訊
- 特徵
- 字數
- 標點符號數
- “問號’佔字數比例
-
一般都會用到正則表達式子處理
-
- 特徵
-
基本資訊結果範例
-
-
關鍵字
-
關鍵字出現次數(bag of words)
-
-
Term Frequency-Inverse Document Frequency (TF-IDF)
- 文字、關鍵字在文件上出現的相對的頻率
-
Why TF-IDF ?
- bag of words 看文字統計的量,都是 the、were、said… 等,沒有重要訊息的文字
- 引入 TF-IDF 關鍵字,可以看得出重要訊息
- TF-IDF 定義
-
TF-IDF 範例
- Doc. 1: I love dogs.
- Doc. 2: I hate dogs and knitting.
- Doc. 3: Knitting is my hobby and my passion.
I | love | dogs | hate | and | knitting | is | my | hobby | passion | |
Doc.1 | 0.18 | 0.48 | 0.18 | |||||||
Doc.2 | 0.18 | 0.18 | 0.48 | 0.18 | 0.18 | |||||
Doc.3 | 0.18 | 0.18 | 0.48 | 0.95 | 0.48 | 0.48 |
feature engineering code
- 把 data load 進來
import re
import pandas as pd
import numpy as np
import pickle
import os
## turn back to main directory
os.chdir("../")
os.getcwd()
df = pd.read_csv('data/article_preprocessed.csv')
## load 'article_cutted'
with open("article_cutted", "rb") as file:
sentences = pickle.load(file)
- define y (push > boo)
## drop data
diff_threshold = 20
df = df[abs(df['push']-df['boo']) > diff_threshold].copy()
## define y
df['type'] = np.clip(df['push']-df['boo'], 0, 1)
df = df.reset_index(drop=True)
df['type'].value_counts()
-
simple feature
- 中文 utf8
## word count ## http://blog.csdn.net/gatieme/article/details/43235791 (中文正則表達式) df['word_count'] = df['content'].str.count('[a-zA-Z0-9]+') + df['content'].str.count('[\u4e00-\u9fff]')
- 中文 utf8
## punctuation count
df['punctuation'] = df['content'].str.replace('[\w\s]', '')
df['punctuation_count'] = df['punctuation'].str.len()
## question mark count
df['question_count'] = df['punctuation'].str.count('[??]')
## drop punctuation column
df = df.drop(['punctuation'],axis=1)
df.iloc[:5, -4:]
type | word_count | punctuation_count | question_count | |
0 | 1 | 175 | 0 | 0 |
1 | 1 | 145 | 4 | 1 |
2 | 1 | 393 | 17 | 8 |
3 | 1 | 295 | 15 | 6 |
4 | 1 | 41 | 4 | 0 |
- pandas .corr() 方法
## compute correlation
df.iloc[:, -4:].corr()
type | word_count | punctuation_count | question_count | |
type | 1.000000 | -0.045100 | -0.024124 | -0.056966 |
word_count | -0.045100 | 1.000000 | 0.738419 | 0.534900 |
punctuation_count | -0.024124 | 0.738419 | 1.000000 | 0.342150 |
question_count | -0.056966 | 0.534900 | 0.342150 | 1.000000 |
- bag of words
from sklearn.feature_extraction.text import CountVectorizer
## define transformer (轉換器)
vectorizer = CountVectorizer()
count = vectorizer.fit_transform([' '.join(x) for x in sentences])
## save data as pickle format
with open("article_count", "wb") as file:
pickle.dump([vectorizer, count], file)
- select top 10 frequency of words
## create a dictionary: id as key ; word as values
id2word = {v:k for k, v in vectorizer.vocabulary_.items()}
## columnwise sum: words frequency
sum_ = np.array(count.sum(axis=0))[0]
## top 10 frequency's wordID
most_sum_id = sum_.argsort()[::-1][:10].tolist()
most_sum_id
[73627, 198934, 95899, 37001, 243708, 258736, 257519, 305714, 256024, 283981]
## print top 10 frequency's words
features = [id2word[i] for i in most_sum_id]
features
[‘八卦’, ‘有沒有’, ‘台灣’, ‘一個’, ‘現在’, ‘知道’, ‘真的’, ‘覺得’, ‘看到’, ‘肥宅’]
## print the data
data = pd.DataFrame(count[df.idx.values,:][:,most_sum_id].toarray(), columns=features)
data[:5]
八卦 | 有沒有 | 台灣 | 一個 | 現在 | 知道 | 真的 | 覺得 | 看到 | 肥宅 | |
0 | 1 | 1 | 1 | 0 | 2 | 0 | 0 | 1 | 0 | 1 |
1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 0 |
3 | 1 | 2 | 0 | 2 | 0 | 2 | 0 | 0 | 0 | 0 |
4 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
df.iloc[0].content
‘反核覺青現在最強招式就是 不然燃料棒放你家 肥宅我覺得 把燃料棒放到其他國家不就好了 一定會有缺錢的國家 台灣塞錢給他們 買他們國家的空間放 一來燃料棒問題解決 核電重啟 台灣缺點問題解決 大家有冷氣吹 台積電不出走 繼續救台灣 二來有買賣就有貪污空間 政客也有賺頭 不會像現在沒糖吃該該叫 送錢出去 邦交國搞不好也會多幾個 簡直是雙贏 核電燃料棒 跟其他國家買空間放不就好了 有沒有相關八卦 ‘
## compute correlation
data = pd.concat([df.type, data], axis=1)
data.corr()
type | 八卦 | 有沒有 | 台灣 | 一個 | 現在 | 知道 | 真的 | 覺得 | 看到 | 肥宅 | |
type | 1.000000 | -0.056491 | 0.000898 | -0.048109 | -0.032585 | -0.018120 | -0.019432 | -0.021593 | -0.012116 | -0.048172 | -0.013955 |
八卦 | -0.056491 | 1.000000 | 0.431786 | -0.001901 | 0.062416 | 0.052670 | 0.091136 | 0.084516 | 0.066589 | 0.066047 | 0.077210 |
有沒有 | 0.000898 | 0.431786 | 1.000000 | 0.032712 | 0.094241 | 0.105734 | 0.144891 | 0.105919 | 0.095098 | 0.089291 | 0.043573 |
台灣 | -0.048109 | -0.001901 | 0.032712 | 1.000000 | 0.194281 | 0.188974 | 0.166716 | 0.162471 | 0.125782 | 0.137087 | -0.033735 |
一個 | -0.032585 | 0.062416 | 0.094241 | 0.194281 | 1.000000 | 0.400985 | 0.523627 | 0.398092 | 0.370977 | 0.327872 | 0.026330 |
現在 | -0.018120 | 0.052670 | 0.105734 | 0.188974 | 0.400985 | 1.000000 | 0.418126 | 0.348470 | 0.306070 | 0.230148 | 0.009126 |
知道 | -0.019432 | 0.091136 | 0.144891 | 0.166716 | 0.523627 | 0.418126 | 1.000000 | 0.486961 | 0.391520 | 0.336525 | 0.037975 |
真的 | -0.021593 | 0.084516 | 0.105919 | 0.162471 | 0.398092 | 0.348470 | 0.486961 | 1.000000 | 0.461401 | 0.331108 | 0.039239 |
覺得 | -0.012116 | 0.066589 | 0.095098 | 0.125782 | 0.370977 | 0.306070 | 0.391520 | 0.461401 | 1.000000 | 0.270267 | 0.026513 |
看到 | -0.048172 | 0.066047 | 0.089291 | 0.137087 | 0.327872 | 0.230148 | 0.336525 | 0.331108 | 0.270267 | 1.000000 | 0.020214 |
肥宅 | -0.013955 | 0.077210 | 0.043573 | -0.033735 | 0.026330 | 0.009126 | 0.037975 | 0.039239 | 0.026513 | 0.020214 | 1.000000 |
- TF-IDF
from sklearn.feature_extraction.text import TfidfVectorizer
## define transformer (轉換器)
vectorizer = TfidfVectorizer(norm=None) ## do not do normalize
tfidf = vectorizer.fit_transform([' '.join(x) for x in sentences])
## save data as pickle format
with open("article_tfidf", "wb") as file:
pickle.dump([vectorizer, tfidf], file)
- select top 10 average tf-idf words
## create a dictionary: id as key ; word as values
id2word = {v:k for k, v in vectorizer.vocabulary_.items()}
## columnwise average: words tf-idf
avg = tfidf.sum(axis=0) / (tfidf!=0).sum(axis=0)
## set df < 20 as 0
avg[(tfidf!=0).sum(axis=0)<20] = 0
avg = np.array(avg)[0]
## top 10 tfidf's wordID
most_avg_id = avg.argsort()[::-1][:10].tolist()
most_avg_id
[90835, 325364, 157970, 263428, 357411, 5490, 47011, 33207, 51405, 183683]
## print top 10 tf-idf's words
features = [id2word[i] for i in most_avg_id]
features
[‘原告’, ‘轉帳’, ‘忍術’, ‘稅後’, ‘震度’, ‘charlie’, ‘中山路’, ‘united’, ‘二段’, ‘支出’]
## print the data
data = pd.DataFrame(tfidf[df.idx.values,:][:,most_avg_id].toarray(), columns=features)
data[:5]
原告 | 轉帳 | 忍術 | 稅後 | 震度 | charlie | 中山路 | united | 二段 | 支出 | |
0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 |
1 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 |
2 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 |
3 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 |
4 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 9.395045 | 0.0 |
## compute correlation
data = pd.concat([df.type, data], axis=1)
data.corr()