Doc2Vec和分类-结果非常差

时间:2019-03-22 23:51:46

标签: python classification gensim text-classification doc2vec

我有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列上进行了一些预处理:

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'])

然后我对GensimDoc2Vec进行以下操作:

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 个答案:

答案 0 :(得分:3)

您没有提到数据集的大小-行,总单词,唯一单词或唯一类。 Doc2Vec最适合处理大量数据。大多数已出版的工作以数万至数百万的文档进行训练,每个文档数十至数千个单词。 (您的数据似乎每个文档只有3-5个字。)

此外,已发布的工作往往会针对每个文档具有唯一ID的数据进行训练。有时,使用已知标签代替唯一ID或除了唯一ID外,还可以使用已知标签。但这不一定是更好的方法。通过使用已知标签作为唯一标签,您实际上仅在每个标签上训练一个文档向量。 (本质上类似于将具有相同标签的所有行连接到一个文档中。)

在训练中,您莫名其妙地使用steps进行推理,而实际上epochs却是类似的值。在gensim的最新版本中,默认情况下,推理将使用与配置用于训练的模型相同数量的推理纪元。而且,在推理过程中使用 more 个历元比训练更为常见。 (此外,您莫名其妙地使用不同的起始alpha值来进行分类器训练和分类器测试的推断。)

但是主要的问题可能是您选择了较小的size=5文档向量。 TfidfVectorizer模型不是将Doc2Vec总结为宽度等于唯一单词计数(也许是数百个还是数千个维度)的向量的Doc2Vec模型,而是将Word2Vec模型将每个文档总结为5个值。您实际上已经将Doc2Vec设为最低。通常的值是100-1000-尽管如果数据集很小,则可能需要较小的大小。

最后,非严格化/阻止可能不是严格必要的,甚至可能是破坏性的。许多Manager / Management的工作都不会麻烦地去定格/词干-通常是因为存在大量的数据,并且所有词形都很多。

这些步骤最有可能通过确保将较稀有的单词形式与相关的更长的形式结合使用,从而仍然从那些原本很难保留的单词(或获得有用的向量)中获得价值来帮助获得较小的数据。

但是我可以看到它们可能会损害您的域的许多方式。 managSecurity在这种情况下不会有完全相同的含义,但都可以归因于Securities。对于securTfidfVectorizer都变成X = np.array(X, dtype="O")以及其他词来说,类似。如果您可以通过评估证明它们有帮助,我只会执行这些步骤。 (传递给print("You're answer is ", (int(first) + int(second))) 的单词是否被修饰/词根化?)

答案 1 :(得分:0)

通常,要训练doc2vec / word2vec需要大量通用数据(对word2vec进行3篇关于米兰人的Wikipedia文章的培训),因为在doc2vec上表现不佳,请考虑尝试对经过预先训练的doc2vec进行试验,请参考this

或者您可以尝试使用word2vec并将其平均用于整个文档,因为word2vec会为每个单词提供矢量。

让我知道这有什么帮助吗?

答案 2 :(得分:-1)

您使用的工具不适合分类。我建议您调查一下char-rnn之类的东西。

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

本教程适用于类似的问题,在该问题中,对名称进行了分类。