开发英法双语主题分析器时出现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'
问题根源
Vectorizer重复fit导致词汇表丢失
原代码处理字典时,循环调用self.vectorizer.fit_transform(),每次fit都会重置Vectorizer的词汇表。处理法语后,英语的fit会覆盖原有词汇,最终两种语言没有共同特征,触发"After pruning, no terms remain"错误。异常抛出后,vectorize函数无返回值,默认返回None,导致后续调用tfidf_matrix.shape时触发AttributeError。输入数据格式错误
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
相关产品推荐
相关产品推荐

