# 使用詞袋嵌入
在本節中,我們將首先向您展示如何使用 TensorFlow 中的詞袋嵌入。這種映射是我們在介紹中介紹的。在這里,我們將向您展示如何使用此類嵌入進行垃圾郵件預測。
## 做好準備
為了說明如何在文本數據集中使用詞袋,我們將使用來自 UCI 機器學習數據倉庫的垃圾郵件電話文本數據庫( [https://archive.ics.uci.edu/ml/數據集/短信+垃圾郵件+收集](https://archive.ics.uci.edu/ml/datasets/SMS+Spam+Collection))。這是垃圾郵件或非垃圾郵件(火腿)的電話短信集合。我們將下載此數據,將其存儲以備將來使用,然后繼續使用詞袋方法來預測文本是否為垃圾郵件。將在詞袋算法上運行的模型將是沒有隱藏層的邏輯模型。我們將使用批量大小為 1 的隨機訓練,并在最后的保持測試集上計算精度。
## 操作步驟
對于這個例子,我們將首先獲取數據,正則化和分割文本,通過嵌入函數運行它,并訓練邏輯函數來預測垃圾郵件:
1. 第一項任務是為此任務導入必要的庫。在通常的庫中,我們需要一個`.zip`文件庫來解壓縮來自 UCI 機器學習網站的數據,我們從中檢索它:
```py
import tensorflow as tf
import matplotlib.pyplot as plt
import os
import numpy as np
import csv
import string
import requests
import io
from zipfile import ZipFile
from tensorflow.contrib import learn
sess = tf.Session()
```
1. 我們不會在每次運行腳本時下載文本數據,而是保存它并檢查文件之前是否已保存。如果我們想要更改腳本的參數,這可以防止我們反復下載數據。下載此數據后,我們將提取輸入和目標數據,并將目標更改為`1`以查找垃圾郵件,將`0`更改為火腿:
```py
save_file_name = os.path.join('temp','temp_spam_data.csv')
if os.path.isfile(save_file_name):
text_data = []
with open(save_file_name, 'r') as temp_output_file:
reader = csv.reader(temp_output_file)
for row in reader:
text_data.append(row)
else:
zip_url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/00228/smsspamcollection.zip'
r = requests.get(zip_url)
z = ZipFile(io.BytesIO(r.content))
file = z.read('SMSSpamCollection')
# Format Data
text_data = file.decode()
text_data = text_data.encode('ascii',errors='ignore')
text_data = text_data.decode().split('\n')
text_data = [x.split('\t') for x in text_data if len(x)>=1]
# And write to csv
with open(save_file_name, 'w') as temp_output_file:
writer = csv.writer(temp_output_file)
writer.writerows(text_data)
texts = [x[1] for x in text_data]
target = [x[0] for x in text_data]
# Relabel 'spam' as 1, 'ham' as 0
target = [1 if x=='spam' else 0 for x in target]
```
1. 為了減少潛在的詞匯量,我們將文本正則化。為此,我們消除了文本中大小寫和數字的影響。使用以下代碼:
```py
# Convert to lower case
texts = [x.lower() for x in texts]
# Remove punctuation
texts = [''.join(c for c in x if c not in string.punctuation) for x in texts]
# Remove numbers
texts = [''.join(c for c in x if c not in '0123456789') for x in texts]
# Trim extra whitespace
texts = [' '.join(x.split()) for x in texts]
```
1. 我們還必須確定最大句子大小。為此,我們將查看數據集中文本長度的直方圖。我們可以看到一個很好的截止可能是 25 個字左右。使用以下代碼:
```py
# Plot histogram of text lengths
text_lengths = [len(x.split()) for x in texts]
text_lengths = [x for x in text_lengths if x < 50]
plt.hist(text_lengths, bins=25)
plt.title('Histogram of # of Words in Texts')
sentence_size = 25
min_word_freq = 3
```
由此,我們將得到以下繪圖:

圖 1:數據中每個文本中單詞數的直方圖。
We use this to establish a maximum length of words to consider in each text. We set this to 25 words, but it can easily be set to 30 or 40 as well.
1. TensorFlow 有一個內置的處理工具,用于確定名為`VocabularyProcessor()`的詞匯嵌入,它位于`learn.preprocessing`庫中。請注意,您可能會使用此函數獲得已棄用的警告:
```py
vocab_processor = learn.preprocessing.VocabularyProcessor(sentence_size, min_frequency=min_word_freq)
vocab_processor.fit_transform(texts)
transformed_texts = np.array([x for x in vocab_processor.transform(texts)])
embedding_size = len(np.unique(transformed_texts))
```
1. 現在我們將數據分成 80-20 訓練和測試集:
```py
train_indices = np.random.choice(len(texts), round(len(texts)*0.8), replace=False)
test_indices = np.array(list(set(range(len(texts))) - set(train_indices)))
texts_train = [x for ix, x in enumerate(texts) if ix in train_indices]
texts_test = [x for ix, x in enumerate(texts) if ix in test_indices]
target_train = [x for ix, x in enumerate(target) if ix in train_indices]
target_test = [x for ix, x in enumerate(target) if ix in test_indices]
```
1. 接下來,我們聲明單詞的嵌入矩陣。句子詞將被翻譯成指數。這些索引將被轉換為一個熱編碼的向量,我們可以使用單位矩陣創建,這將是我們的單詞嵌入的大小。我們將使用此矩陣查找每個單詞的稀疏向量,并將它們一起添加到稀疏句子向量中。使用以下代碼執行此操作:
```py
identity_mat = tf.diag(tf.ones(shape=[embedding_size]))
```
1. 由于我們最終會執行邏輯回歸來預測垃圾郵件的概率,因此我們需要聲明邏輯回歸變量。然后我們也可以聲明我們的數據占位符。值得注意的是,`x_data`輸入占位符應該是整數類型,因為它將用于查找我們的單位矩陣的行索引。 TensorFlow 要求此查找為整數:
```py
A = tf.Variable(tf.random_normal(shape=[embedding_size,1]))
b = tf.Variable(tf.random_normal(shape=[1,1]))
# Initialize placeholders
x_data = tf.placeholder(shape=[sentence_size], dtype=tf.int32)
y_target = tf.placeholder(shape=[1, 1], dtype=tf.float32)
```
1. 現在我們將使用 TensorFlow 的嵌入查找函數,它將句子中單詞的索引映射到我們單位矩陣的單熱編碼向量。當我們有這個矩陣時,我們通過總結上述單詞向量來創建句子向量。使用以下代碼執行此操作:
```py
x_embed = tf.nn.embedding_lookup(identity_mat, x_data)
x_col_sums = tf.reduce_sum(x_embed, 0)
```
1. 現在我們為每個句子都有固定長度的句子向量,我們想要進行邏輯回歸。為此,我們需要聲明實際的模型操作。由于我們一次只做一個數據點(隨機訓練),我們將擴展輸入的維度并對其進行線性回歸操作。請記住,TensorFlow 具有包含 sigmoid 函數的 loss 函數,因此我們不需要在此輸出中包含它:
```py
x_col_sums_2D = tf.expand_dims(x_col_sums, 0)
model_output = tf.add(tf.matmul(x_col_sums_2D, A), b)
```
1. 我們現在將聲明損失函數,預測操作和優化函數來訓練模型。使用以下代碼執行此操作:
```py
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=model_output, labels=y_target))
# Prediction operation
prediction = tf.sigmoid(model_output)
# Declare optimizer
my_opt = tf.train.GradientDescentOptimizer(0.001)
train_step = my_opt.minimize(loss)
```
1. 接下來,我們將在開始訓練生成之前初始化圖變量:
```py
init = tf.global_variables_initializer()
sess.run(init)
```
1. 現在我們將開始對句子進行迭代。 TensorFlow 的`vocab_processor.fit()`函數是一次運行一個句子的生成器。我們將利用這一優勢,以便我們可以對物流模型進行隨機訓練。為了更好地了解準確率趨勢,我們將保留過去 50 個訓練步驟的平均值。如果我們只是繪制當前的一個,我們會看到 1 或 0,這取決于我們是否預測訓練數據是否正確。使用以下代碼執行此操作:
```py
loss_vec = []
train_acc_all = []
train_acc_avg = []
for ix, t in enumerate(vocab_processor.fit_transform(texts_train)):
y_data = [[target_train[ix]]]
sess.run(train_step, feed_dict={x_data: t, y_target: y_data})
temp_loss = sess.run(loss, feed_dict={x_data: t, y_target: y_data})
loss_vec.append(temp_loss)
if (ix+1)%10==0:
print('Training Observation #{}: Loss= {}'.format(ix+1, temp_loss))
# Keep trailing average of past 50 observations accuracy
# Get prediction of single observation
[[temp_pred]] = sess.run(prediction, feed_dict={x_data:t, y_target:y_data})
# Get True/False if prediction is accurate
train_acc_temp = target_train[ix]==np.round(temp_pred)
train_acc_all.append(train_acc_temp)
if len(train_acc_all) >= 50:
train_acc_avg.append(np.mean(train_acc_all[-50:]))
```
1. 這導致以下輸出:
```py
Starting Training Over 4459 Sentences.
Training Observation #10: Loss = 5.45322
Training Observation #20: Loss = 3.58226
Training Observation #30: Loss = 0.0
...
Training Observation #4430: Loss = 1.84636
Training Observation #4440: Loss = 1.46626e-05
Training Observation #4450: Loss = 0.045941
```
1. 為了獲得測試集的準確率,我們重復前面的過程,但僅限于預測操作,而不是測試集的訓練操作:
```py
print('Getting Test Set Accuracy')
test_acc_all = []
for ix, t in enumerate(vocab_processor.fit_transform(texts_test)):
y_data = [[target_test[ix]]]
if (ix+1)%50==0:
print('Test Observation #{}'.format(ix+1))
# Keep trailing average of past 50 observations accuracy
# Get prediction of single observation
[[temp_pred]] = sess.run(prediction, feed_dict={x_data:t, y_target:y_data})
# Get True/False if prediction is accurate
test_acc_temp = target_test[ix]==np.round(temp_pred)
test_acc_all.append(test_acc_temp)
print('\nOverall Test Accuracy: {}'.format(np.mean(test_acc_all)))
Getting Test Set Accuracy For 1115 Sentences.
Test Observation #10
Test Observation #20
Test Observation #30
...
Test Observation #1000
Test Observation #1050
Test Observation #1100
Overall Test Accuracy: 0.8035874439461883
```
## 工作原理
在本例中,我們使用了來自 UCI 機器學習庫的垃圾郵件文本數據。我們使用 TensorFlow 的詞匯處理函數來創建標準化詞匯表來處理和創建句子向量,這些句子向量是每個文本的單詞向量的總和。我們使用這個句子向量與邏輯回歸并獲得 80%準確率模型來預測特定文本是否是垃圾郵件。
## 更多
值得一提的是限制句子(或文本)大小的動機。在此示例中,我們將文本大小限制為 25 個單詞。這是詞袋的常見做法,因為它限制了文本長度對預測的影響。你可以想象,如果我們找到一個單詞,例如`meeting`,它可以預測文本是火腿(而不是垃圾郵件),那么垃圾郵件可能會通過在最后輸入該單詞的多次出現來實現。實際上,這是目標數據不平衡的常見問題。在這種情況下可能會出現不平衡的數據,因為垃圾郵件可能很難找到,而火腿可能很容易找到。由于這個事實,我們創建的詞匯可能嚴重偏向于我們數據的火腿部分中表示的單詞(更多火腿意味著更多的單詞在火腿中表示而不是垃圾郵件)。如果我們允許無限長度的文本,那么垃圾郵件發送者可能會利用這一點并創建非常長的文本,這些文本在我們的邏輯模型中觸發非垃圾郵件詞因素的概率更高。
在下一節中,我們將嘗試通過使用單詞出現的頻率來更好地解決此問題,以確定單詞嵌入的值。
- TensorFlow 入門
- 介紹
- TensorFlow 如何工作
- 聲明變量和張量
- 使用占位符和變量
- 使用矩陣
- 聲明操作符
- 實現激活函數
- 使用數據源
- 其他資源
- TensorFlow 的方式
- 介紹
- 計算圖中的操作
- 對嵌套操作分層
- 使用多個層
- 實現損失函數
- 實現反向傳播
- 使用批量和隨機訓練
- 把所有東西結合在一起
- 評估模型
- 線性回歸
- 介紹
- 使用矩陣逆方法
- 實現分解方法
- 學習 TensorFlow 線性回歸方法
- 理解線性回歸中的損失函數
- 實現 deming 回歸
- 實現套索和嶺回歸
- 實現彈性網絡回歸
- 實現邏輯回歸
- 支持向量機
- 介紹
- 使用線性 SVM
- 簡化為線性回歸
- 在 TensorFlow 中使用內核
- 實現非線性 SVM
- 實現多類 SVM
- 最近鄰方法
- 介紹
- 使用最近鄰
- 使用基于文本的距離
- 使用混合距離函數的計算
- 使用地址匹配的示例
- 使用最近鄰進行圖像識別
- 神經網絡
- 介紹
- 實現操作門
- 使用門和激活函數
- 實現單層神經網絡
- 實現不同的層
- 使用多層神經網絡
- 改進線性模型的預測
- 學習玩井字棋
- 自然語言處理
- 介紹
- 使用詞袋嵌入
- 實現 TF-IDF
- 使用 Skip-Gram 嵌入
- 使用 CBOW 嵌入
- 使用 word2vec 進行預測
- 使用 doc2vec 進行情緒分析
- 卷積神經網絡
- 介紹
- 實現簡單的 CNN
- 實現先進的 CNN
- 重新訓練現有的 CNN 模型
- 應用 StyleNet 和 NeuralStyle 項目
- 實現 DeepDream
- 循環神經網絡
- 介紹
- 為垃圾郵件預測實現 RNN
- 實現 LSTM 模型
- 堆疊多個 LSTM 層
- 創建序列到序列模型
- 訓練 Siamese RNN 相似性度量
- 將 TensorFlow 投入生產
- 介紹
- 實現單元測試
- 使用多個執行程序
- 并行化 TensorFlow
- 將 TensorFlow 投入生產
- 生產環境 TensorFlow 的一個例子
- 使用 TensorFlow 服務
- 更多 TensorFlow
- 介紹
- 可視化 TensorBoard 中的圖
- 使用遺傳算法
- 使用 k 均值聚類
- 求解常微分方程組
- 使用隨機森林
- 使用 TensorFlow 和 Keras