python - Doc2Vec 和分类——结果很差

标签 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% 的准确率 (!) .

因此,我想我一定是在应用 GensimDoc2Vec 时做错了什么。

它是什么以及如何修复它?

或者仅仅是因为我的数据集相对较小,而更高级的方法(例如词嵌入等)需要更多数据?

最佳答案

您没有提及数据集的大小 - 行数、总字数、唯一字数或唯一类别。 Doc2Vec 最适合处理大量数据。大多数已发表的作品都是基于数万至数百万份文件,每份文件包含数十至数千个单词。 (您的数据似乎每个文档只有 3-5 个词。)

此外,已发表的作品倾向于对每个文档都有唯一 ID 的数据进行训练。有时使用已知标签作为标签代替或补充唯一 ID 是有意义的。但这不一定是更好的方法。通过使用已知标签作为唯一的标签,您实际上只为每个标签训练一个文档向量。 (它本质上类似于将具有相同标签的所有行连接到一个文档中。)

你莫名其妙地在推理中使用的 steps 比在训练中使用的 epochs 少 - 事实上这些是类似的值。在 gensim 的最新版本中,默认情况下,推理将使用与模型配置为用于训练的相同数量的推理时期。而且,在推理过程中使用更多 时期比在训练过程中更常见。 (此外,您莫名其妙地使用不同的起始 alpha 值来推断分类器训练和分类器测试。)

但主要问题可能是您选择了微小的 size=5 文档向量。 TfidfVectorizer 将每一行汇总为宽度等于唯一字数的向量——可能有数百或数千个维度——你的 Doc2Vec 模型汇总每个文档仅 5 个值。您基本上已经切除了 Doc2Vec。此处的常用值是 100-1000——但如果数据集很小,可能需要更小的尺寸。

最后,词形还原/词干化可能不是绝对必要的,甚至可能是破坏性的。很多 Word2Vec/Doc2Vec 工作都懒得去词形还原/词干——通常是因为有大量的数据,所有单词形式都有很多出现。

这些步骤最有可能帮助处理较小的数据,方法是确保将较稀有的词形式与相关的较长形式结合起来,以仍然从本来会太稀有而无法保留的词中获取值(value)(或获得有用的向量)。

但我可以看到它们可能会以多种方式损害您的域。 ManagerManagement 在此上下文中的含义并不完全相同,但都可以归结为 manag。类似于 SecuritySecurities 都变成了 secur,等等。如果您可以通过评估证明它们有帮助,我只会执行这些步骤。 (传递给 TfidfVectorizer 的词是否被词形还原/词干化?)

关于python - Doc2Vec 和分类——结果很差,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55309197/

相关文章:

python - 列标题前缀上的 GroupBy 列

python - 使用 Python 比较目录和文本文件

machine-learning - 朴素贝叶斯分类器对于正负类的准确性较差

python-3.x - Gensim doc2vecmost_similar相当于获取完整文档

python - Gensim Word2Vec 令人疲惫不堪的可迭代

python - 如何从 gensim 模型中的 Doc2Vec 相似度分数访问文档详细信息?

python - 迭代时如何获取 2D Numpy 数组中的位置?

python - pandas 使用 .loc 对多列进行条件赋值

apache-spark - 在 Spark MLlib 中处理不平衡数据集

java - 如何提高相对简单的 Java 计数方法的效率和/或性能?