1.1 性别鉴定
在4中,我们看到,男性和女性的名字有一些鲜明的特点。以 a,e 和 i 结尾的很可能是女性,而以 k,o,r,s 和 t 结尾的很可能是男性。让我们建立一个分类器更精确地模拟这些差异。
创建一个分类器的第一步是决定输入的什么样的特征是相关的,以及如何为那些特征编码。在这个例子中,我们一开始只是寻找一个给定的名称的最后一个字母。以下特征提取器函数建立一个字典,包含有关给定名称的相关信息:
>>> def gender_features(word):
... return {'last_letter': word[-1]}
>>> gender_features('Shrek')
{'last_letter': 'k'}
这个函数返回的字典被称为特征集,映射特征名称到它们的值。特征名称是区分大小写的字符串,通常提供一个简短的人可读的特征描述,例如本例中的'last_letter'
。特征值是简单类型的值,如布尔、数字和字符串。
注意
大多数分类方法要求特征使用简单的类型进行编码,如布尔类型、数字和字符串。但要注意仅仅因为一个特征是简单类型,并不一定意味着该特征的值易于表达或计算。的确,它可以用非常复杂的和有信息量的值作为特征,如第 2 个有监督分类器的输出。
现在,我们已经定义了一个特征提取器,我们需要准备一个例子和对应类标签的列表。
>>> from nltk.corpus import names
>>> labeled_names = ([(name, 'male') for name in names.words('male.txt')] +
... [(name, 'female') for name in names.words('female.txt')])
>>> import random
>>> random.shuffle(labeled_names)
接下来,我们使用特征提取器处理names
数据,并划分特征集的结果链表为一个训练集和一个测试集。训练集用于训练一个新的“朴素贝叶斯”分类器。
>>> featuresets = [(gender_features(n), gender) for (n, gender) in labeled_names]
>>> train_set, test_set = featuresets[500:], featuresets[:500]
>>> classifier = nltk.NaiveBayesClassifier.train(train_set)
在本章的后面,我们将学习更多关于朴素贝叶斯分类器的内容。现在,让我们只是在上面测试一些没有出现在训练数据中的名字:
>>> classifier.classify(gender_features('Neo'))
'male'
>>> classifier.classify(gender_features('Trinity'))
'female'
请看 《黑客帝国》 中这些角色的名字被正确分类。尽管这部科幻电影的背景是在 2199 年,但它仍然符合我们有关名字和性别的预期。我们可以在大数据量的未见过的数据上系统地评估这个分类器:
>>> print(nltk.classify.accuracy(classifier, test_set))
0.77
最后,我们可以检查分类器,确定哪些特征对于区分名字的性别是最有效的:
>>> classifier.show_most_informative_features(5)
Most Informative Features
last_letter = 'a' female : male = 33.2 : 1.0
last_letter = 'k' male : female = 32.6 : 1.0
last_letter = 'p' male : female = 19.7 : 1.0
last_letter = 'v' male : female = 18.6 : 1.0
last_letter = 'f' male : female = 17.3 : 1.0
此列表显示训练集中以 a 结尾的名字中女性是男性的 38 倍,而以 k 结尾名字中男性是女性的 31 倍。这些比率称为似然比,可以用于比较不同特征-结果关系。
注意
轮到你来:修改gender_features()
函数,为分类器提供名称的长度、它的第一个字母以及任何其他看起来可能有用的特征。用这些新特征重新训练分类器,并测试其准确性。
在处理大型语料库时,构建一个包含每一个实例的特征的单独的列表会使用大量的内存。在这些情况下,使用函数nltk.classify.apply_features
,返回一个行为像一个列表而不会在内存存储所有特征集的对象:
>>> from nltk.classify import apply_features
>>> train_set = apply_features(gender_features, labeled_names[500:])
>>> test_set = apply_features(gender_features, labeled_names[:500])