iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 27
0
自我挑戰組

零基礎成為 AI 解夢大師秘笈系列 第 27

【零基礎成為 AI 解夢大師秘笈】Day27 - 周易解夢之人工智慧(8)

人工智慧8

前言

系列文章簡介

大家好,我們是 AI . FREE Team - 人工智慧自由團隊,這一次的鐵人賽,自由團隊將從0到1 手把手教各位讀者學會 (1)Python基礎語法 (2)Python Web 網頁開發框架 – Django (3)Python網頁爬蟲 – 周易解夢網 (4)Tensorflow AI語言模型基礎與訓練 – LSTM (5)實際部屬AI解夢模型到Web框架上。

為什麼技術要從零開始寫起

自由團隊的成立宗旨為開發AI/新科技的學習資源,提供各領域的學習者能夠跨域學習資料科學,並透過自主學習發展協槓職涯,結合智能應用到各式領域,無論是文、法、商、管、醫領域的朋友,都可以自由的學習AI技術。

資源

AI . FREE Team 讀者專屬福利 → Python Basics 免費學習資源

實作part-1

今天將帶大家實作NLP前段,處理資料的部分

資料集

一開始先下載資料集

!git clone https://github.com/ken19980727/emoji.git

輸出

Cloning into 'emoji'...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (6/6), done.

下載好後,應該會在左邊的side bar

在解壓縮

!unzip /content/emoji/data.zip

在檢查side bar

這就是我們的資料集,雖然說很多個資料,但是我們只會用到兩個

下載&導入套件

這個套件是將符號變成實際的表情符號,待會會有實際的操作和詳細說明

!pip install emoji 
Collecting emoji
  Downloading https://files.pythonhosted.org/packages/ff/1c/1f1457fe52d0b30cbeebfd578483cedb3e3619108d2d5a21380dfecf8ffd/emoji-0.6.0.tar.gz (51kB)
     |████████████████████████████████| 51kB 1.8MB/s 
Building wheels for collected packages: emoji
  Building wheel for emoji (setup.py) ... done
  Created wheel for emoji: filename=emoji-0.6.0-cp36-none-any.whl size=49716 sha256=b0cb86566420299a4f4558c19a9ac6f00d33c57c3647d8e08188f7932f2f3af7
  Stored in directory: /root/.cache/pip/wheels/46/2c/8b/9dcf5216ca68e14e0320e283692dce8ae321cdc01e73e17796
Successfully built emoji
Installing collected packages: emoji
Successfully installed emoji-0.6.0

其他套件

import numpy as np
import emoji
import matplotlib.pyplot as plt
import pandas as pd
import emoji
from sklearn.metrics import confusion_matrix
from emoji import emojize

除了emoji之外其他的大家一定都不陌生

再來,我們利用pd.read_csv將csv資料讀進來

data = pd.read_csv('/content/data/emojify_data.csv',names = ['sentences','labels',3,4])
data_dev = pd.read_csv('/content/data/tesss.csv',names = ['sentences','labels'])

我們讀進兩筆data,第一個為train用,第二個valid用,而括號的第一欄是路徑,第二個是藍為名稱

輸出

data_dev

讀取資料集的長度

X_train = [i for i in data['sentences']]
y_train = [i for i in data['labels']]
X_valid = [i[:-1] for i in data_dev['sentences']] # clean the data
y_valid = [i for i in data_dev['labels']]
print(f'X_train length : {len(X_train)}.')
print(f'y_train length : {len(y_train)}.')
print(f'X_valid length : {len(X_valid)}.')
print(f'y_valid length : {len(y_valid)}.')

可以發現X_valid我取每個句子並去掉最後一個字元,原因是因為這筆資料保留的\t跳脫字元,但我們不需要,所以去除(可以自己print出來)

輸出

X_train length : 183.
y_train length : 183.
X_valid length : 56.
y_valid length : 56.

表情符號

前面有提到emoji,他是可以將str轉成可視的表情符號

emoji_dictionary = {"0": "\u2764\uFE0F",    # :heart: prints a black instead of red heart depending on the font
                    "1": ":baseball:",
                    "2": ":smile:",
                    "3": ":disappointed:",
                    "4": ":fork_and_knife:"}

def label_to_emoji(label):
    return emoji.emojize(emoji_dictionary[str(label)])
idx = 3
print(f'before emoji convert : \n{X_train[idx]} {y_train[idx]}')
print('')
print(f'after emoji convert : \n{X_train[idx]} {label_to_emoji(y_train[idx])}')

輸出

before emoji convert : 
throw the ball 1

after emoji convert : 
throw the ball ⚾

想不到hackmd也有表情符號XD,我原本打算用截圖的

差點忘記介紹,可以發現我們總共有5類的答案

print(emoji.emojize('\u2764\uFE0F'))
print(emoji.emojize(':baseball:'))
print(emoji.emojize(':smile:', use_aliases=True))
print(emoji.emojize(":disappointed:", use_aliases=True))
print(emoji.emojize(':fork_and_knife:'))
❤️
⚾
?
?
?

當初資料集的說明是這樣的(大家可以自己打開csv來看)

來看一下每個句子(大家可以調整idx)

idx = 2
print(f'before emoji convert : \n{X_train[idx]} {y_train[idx]}')
print('')
print(f'after emoji convert : \n{X_train[idx]} {label_to_emoji(y_train[idx])}')

輸出

before emoji convert : 
I am upset 3

after emoji convert : 
I am upset ?

one hot encoding

再用one hot之前,先介紹np.eye()這個funciton

np.eye(5)
array([[1., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 1., 0.],
       [0., 0., 0., 0., 1.]])

這個function可以產生一個對稱的n*n的矩陣

因此利用其特性來做one hot encoding,方法有很多種,大家可以來brainstorm一下

def convert_to_one_hot(Y, C):
    Y_oh = [np.eye(C)[i] for i in Y]
    return Y_oh
y_oh_train = convert_to_one_hot(y_train, C = 5)
y_oh_valid = convert_to_one_hot(y_valid, C = 5)
idx = 7
print(f'train : {y_train[idx]} is converted into one hot : {y_oh_train[idx]}')
print(f'valid : {y_valid[idx]} is converted into one hot : {y_oh_valid[idx]}')

輸出

train : 3 is converted into one hot : [0. 0. 0. 1. 0.]
valid : 2 is converted into one hot : [0. 0. 1. 0. 0.]

這樣就算轉換完成了

文字轉數字

之前有提到說,文字也要轉成index(索引)

我們先建立一個words來存入全部的字(不重複)

words = []
for i in X_train:
  for j in i.split():
    if j not in words:
      words.append(j)
words.append('unk')
words.append('pad')
len(words)
335

可以看到總共有333+2個字,至於unkpad待會兒會用到

建立一個字典,讓每個字都有對應的indexword2idx,每個index也有對應的字idx2word,方便查表

word2idx = {w: i for i, w in enumerate(words)}
idx2word = {i: w for i, w in enumerate(words)}
word2idx['unk']
idx = 24
print(f'before split : {X_train[idx]}')
print('')
print(f'after split : {[word2idx[j] for j in X_train[idx].split()]}')

輸出

before split : family is all I have

after split : [68, 2, 69, 7, 47]

建立字典後,可以將全部的句子轉換了

X_train_int = [[word2idx[j] for j in i.split()] for i in X_train]
X_valid_int = []
for i in X_valid:
  x_val_ = []
  for j in i.split():
    if j in words:
      x_val_.append(word2idx[j])
    else:
      x_val_.append(word2idx['unk'])
  X_valid_int.append(x_val_)

這裡可以看到X_train_int沒有複雜的判斷式,但為何X_valid_int要呢,因為當初在建字典和辭庫時,是以X_train的為主,所以X_valid_int可能會有字典和辭庫沒有的字,遇到這種字一律使用unk

這時候就會有熱心的讀者好奇,變unk會不會影響training的結果

其實不太大,就算你把X_valid的詞也丟進字典,但是在訓練時,其實不會training到這類的資料,所以是一樣的

填充句子

之前有說過,如果要用gpu加速的話,就要將資料全部轉成長度一致的矩陣

因此我們來看一下最長的句子長度

tr_maxLen = len(max(X_train_int, key=len))
print(f'train max length : {tr_maxLen}')
va_maxLen = len(max(X_valid_int, key=len))
print(f'valid max length : {va_maxLen}')

輸出

train max length : 10
valid max length : 8

最長的句子長度為10

def padding(X,maxlen):
  for i in X:
    for pad in range(maxlen-len(i)):
      i.append(word2idx['pad'])
  return X
  
X_train_int = padding(X_train_int,tr_maxLen)
X_valid_int = padding(X_valid_int,tr_maxLen)

我們將最長的長度設為tr_maxLen,讓tr_maxLen減去每個句子的長度,之間的差就是要填充的長度,我們再將word2idx['pad']填入

print(f'train max length : {len(max(X_train_int, key=len))}')
print(f'valid max length : {len(max(X_valid_int, key=len))}')

這時應該每個句子長度都一致

train max length : 10
valid max length : 10

先介紹到這裡,NLP的資料處理是非常複雜且多元的,基本上資料處理到這就可以丟進模型了,剩下的我們下篇介紹

想更深入認識 AI . FREE Team ?

自由團隊 官方網站:https://aifreeblog.herokuapp.com/
自由團隊 Github:https://github.com/AI-FREE-Team/
自由團隊 粉絲專頁:https://www.facebook.com/AI.Free.Team/
自由團隊 IG:https://www.instagram.com/aifreeteam/
自由團隊 Youtube:https://www.youtube.com/channel/UCjw6Kuw3kwM_il39NTBJVTg/

文章同步發布於:自由團隊部落格
(想看更多文章?學習更多AI知識?敬請鎖定自由團隊的頻道!)


上一篇
【零基礎成為 AI 解夢大師秘笈】Day26 - 周易解夢之人工智慧(7)
下一篇
【零基礎成為 AI 解夢大師秘笈】Day28 - 周易解夢之人工智慧(9)
系列文
零基礎成為 AI 解夢大師秘笈30

尚未有邦友留言

立即登入留言