(本文所使用的Python庫和版本號: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2, NLTK 3.3)git
本文的目標是構建一個分類器,從名字就判斷這我的是男性仍是女性。可以創建這種分類器的基本假設是英文名字後面的幾個字母帶有很明顯的性別傾向,好比'la'結尾的通常是女性,以'im'結尾的通常是男性。故而咱們認爲名字的後面幾個字母和性別之間有很強烈的相關性,因此能夠創建一個分類模型,從名字中就能夠直接判斷性別。github
<br/>dom
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個字母,而後組成數據集的特徵列,分別建模,看看哪種的結果最好。spa
# 處理數據集 # 咱們難以肯定究竟是姓名後面的幾個字母才和性別相關性最大, # 故而此處把後面的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())# 檢查沒有問題
-------------------------------------輸---------出--------------------------------code
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 bbotorm
--------------------------------------------完-------------------------------------
<br/>
此處因爲咱們不知道姓名後面幾個字母獲得的結果最準確,故而只能都建模看看在測試集上的表現。以下爲代碼:
# 分別構建分類器,並訓練後再測試集上看看效果 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,不然不少狀況下會出錯。
#################################################################
<br/>
注:本部分代碼已經所有上傳到(個人github)上,歡迎下載。
參考資料:
1, Python機器學習經典實例,Prateek Joshi著,陶俊傑,陳小莉譯