【问题标题】:How do I make train and test set the same size using bag of words如何使用词袋使训练集和测试集大小相同
【发布时间】:2021-05-11 22:05:02
【问题描述】:

我想使用词袋来训练回归模型。但是,我不想在我的训练集和测试集之间发生信息泄漏。所以,这意味着我需要在训练集上创建一个与我的测试集分开的词向量。我运行了这段代码

def bow (tokens, data):
    tokens = tokens.apply(nltk.word_tokenize)
    cvec = CountVectorizer(min_df = .01, max_df = .95, ngram_range=(1,2), tokenizer=lambda doc:doc, lowercase=False)
    cvec.fit(tokens)
    cvec_counts = cvec.transform(tokens)
    cvec_counts_bow = cvec_counts.toarray()
    vocab = cvec.get_feature_names()
    bow_model = pd.DataFrame(cvec_counts_bow, columns=vocab)
    return bow_model

X_train = bow(train['clean_text'], train)
X_test = bow(test['clean_text'], test)

vocab = list(X_train.columns)

但我的数据框的形状是 X_train: (300, 730) 和 X_test (35, 1661) 我的测试集中有比我的训练集更多的独特词——因为训练集太小——而且这些词不匹配。 X_train 中有一些词不在 X_test 中,反之亦然。我想从 X_train 创建一个词汇表,然后只保留 X_test 中的列,但这似乎不对。

如何将 X_train 中的词汇表拟合到 X_test 中?

【问题讨论】:

    标签: tensorflow keras nlp token vectorization


    【解决方案1】:

    看起来您为训练集和测试集创建了不同的词汇。 您可以尝试从 bow 函数中移动下一个代码,并仅创建一个基于 train set 的词汇。你也不需要使用 nltk.word_tokenize 因为 CountVectorizer 已经有标记器:

    cvec = CountVectorizer(min_df = .01, max_df = .95, ngram_range=(1,2), lowercase=False)
    cvec.fit(train['clean_text'])
    vocab = cvec.get_feature_names() 
    print(vocab)
    

    然后改变弓的功能:

    def bow (tokens, vocab, cvec):
        cvec_counts = cvec.transform(tokens)
        cvec_counts_bow = cvec_counts.toarray()
        bow_model = pd.DataFrame(cvec_counts_bow, columns=vocab)
        return bow_model
    
    X_train = bow(train['clean_text'], vocab, cvec)
    X_test = bow(test['clean_text'], vocab, cvec)
    

    或者看看我是怎么做到的。

    首先,我只使用训练集创建词汇。我也只使用了这个集合和其他集合中更常见的词,比如'<UNK>'

    您可以为此使用下一个代码:

     def create_vocab(all_tokens, vocab_size):   
         token_counts = Counter(all_tokens)   
         token_counts = token_counts.most_common()[:vocab_size]   
         vocab_list = ['<UNK>'] + [token for token, _ in token_counts]   
         return vocab_list
    

    在创建词汇之后,我将它用于像这样的词袋:

     def bag_of_words(tokens, vocab_list):
         result = [0] * len(vocab_list)
         for t in tokens:
           if t not in vocab_list:
             t = '<UNK>'
         result[vocab_list.index(t)] += 1
         return result
    

    使用此代码,我创建了一个单词包,其中包括我的词汇中的所有单词(仅使用火车组创建)和'&lt;UNK&gt;' 符号用于不在我的词汇中的单词。

    有一个我如何运行此代码的示例:

    vocab_list = create_vocab(list(chain.from_iterable(tokens_train)), 5000)
    
    bag_of_words_train = []
    for token in tokens_train:
      bag_of_words_train.append(bag_of_words(token, vocab_list))
    
    bag_of_words_test = []
    for token in tokens_test:
      bag_of_words_test.append(bag_of_words(token, vocab_list))
    

    【讨论】:

    • @olesiaslavchnyk 非常感谢!!! I got the first option to run successfully but not the second with .我一定是做错了什么——我的 bag_of_words_train 和 bag_of_words_test 是一系列 0。此外,词汇表是单字母表。我怎样才能得到二元组呢?我添加了``` tokens_train = X_train['text'].apply(nltk.word_tokenize) tokens_test = X_test['text'].apply(nltk.word_tokenize) ```
    • @KimS。您可以添加 ngram_range=(1, 2) 作为 CountVectorizer 的参数以获取 unigrams 和 bi-grams 或 ngram_range=(2, 2) 以仅获取 bi-grams。您还确定使用 nltk.word_tokenize 创建的 tokens_train 和 tokens_test 与您的词汇中的标记相同吗?我相信不使用nltk.word_tokenize会更好。
    • @olesiaslavchnyk 我想我对您如何创建 tokens_train 感到困惑。当我尝试按原样运行代码时,我收到 tokens_train 不存在的错误。我从“def create_vocab ...”开始到最后一行代码。你知道我错过了什么吗?
    猜你喜欢
    • 2013-06-18
    • 2012-11-21
    • 2012-07-21
    • 1970-01-01
    • 2020-05-28
    • 2019-08-21
    • 1970-01-01
    • 2019-06-16
    • 2020-01-21
    相关资源
    最近更新 更多