我有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'])
然后我用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
时做错了。
它是什么,我该如何解决?
或者它只是我的数据集相对较小,而更高级的方法,如字嵌入等需要更多的数据?
您没有提到数据集的大小 - 行,总单词,唯一单词或唯一类。 Doc2Vec最适合大量数据。大多数已发表的作品都训练了数万到数百万个文档,每个文档有数十到数千个单词。 (您的数据似乎每个文档只有3-5个字。)
此外,已发表的工作倾向于训练每个文档都具有唯一ID的数据。有时使用已知标签作为标签而不是唯一ID,或者除了唯一ID之外,有意义。但它不一定是更好的方法。通过使用已知标签作为唯一标签,您实际上每个标签只能训练一个doc-vector。 (它基本上类似于将具有相同标记的所有行连接到一个文档中。)
你在训练中使用的steps
莫名其妙地比epochs
更少 - 实际上这些是类似的值。在gensim
的最新版本中,默认情况下,推理将使用与模型配置用于训练相同数量的推理时期。并且,在推理期间使用更多的时期比训练更常见。 (另外,你莫名其妙地使用不同的起始alpha
值来推断分类器训练和分类器测试。)
但主要的问题是你可能选择微小的size=5
doc向量。而不是TfidfVectorizer
,它将每行汇总为宽度等于唯一字数的矢量 - 可能是数百或数千个维度 - 您的Doc2Vec
模型将每个文档概括为5个值。你基本上已经切割了Doc2Vec
。这里的常用值为100-1000 - 但如果数据集很小,则可能需要更小的尺寸。
最后,词义化/词干化可能不是严格必要的,甚至可能是破坏性的。很多Word2Vec
/ Doc2Vec
的工作并不打扰lemmatize / stem - 通常是因为有大量的数据,所有单词形式的出现很多。
这些步骤最有可能帮助处理较小的数据,通过确保较少的单词形式与相关的较长形式相结合,仍然可以从单词获得价值,否则这些单词将难以保留(或获得有用的向量)。
但我可以看到他们可能会为您的域名造成多种伤害。在这方面,Manager
和Management
不会有完全相同的含义,但两者都可以源于manag
。类似于Security
和Securities
都成为secur
,换句话说。如果你能通过评估证明他们正在帮助我,我只会执行这些步骤。 (传递给TfidfVectorizer
的词是被lemmatized / stemmed?)
通常培训doc2vec / word2vec需要大量的通用数据(word2vec受过3百万维基百科文章的训练),因为它在doc2vec上表现不佳考虑尝试使用预先训练过的doc2vec参考this
或者您可以尝试使用word2vec并将其平均为整个文档,因为word2vec为每个单词提供向量。
让我知道这有什么帮助?
您使用的工具不适合分类。我建议你看看像char-rnn这样的东西。
https://pytorch.org/tutorials/intermediate/char_rnn_classification_tutorial.html
本教程适用于类似的问题,它对名称进行了分类。