1.1 性别鉴定

4中,我们看到,男性和女性的名字有一些鲜明的特点。以 a,e 和 i 结尾的很可能是女性,而以 k,o,r,s 和 t 结尾的很可能是男性。让我们建立一个分类器更精确地模拟这些差异。

创建一个分类器的第一步是决定输入的什么样的特征是相关的,以及如何为那些特征编码。在这个例子中,我们一开始只是寻找一个给定的名称的最后一个字母。以下特征提取器函数建立一个字典,包含有关给定名称的相关信息:

  1. >>> def gender_features(word):
  2. ... return {'last_letter': word[-1]}
  3. >>> gender_features('Shrek')
  4. {'last_letter': 'k'}

这个函数返回的字典被称为特征集,映射特征名称到它们的值。特征名称是区分大小写的字符串,通常提供一个简短的人可读的特征描述,例如本例中的'last_letter'。特征值是简单类型的值,如布尔、数字和字符串。

注意

大多数分类方法要求特征使用简单的类型进行编码,如布尔类型、数字和字符串。但要注意仅仅因为一个特征是简单类型,并不一定意味着该特征的值易于表达或计算。的确,它可以用非常复杂的和有信息量的值作为特征,如第 2 个有监督分类器的输出。

现在,我们已经定义了一个特征提取器,我们需要准备一个例子和对应类标签的列表。

  1. >>> from nltk.corpus import names
  2. >>> labeled_names = ([(name, 'male') for name in names.words('male.txt')] +
  3. ... [(name, 'female') for name in names.words('female.txt')])
  4. >>> import random
  5. >>> random.shuffle(labeled_names)

接下来,我们使用特征提取器处理names数据,并划分特征集的结果链表为一个训练集和一个测试集。训练集用于训练一个新的“朴素贝叶斯”分类器。

  1. >>> featuresets = [(gender_features(n), gender) for (n, gender) in labeled_names]
  2. >>> train_set, test_set = featuresets[500:], featuresets[:500]
  3. >>> classifier = nltk.NaiveBayesClassifier.train(train_set)

在本章的后面,我们将学习更多关于朴素贝叶斯分类器的内容。现在,让我们只是在上面测试一些没有出现在训练数据中的名字:

  1. >>> classifier.classify(gender_features('Neo'))
  2. 'male'
  3. >>> classifier.classify(gender_features('Trinity'))
  4. 'female'

请看 《黑客帝国》 中这些角色的名字被正确分类。尽管这部科幻电影的背景是在 2199 年,但它仍然符合我们有关名字和性别的预期。我们可以在大数据量的未见过的数据上系统地评估这个分类器:

  1. >>> print(nltk.classify.accuracy(classifier, test_set))
  2. 0.77

最后,我们可以检查分类器,确定哪些特征对于区分名字的性别是最有效的:

  1. >>> classifier.show_most_informative_features(5)
  2. Most Informative Features
  3. last_letter = 'a' female : male = 33.2 : 1.0
  4. last_letter = 'k' male : female = 32.6 : 1.0
  5. last_letter = 'p' male : female = 19.7 : 1.0
  6. last_letter = 'v' male : female = 18.6 : 1.0
  7. last_letter = 'f' male : female = 17.3 : 1.0

此列表显示训练集中以 a 结尾的名字中女性是男性的 38 倍,而以 k 结尾名字中男性是女性的 31 倍。这些比率称为似然比,可以用于比较不同特征-结果关系。

注意

轮到你来:修改gender_features()函数,为分类器提供名称的长度、它的第一个字母以及任何其他看起来可能有用的特征。用这些新特征重新训练分类器,并测试其准确性。

在处理大型语料库时,构建一个包含每一个实例的特征的单独的列表会使用大量的内存。在这些情况下,使用函数nltk.classify.apply_features,返回一个行为像一个列表而不会在内存存储所有特征集的对象:

  1. >>> from nltk.classify import apply_features
  2. >>> train_set = apply_features(gender_features, labeled_names[500:])
  3. >>> test_set = apply_features(gender_features, labeled_names[:500])