Doc2Vec & классификация - очень плохие результаты - PullRequest
3 голосов
/ 23 марта 2019

У меня есть набор данных 6000 наблюдений;Пример этого следующий:

job_id      job_title                                           job_sector
30018141    Secondary Teaching Assistant                        Education
30006499    Legal Sales Assistant / Executive                   Sales
28661197    Private Client Practitioner                         Legal
28585608    Senior hydropower mechanical project manager        Engineering
28583146    Warehouse Stock Checker - Temp / Immediate Start    Transport & Logistics
28542478    Security Architect Contract                         IT & Telecoms

Цель состоит в том, чтобы предсказать сектор работы каждой строки на основе названия должности.

Во-первых, я применяю некоторую предварительную обработку к job_title column:

def preprocess(document):
    lemmatizer = WordNetLemmatizer()
    stemmer_1 = PorterStemmer()
    stemmer_2 = LancasterStemmer()
    stemmer_3 = SnowballStemmer(language='english')

    # Remove all the special characters
    document = re.sub(r'\W', ' ', document)

    # remove all single characters
    document = re.sub(r'\b[a-zA-Z]\b', ' ', document)

    # Substituting multiple spaces with single space
    document = re.sub(r' +', ' ', document, flags=re.I)

    # Converting to lowercase
    document = document.lower()

    # Tokenisation
    document = document.split()

    # Stemming
    document = [stemmer_3.stem(word) for word in document]

    document = ' '.join(document)

    return document

df_first = pd.read_csv('../data.csv', keep_default_na=True)

for index, row in df_first.iterrows():

    df_first.loc[index, 'job_title'] = preprocess(row['job_title'])

Затем я делаю следующее с Gensim и Doc2Vec:

X = df_first.loc[:, 'job_title'].values
y = df_first.loc[:, 'job_sector'].values

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=0)

tagged_train = TaggedDocument(words=X_train.tolist(), tags=y_train.tolist())
tagged_train = list(tagged_train)

tagged_test = TaggedDocument(words=X_test.tolist(), tags=y_test.tolist())
tagged_test = list(tagged_test)

model = Doc2Vec(vector_size=5, min_count=2, epochs=30)

training_set = [TaggedDocument(sentence, tag) for sentence, tag in zip(X_train.tolist(), y_train.tolist())]

model.build_vocab(training_set)

model.train(training_set, total_examples=model.corpus_count, epochs=model.epochs)   

test_set = [TaggedDocument(sentence, tag) for sentence, tag in zip(X_test.tolist(), y_test.tolist())]

predictors_train = []
for sentence in X_train.tolist():

    sentence = sentence.split()
    predictor = model.infer_vector(doc_words=sentence, steps=20, alpha=0.01)

    predictors_train.append(predictor.tolist())

predictors_test = []
for sentence in X_test.tolist():

    sentence = sentence.split()
    predictor = model.infer_vector(doc_words=sentence, steps=20, alpha=0.025)

    predictors_test.append(predictor.tolist())

sv_classifier = SVC(kernel='linear', class_weight='balanced', decision_function_shape='ovr', random_state=0)
sv_classifier.fit(predictors_train, y_train)

score = sv_classifier.score(predictors_test, y_test)
print('accuracy: {}%'.format(round(score*100, 1)))

Однако, результат, который я получаю, составляет 22% точности.

Это вызывает у меня много подозрений, особенно потому, что, используя TfidfVectorizer вместо Doc2Vec (оба с одним и тем же классификатором), я получаю точность 88% (!).

Следовательно,Я предполагаю, что я, должно быть, делаю что-то не так, применяя Doc2Vec из Gensim.

Что это такое и как я могу это исправить?

Или это просто, что мойнабор данных относительно мал, в то время как более продвинутые методы, такие как встраивание слов и т. д., требуют гораздо больше данных?

Ответы [ 3 ]

3 голосов
/ 25 марта 2019

Вы не упоминаете размер своего набора данных - в строках, общих словах, уникальных словах или уникальных классах. Doc2Vec лучше всего работает с большим количеством данных. Большинство опубликованных работ составлено из десятков тысяч до миллионов документов, от десятков до тысяч слов в каждом. (Ваши данные содержат только 3-5 слов в документе.)

Кроме того, опубликованная работа имеет тенденцию обучаться на данных, где каждый документ имеет уникальный идентификатор. Иногда имеет смысл использовать известные метки в качестве тегов вместо уникальных идентификаторов или в дополнение к ним. Но это не обязательно лучший подход. Используя в качестве единственных тегов известные ярлыки, вы фактически тренируете только один вектор документа на ярлык. (По сути это похоже на объединение всех строк с одним и тем же тегом в один документ.)

Вы необъяснимо используете меньше steps в выводе, чем epochs в обучении, хотя на самом деле это аналогичные значения. В последних версиях gensim логический вывод будет по умолчанию использовать то же количество эпох логического вывода, что и модель, настроенная для обучения. Кроме того, во время логического вывода чаще используется больше эпох, чем при обучении. (Кроме того, вы необъяснимо используете разные начальные значения alpha для вывода как для обучения классификатора, так и для тестирования классификатора.)

Но главная проблема, вероятно, заключается в выборе крошечных size=5 векторов документов. Вместо TfidfVectorizer, который будет суммировать каждую строку как вектор ширины, равный количеству уникальных слов (возможно, сотням или тысячам измерений), ваша модель Doc2Vec суммирует каждый документ как всего 5 значений. Вы по существу лоботомизировали Doc2Vec. Обычные значения здесь - 100-1000 - хотя, если набор данных крошечный, могут потребоваться меньшие размеры.

Наконец, лемматизация / основание могут не быть строго необходимыми и даже могут быть разрушительными. Многие работы Word2Vec / Doc2Vec не удосуживаются лемматизировать / основываться - часто потому, что имеется множество данных со многими появлениями всех словоформ.

Скорее всего, эти шаги помогут с меньшими данными, поскольку более редкие формы слов объединяются с соответствующими более длинными формами, чтобы по-прежнему получать значение из слов, которые в противном случае были бы слишком редкими для сохранения (или получения полезных векторов).

Но я вижу много способов, как они могут навредить вашему домену. Manager и Management не будут иметь абсолютно одинаковые значения в этом контексте, но оба могут быть ограничены manag. Похоже на Security и Securities, ставших secur, и другими словами. Я выполнил бы эти шаги только в том случае, если вы сможете посредством оценки доказать, что они помогают. (Слова, переданные в TfidfVectorizer, лемматизируются / основываются?)

0 голосов
/ 28 марта 2019

обычно для обучения doc2vec / word2vec требуется много обобщенных данных (word2vec, обученный по 3 миллионным статьям Википедии), так как он плохо работает на doc2vec, подумайте над экспериментами с предварительно обученным doc2vec, см. this

Или вы можете попробовать использовать word2vec и усреднить его для всего документа, поскольку word2vec дает вектор для каждого слова.

Дайте мне знать, как это помогает?

0 голосов
/ 23 марта 2019

Инструменты, которые вы используете, не подходят для классификации. Я бы посоветовал вам взглянуть на что-то вроде персонажа.

https://pytorch.org/tutorials/intermediate/char_rnn_classification_tutorial.html

Этот учебник работает над аналогичной проблемой, где он классифицирует имена.

...