(本文所使用的Python库和版本号: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2, NLTK 3.3)git
本文的目标是构建一个分类器,从名字就判断这我的是男性仍是女性。可以创建这种分类器的基本假设是英文名字后面的几个字母带有很明显的性别倾向,好比'la'结尾的通常是女性,以'im'结尾的通常是男性。故而咱们认为名字的后面几个字母和性别之间有很强烈的相关性,因此能够创建一个分类模型,从名字中就能够直接判断性别。github
NLTK库中已经有英文姓名的一些文档,此处咱们能够直接加载,并将两部分的名字合并组成一个数据集。dom
# 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())# 检查没有问题
-------------------------------------输---------出--------------------------------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
--------------------------------------------完-------------------------------------继承
此处因为咱们不知道姓名后面几个字母获得的结果最准确,故而只能都建模看看在测试集上的表现。以下为代码:
# 分别构建分类器,并训练后再测试集上看看效果 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著,陶俊杰,陈小莉译