субота, 3 квітня 2010 р.

Задача №3 розділ №6 "Learning to Classify Text"

Умова задачі:
The Senseval 2 Corpus contains data intended to train word-sense disambiguation
classifiers. It contains data for four words: hard, interest, line, and serve.
Choose one of these four words, and load the corresponding data:
>>> from nltk.corpus import senseval
>>> instances = senseval.instances('hard.pos')
>>> size = int(len(instances) * 0.1)
>>> train_set, test_set = instances[size:], instances[:size]
Using this dataset, build a classifier that predicts the correct sense tag for a given
instance. See the corpus HOWTO at http://www.nltk.org/howto for information
on using the instance objects returned by the Senseval 2 Corpus.

Шлях рішення:
Спочатку здається все просто. instances - це ознаки (features) на основі яких ми можемо тренувати будь-який з класифікаторів. Пробуємо:
>>> import nltk
>>> from nltk.corpus import senseval
>>> instances = senseval.instances('hard.pos')
>>> size = int(len(instances) * 0.1)
>>> train_set, test_set = instances[size:], instances[:size]
>>> classifier = nltk.NaiveBayesClassifier.train(train_set)

Traceback (most recent call last):
File "", line 1, in
classifier = nltk.NaiveBayesClassifier.train(train_set)
File "C:\Python26\lib\site-packages\nltk\classify\naivebayes.py", line 192, in train
for featureset, label in labeled_featuresets:
TypeError: 'SensevalInstance' object is not iterable

!!! Помилка. Використати instances як ознаки (features) не вдалося.
Потрібно розібратися у якому вигляді класифікатор (в даному випадку NaiveBayesClassifier) потребує дані для тренування (train_set)
Беремо будь-який з прикладів з підручника і аналізуємо(приклад сторінка 225):
>>> from nltk.corpus import names
>>> import random
>>> names = ([(name, 'male') for name in names.words('male.txt')] +
[(name, 'female') for name in names.words('female.txt')])
>>> random.shuffle(names)
>>> def gender_features2(name):
features = {}
features["firstletter"] = name[0].lower()
features["lastletter"] = name[-1].lower()
for letter in 'abcdefghijklmnopqrstuvwxyz':
features["count(%s)" % letter] = name.lower().count(letter)
features["has(%s)" % letter] = (letter in name.lower())
return features
>>> featuresets = [(gender_features2(n), g) for (n,g) in names]
>>> train_set, test_set = featuresets[500:], featuresets[:500]
# перевіримо що за змінна train_set
>>> type(train_set)
# тип цієї змінної - список
# скільки елементів у цьому списку
>>> len(train_set)
7444
# багато, поглянемо на один з них
>>> train_set[5]
({'count(u)': 0, 'has(d)': False, 'count(b)': 0, 'count(w)': 0, 'has(b)': False, 'count(l)': 1, 'count(q)': 0, 'count(n)': 0, 'has(j)': False, 'count(s)': 0, 'count(h)': 0, 'has(h)': False, 'has(y)': False, 'count(j)': 0, 'has(f)': False, 'has(o)': False, 'count(x)': 0, 'has(m)': True, 'count(z)': 0, 'has(k)': False, 'has(u)': False, 'count(d)': 0, 'has(s)': False, 'count(f)': 0, 'lastletter': 'a', 'has(q)': False, 'has(w)': False, 'has(e)': False, 'has(z)': False, 'count(t)': 0, 'count(c)': 0, 'has(c)': False, 'has(x)': False, 'count(v)': 0, 'count(m)': 1, 'has(a)': True, 'has(v)': False, 'count(p)': 0, 'count(o)': 0, 'has(i)': False, 'count(i)': 0, 'has(r)': False, 'has(g)': False, 'count(k)': 0, 'firstletter': 'm', 'count(y)': 0, 'has(n)': False, 'has(l)': True, 'count(e)': 0, 'has(t)': False, 'count(g)': 0, 'count(r)': 0, 'count(a)': 2, 'has(p)': False}, 'female')
# структура елементу складна. кортеж, словник, стрічки....
>>> type(train_set[5])
# тип елемента списку train_set - кортеж
>>> len(train_set[5])
2 # цей кортеж складається з двох елементів
>>> type(train_set[5][0])
# тип першого елемента - словник
>>> type(train_set[5][1])
# тип другого елемента - стрічка
Все зрозуміло, за допомогою словника описуються ознаки а за допомогою стрічки описується мітка, яка відповідає цим ознакам.
Тепер потрібно розібратися що таке - instances. Найпростіше почитати HOWTO at http://www.nltk.org/howto як рекомендують автори. Точніше читаємо тут: http://nltk.googlecode.com/svn/trunk/doc/howto/corpus.html#other-corpora
instances - також складний об'єкт. Він складається з окремих SensevalInstance - в яких описано слово (word), позиція цього слова у реченні (position), всі слова речення та їх морфологічні характеристики (context) та значення слова (senses).
Для доступу до елементів SensevalInstance є окремі методи:
.position, .word, .context, .senses
Отже потрібно доступитися до SensevalInstance і перетворити його елементи до вигляду:
Окремий SensevalInstance це буде кортеж, position, word, context, - словник, senses - стрічка.
Пишемо текст програми:
# імпортуємо необхідні для роботи програми модулі
import nltk
import types
from nltk.corpus import senseval
# доступаємся до даних з корпусв
instances = senseval.instances('serve.pos')
features=[]
# перетворюємо instances до потрібного вигляду (списку кортежів кожен з яких складається зі словника та стрічки). Змінна features і буде цим списком.
for inst in instances:
zx=[]
for i in inst.context:
if type(i) == types.TupleType:
zx.append(i)
elif type(i) == types.StringType:
zx.append(("None",i))
a={"word": inst.word,"position": inst.position,}
b=dict(zx)
a.update(b)
features.append((a,' '.join(inst.senses)))
# далі вже все просто
# встановлюємо розмір даних для тестуваня (10%)
size = int(len(features) * 0.1)
# ділимо всі дані на дві частини - для тренування і для тестування
train_set, test_set = features[size:], features[:size]
# тренуємо класифікатор
classifier1 = nltk.NaiveBayesClassifier.train(train_set)
# оцінюємо точність його роботи
print nltk.classify.accuracy(classifier1, test_set)
0.66590389016
# точність - так собі, не дуже
але задачу здається виконали....

Немає коментарів:

Дописати коментар