【火爐煉AI】機器學習040-NLP性別判斷分類器

weixin_34377065發表於2018-10-17

【火爐煉AI】機器學習040-NLP性別判斷分類器

(本文所使用的Python庫和版本號: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2, NLTK 3.3)

本文的目標是構建一個分類器,從名字就判斷這個人是男性還是女性。能夠建立這種分類器的基本假設是英文名字後面的幾個字母帶有很明顯的性別傾向,比如'la'結尾的一般是女性,以'im'結尾的一般是男性。故而我們認為名字的後面幾個字母和性別之間有很強烈的相關性,所以可以建立一個分類模型,從名字中就可以直接判斷性別。


1. 準備資料集

NLTK庫中已經有英文姓名的一些文件,此處我們可以直接載入,並將兩部分的名字合併組成一個資料集。

# 1, 準備資料集,此次資料集來源於nltk.corpus內建的names檔案
from nltk.corpus import names
male_names=[(name, 'male') for name in names.words('male.txt')]
female_names=[(name,'female') for name in names.words('female.txt')]
print(len(male_names)) # 2943
print(len(female_names)) # 5001
# 資料集中有2943個男性名字,5001個女性名字

# 看看男性和女性的名字都是哪些。。。。
print(male_names[:5])
print(female_names[:3])

# 將這些名字組成的list合併成一個資料集,第一列是名字,即features,第二列是性別,即label
dataset=np.array(male_names+female_names)
print(dataset.shape) # (7944, 2)沒錯
複製程式碼

------------------輸---------出------------

2943 5001 [('Aamir', 'male'), ('Aaron', 'male'), ('Abbey', 'male'), ('Abbie', 'male'), ('Abbot', 'male')] [('Abagael', 'female'), ('Abagail', 'female'), ('Abbe', 'female')] (7944, 2)

-----------------------完-------------

雖然此處我們假設名字的後面幾個字母和性別之間有很強烈的相關性,但是我們不確定到底是最後幾個字母的相關性最強,我們應該給予最後的幾個字母來建模,所以,此處我們就分別取最後的1-4個字母,然後組成資料集的特徵列,分別建模,看看哪一種的結果最好。

# 處理資料集
# 我們難以確定到底是姓名後面的幾個字母才和性別相關性最大,
# 故而此處把後面的1-4個字母都取出來作為一個特徵列
# 用pandas 貌似更容易一些
import pandas as pd
dataset_df=pd.DataFrame(dataset,columns=['name','sex'])
# print(dataset_df.info())
# print(dataset_df.head()) # 檢查沒有問題

for i in range(1,5): # 分別擷取每個名字的後面i個字母
    dataset_df['len'+str(i)]=dataset_df.name.map(lambda x: x[-i:].lower())
    
print(dataset_df.head())# 檢查沒有問題
複製程式碼

-----------------輸---------出------

name sex len1 len2 len3 len4
0 Aamir male r ir mir amir
1 Aaron male n on ron aron
2 Abbey male y ey bey bbey
3 Abbie male e ie bie bbie
4 Abbot male t ot bot bbot

-------------------完-------------


2. 建立模型,訓練特徵

此處由於我們不知道姓名後面幾個字母得到的結果最準確,故而只能都建模看看在測試集上的表現。如下為程式碼:

# 分別構建分類器,並訓練後再測試集上看看效果
dataset=dataset_df.values
np.random.shuffle(dataset)
rows=int(len(dataset)*0.7) # 70%為train set
train_set,test_set=dataset[:rows],dataset[rows:]

from nltk import NaiveBayesClassifier
from nltk.classify import accuracy as nltk_accuracy
for i in range(1,5): # 對每一列特徵分別建模並訓練
    train_X,train_y=train_set[:,i+1],train_set[:,1]
    train=[({'feature':feature},label) for (feature,label) in zip(train_X,train_y)] 
    # 後面的NaiveBayesClassifier 在train的時候需要()組成的list
    clf=NaiveBayesClassifier.train(train)
    
    # 檢視該模型在test set上的表現
    test_X,test_y=test_set[:,i+1],test_set[:,1]
    test=[({'feature':feature},label) for (feature,label) in zip(test_X,test_y)] 
    acc=nltk_accuracy(clf,test)
    
    print('Number of suffix: {}, accuracy on test set: {:.2f}%'
          .format(i, 100*acc))
複製程式碼

------------------輸---------出-----------

Number of suffix: 1, accuracy on test set: 76.05%
Number of suffix: 2, accuracy on test set: 77.89%
Number of suffix: 3, accuracy on test set: 75.80%
Number of suffix: 4, accuracy on test set: 71.56%

----------------完-----------------------

由此可以看出,最準確的是隻需要兩個字母的情況,其次是隻需要一個字母。在測試集上的準確率為77%左右。

########################小**********結###############################

1,本專案對資料集的準備需要花費一番功夫,需要分別取出名字的後面N個字母作為一個新的特徵列。然後用這個特徵列在訓練模型

2,nltk模組中繼承的分類器可以不需要對特徵進行文字轉數字操作,故而此處我們沒必要用傳統機器學習的String轉int的讀熱編碼方式來轉換,估計nltk這些分類器內部已經整合了這些轉換操作。

3,NaiveBaysClassifier在呼叫train方法時,需要注意輸入變數的形式,必須是(特徵dict,label)組成的list,否則很多情況下會出錯。

#################################################################


注:本部分程式碼已經全部上傳到(我的github)上,歡迎下載。

參考資料:

1, Python機器學習經典例項,Prateek Joshi著,陶俊傑,陳小莉譯

相關文章