You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发英法双语主题分析器时出现NoneType错误的技术求助

双语主题分析器NoneType错误排查与修复

问题背景

开发一款支持英法双语的主题分析器,采用按语言分类的字典存储分词,但运行时返回NoneType类型值,调整min_df和max_df参数后问题仍未解决。

原代码

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import LatentDirichletAllocation
from langdetect import detect
from scipy import sparse

class Test:
    def __init__(self, lang='bilingual'):
        self.lang = lang
        self.vectorizer = TfidfVectorizer(max_df=0.90, min_df=0.10, max_features=1000, ngram_range=(1, 2))
    def analyze(self, processed_sentences):
        print("Processed sentences: {}".format(processed_sentences))
        tfidf_matrix = self.vectorize(processed_sentences)
        if tfidf_matrix.shape[0] > 0:
            print("TF-IDF vectorizer objects created for {} sentences".format(self.lang))
        else:
            print(tfidf_matrix)
        lda_model = self.topic_modeling(tfidf_matrix)
        print(f"\nTopics:")
        self.plot_topics(lda_model.components_, self.vectorizer)

    def plot_topics(self, topics, tfidf_vectorizer, num_top_words=10):
        """
        Plot the top words for each topic using the given topics, tfidf_vectorizer, and num_top_words.

        Parameters:
            topics (array-like): The topics to be plotted.
            tfidf_vectorizer: The TF-IDF vectorizer used to extract feature names.
            num_top_words (int, optional): The number of top words to display for each topic. Defaults to 10.
        """
        try:
            feature_names = tfidf_vectorizer.get_feature_names_out()
            for topic_id, topic in enumerate(topics):
                print(f"Topic {topic_id + 1}:")
                top_word_indices = topic.argsort()[:-num_top_words - 1:-1]
                top_words = [feature_names[index] for index in top_word_indices]
                print(", ".join(top_words))
        except Exception as e:
            print(f"Error plotting topics: {e}")

    def vectorize(self, documents):
        """
        Vectorizes the given documents using the internal vectorizer and returns the TF-IDF matrix.

        Args:
            documents: A list of documents to be vectorized.

        Returns:
            The TF-IDF matrix representing the vectorized documents.
        """
        try:
            processed_documents = []
            if isinstance(documents, dict):
                # Handle bilingual documents dictionary
                tfidf_matrices = []
                for lang, sentences in documents.items():
                    tfidf_matrix_lang = self.vectorizer.fit_transform(sentences)
                    print(f"TF-IDF matrix created for {lang}!")
                    tfidf_matrices.append(tfidf_matrix_lang)
                # Concatenate the TF-IDF matrices for each language
                tfidf_matrix = sparse.vstack(tfidf_matrices)
            elif isinstance(documents, list):
                # Handle single documents
                for doc in documents:
                    lang = detect(doc)
                    processed_documents.append((doc, lang))
                tfidf_matrix = self.vectorizer.fit_transform([doc for doc, _ in processed_documents])
                print("TF-IDF matrix created!")
            return tfidf_matrix
        except Exception as e:
            print(f"Error while vectorizing documents: {e}")

    def topic_modeling(self, tfidf_matrix, num_topics=5):
        """
        Perform topic modeling on the given TF-IDF matrix using Latent Dirichlet Allocation (LDA) algorithm.

        Parameters:
            tfidf_matrix: The TF-IDF matrix representing the input document-term matrix.
            num_topics: The number of topics to be generated (default is 5).

        Returns:
            lda_model: The trained LDA model for topic modeling.
        """
        try:
            lda_model = LatentDirichletAllocation(n_components=num_topics, max_iter=100, learning_method='batch', random_state=42)
            lda_model.fit(tfidf_matrix)
            print("LDA model built!")
            return lda_model
        except Exception as e:
            print(f"Error while initializing LDA model: {e}")

# Input example
example = {
    'fr': ['soir e', '4', 'novembre', '2019', 's.e.n.c', '.', 'marie-clair', 'pinet', 's.o', '.', '17', '495', 'infiniment', 'monsieur', 'gauthier', '.'],
    'en': ['sam', '2007', 'richard', 'florida', 'sorry', 'jacobin', 'magazine', 'august', '27', '2017']
}
test = Test()
test.analyze(example)

报错信息

Processed sentences: {'fr': ['soir e', '4', 'novembre', '2019', 's.e.n.c', '.', 'marie-clair', 'pinet', 's.o', '.', '17', '495', 'infiniment', 'monsieur', 'gauthier', '.'], 'en': ['sam', '2007', 'richard', 'florida', 'sorry', 'jacobin', 'magazine', 'august', '27', '2017']}
Error while vectorizing documents: After pruning, no terms remain. Try a lower min_df or a higher max_df.
Traceback (most recent call last):
  File "c:\Users\nicol\Documents\UdeM\Maîtrise\Données\scorpion_data\topic_analysis\test_playground.py", line 97, in <module>
    test.analyze(example)
  File "c:\Users\nicol\Documents\UdeM\Maîtrise\Données\scorpion_data\topic_analysis\test_playground.py", line 13, in analyze
    if tfidf_matrix.shape[0] > 0:
       ^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'shape'

问题根源

  1. Vectorizer重复fit导致词汇表丢失
    原代码处理字典时,循环调用self.vectorizer.fit_transform(),每次fit都会重置Vectorizer的词汇表。处理法语后,英语的fit会覆盖原有词汇,最终两种语言没有共同特征,触发"After pruning, no terms remain"错误。异常抛出后,vectorize函数无返回值,默认返回None,导致后续调用tfidf_matrix.shape时触发AttributeError。

  2. 输入数据格式错误
    TF-IDF要求输入元素是完整文档(字符串),但当前输入是单个词/短语的列表,每个"文档"只有一个词。min_df=0.1要求词出现在10%以上的文档中,而每个词仅出现一次,全部被过滤。

修复方案

1. 调整输入格式

将每种语言的分词列表合并为完整文档字符串,或构造多个文档。

2. 统一训练Vectorizer

使用合并后的双语语料训练单个Vectorizer,避免重复fit覆盖词汇表。

3. 异常处理后返回合理默认值

避免None传播导致后续报错。

4. 适配小数据集调整TF-IDF参数

降低min_df至1,关闭特征过滤,适配测试用的小数据集。

修复后代码

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import LatentDirichletAllocation
from scipy import sparse

class BilingualTopicAnalyzer:
    def __init__(self, lang='bilingual'):
        self.lang = lang

    def analyze(self, processed_sentences):
        print("Processed sentences: {}".format(processed_sentences))
        tfidf_info = self.vectorize(processed_sentences)
        if not tfidf_info:
            print("Failed to generate valid TF-IDF matrix")
            return
        
        tfidf_matrix, vectorizer = tfidf_info
        if tfidf_matrix.shape[0] > 0:
            print("TF-IDF matrix created successfully")
        
        lda_model = self.topic_modeling(tfidf_matrix)
        if not lda_model:
            return
        
        print(f"\nTopics:")
        self.plot_topics(lda_model.components_, vectorizer)

    def plot_topics(self, topics, tfidf_vectorizer, num_top_words=5):
        try:
            feature_names = tfidf_vectorizer.get_feature_names_out()
            for topic_id, topic in enumerate(topics):
                print(f"Topic {topic_id + 1}:")
                top_word_indices = topic.argsort()[:-num_top_words -1:-1]
                top_words = [feature_names[index] for index in top_word_indices]
                print(", ".join(top_words))
        except Exception as e:
            print(f"Error plotting topics: {e}")

    def vectorize(self, documents):
        try:
            if isinstance(documents, dict):
                # 将每种语言的分词合并为完整文档
                all_docs = []
                for lang, tokens in documents.items():
                    doc = ' '.join(tokens)
                    all_docs.append(doc)
                
                # 使用适配小数据集的参数训练Vectorizer
                vectorizer = TfidfVectorizer(min_df=1, max_features=1000, ngram_range=(1,2))
                tfidf_matrix = vectorizer.fit_transform(all_docs)
                print("Combined TF-IDF matrix created!")
                return (tfidf_matrix, vectorizer)
            
            elif isinstance(documents, list):
                vectorizer = TfidfVectorizer(min_df=1, max_features=1000, ngram_range=(1,2))
                tfidf_matrix = vectorizer.fit_transform(documents)
                print("TF-IDF matrix created!")
                return (tfidf_matrix, vectorizer)
        except Exception as e:
            print(f"Error while vectorizing documents: {e}")
            return None

    def topic_modeling(self, tfidf_matrix, num_topics=2):
        try:
            if tfidf_matrix.shape[0] == 0 or tfidf_matrix.shape[1] ==0:
                print("Invalid TF-IDF matrix for LDA")
                return None
            # 适配小数据集减少主题数
            lda_model = LatentDirichletAllocation(n_components=num_topics, max_iter=50, learning_method='batch', random_state=42)
            lda_model.fit(tfidf_matrix)
            print("LDA model built!")
            return lda_model
        except Exception as e:
            print(f"Error while building LDA model: {e}")
            return None

# 调整输入:每个语言对应一个完整文档
example = {
    'fr': ['soir e 4 novembre 2019 s.e.n.c . marie-clair pinet s.o . 17 495 infiniment monsieur gauthier .'],
    'en': ['sam 2007 richard florida sorry jacobin magazine august 27 2017']
}
analyzer = BilingualTopicAnalyzer()
analyzer.analyze(example)

内容的提问来源于stack exchange,提问作者9scorp4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 23:48:10