本文目录导读:

进行分类的实现。
完整的Python实现
import os
import re
import math
from collections import defaultdict, Counter
import pickle
class NaiveBayesClassifier:
def __init__(self, alpha=1.0):
"""
初始化朴素贝叶斯分类器
alpha: 拉普拉斯平滑参数
"""
self.alpha = alpha
self.class_probabilities = {} # P(类别)
self.word_probabilities = {} # P(单词|类别)
self.classes = []
self.vocabulary = set()
def _tokenize(self, text):
"""文本预处理和分词"""
# 转为小写
text = text.lower()
# 去除标点符号和数字
text = re.sub(r'[^\w\s]', ' ', text)
text = re.sub(r'\d+', ' ', text)
# 分词
tokens = text.split()
# 去除停用词(可以根据需要扩充)
stop_words = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'by', 'with', 'from'}
tokens = [t for t in tokens if t not in stop_words and len(t) > 2]
return tokens
def _read_file(self, filepath):
"""读取文件内容"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
return f.read()
except UnicodeDecodeError:
# 尝试其他编码
try:
with open(filepath, 'r', encoding='latin-1') as f:
return f.read()
except Exception as e:
print(f"Error reading file {filepath}: {e}")
return ""
def train_from_directory(self, directory_path):
"""
从目录结构训练模型
目录结构:
train/
category1/
file1.txt
file2.txt
category2/
file3.txt
...
"""
# 获取所有类别
self.classes = [d for d in os.listdir(directory_path)
if os.path.isdir(os.path.join(directory_path, d))]
# 统计每个类别的文档数量和单词数量
class_doc_count = defaultdict(int)
class_word_count = defaultdict(Counter)
total_docs = 0
# 遍历所有文件
for category in self.classes:
category_path = os.path.join(directory_path, category)
for filename in os.listdir(category_path):
filepath = os.path.join(category_path, filename)
if os.path.isfile(filepath):
content = self._read_file(filepath)
if content:
tokens = self._tokenize(content)
class_doc_count[category] += 1
class_word_count[category].update(tokens)
self.vocabulary.update(tokens)
total_docs += 1
# 计算类先验概率 P(类别)
self.class_probabilities = {
c: count / total_docs
for c, count in class_doc_count.items()
}
# 计算条件概率 P(单词|类别) 使用拉普拉斯平滑
vocab_size = len(self.vocabulary)
self.word_probabilities = {}
for category in self.classes:
word_counts = class_word_count[category]
total_words = sum(word_counts.values())
self.word_probabilities[category] = {}
for word in self.vocabulary:
# 使用拉普拉斯平滑
word_prob = (word_counts.get(word, 0) + self.alpha) / (total_words + self.alpha * vocab_size)
self.word_probabilities[category][word] = word_prob
print(f"训练完成!共 {total_docs} 个文档,{vocab_size} 个唯一词汇,{len(self.classes)} 个类别")
def predict(self, text_or_filepath):
"""
预测文本或文件的类别
返回: (预测类别, 各类别概率)
"""
# 如果是文件路径,读取文件内容
if os.path.isfile(text_or_filepath):
text = self._read_file(text_or_filepath)
else:
text = text_or_filepath
# 分词
tokens = self._tokenize(text)
if not tokens:
return None, {}
# 计算每个类别的对数概率
log_probabilities = {}
for category in self.classes:
# 初始化为对数类先验概率
log_prob = math.log(self.class_probabilities[category])
# 加上每个词的对数条件概率
for token in tokens:
if token in self.vocabulary:
log_prob += math.log(self.word_probabilities[category].get(token, self.alpha))
log_probabilities[category] = log_prob
# 计算实际概率(用于返回)
probabilities = self._softmax(log_probabilities)
# 选择概率最大的类别
predicted_class = max(probabilities, key=probabilities.get)
return predicted_class, probabilities
def _softmax(self, log_probs):
"""将对数概率转换为实际概率"""
# 找到最大值避免数值溢出
max_log = max(log_probs.values())
exp_probs = {c: math.exp(log_p - max_log) for c, log_p in log_probs.items()}
total = sum(exp_probs.values())
return {c: p / total for c, p in exp_probs.items()}
def save_model(self, filepath):
"""保存模型"""
model = {
'class_probabilities': self.class_probabilities,
'word_probabilities': self.word_probabilities,
'classes': self.classes,
'vocabulary': self.vocabulary,
'alpha': self.alpha
}
with open(filepath, 'wb') as f:
pickle.dump(model, f)
print(f"模型已保存到 {filepath}")
def load_model(self, filepath):
"""加载模型"""
with open(filepath, 'rb') as f:
model = pickle.load(f)
self.class_probabilities = model['class_probabilities']
self.word_probabilities = model['word_probabilities']
self.classes = model['classes']
self.vocabulary = model['vocabulary']
self.alpha = model['alpha']
print(f"模型已从 {filepath} 加载")
def evaluate(self, test_dir):
"""评估模型性能"""
correct = 0
total = 0
confusion_matrix = defaultdict(lambda: defaultdict(int))
for actual_class in self.classes:
class_path = os.path.join(test_dir, actual_class)
if not os.path.isdir(class_path):
continue
for filename in os.listdir(class_path):
filepath = os.path.join(class_path, filename)
if os.path.isfile(filepath):
predicted, _ = self.predict(filepath)
if predicted == actual_class:
correct += 1
confusion_matrix[actual_class][predicted] += 1
total += 1
accuracy = correct / total if total > 0 else 0
print(f"准确率: {accuracy:.2%} ({correct}/{total})")
# 打印混淆矩阵
print("\n混淆矩阵:")
print("真实\\预测", end="\t")
for c in self.classes:
print(c[:8], end="\t")
print()
for true_class in self.classes:
print(true_class[:8], end="\t")
for pred_class in self.classes:
print(confusion_matrix[true_class][pred_class], end="\t")
print()
return accuracy, confusion_matrix
使用示例
# 1. 创建数据目录结构
"""
train/
spam/
email1.txt
email2.txt
ham/
email3.txt
email4.txt
test/
spam/
email5.txt
ham/
email6.txt
"""
# 批量创建测试文件
import os
def create_sample_data():
"""创建示例数据集"""
# 创建目录
for category in ['spam', 'ham']:
os.makedirs(f'train/{category}', exist_ok=True)
os.makedirs(f'test/{category}', exist_ok=True)
# 创建示例文件
spam_samples = [
"Buy cheap medicine now!!! Limited offer",
"You have won a free prize! Click here",
"Make money fast, work from home",
"Urgent! Your account needs verification"
]
ham_samples = [
"Meeting scheduled for tomorrow at 2pm",
"Please review the attached document",
"Thanks for your help with the project",
"Can we reschedule our appointment?"
]
# 写入训练数据
for i, text in enumerate(spam_samples[:3]):
with open(f'train/spam/spam_{i}.txt', 'w') as f:
f.write(text)
for i, text in enumerate(ham_samples[:3]):
with open(f'train/ham/ham_{i}.txt', 'w') as f:
f.write(text)
# 写入测试数据
with open('test/spam/test_spam.txt', 'w') as f:
f.write(spam_samples[3])
with open('test/ham/test_ham.txt', 'w') as f:
f.write(ham_samples[3])
# 2. 使用分类器
def main():
# 创建示例数据
create_sample_data()
# 初始化分类器
classifier = NaiveBayesClassifier(alpha=1.0)
# 训练模型
classifier.train_from_directory('train')
# 测试单个文件
result, probs = classifier.predict('test/spam/test_spam.txt')
print(f"\n预测结果: {result}")
print("各类别概率:")
for cat, prob in probs.items():
print(f" {cat}: {prob:.4f}")
# 预测新文本
new_text = "This is a normal message about work"
result, probs = classifier.predict(new_text)
print(f"\n新文本预测: {result}")
print(f"概率: {probs}")
# 评估模型
classifier.evaluate('test')
# 保存模型
classifier.save_model('nb_model.pkl')
# 加载模型
new_classifier = NaiveBayesClassifier()
new_classifier.load_model('nb_model.pkl')
# 使用加载的模型预测
result, probs = new_classifier.predict("Limited offer! Don't miss out!")
print(f"\n加载模型后预测: {result}")
# 清理示例文件
import shutil
for dir in ['train', 'test']:
shutil.rmtree(dir)
if os.path.exists('nb_model.pkl'):
os.remove('nb_model.pkl')
if __name__ == "__main__":
main()
高级功能扩展
class AdvancedNaiveBayes(NaiveBayesClassifier):
"""增强版朴素贝叶斯"""
def __init__(self, alpha=1.0, use_bigram=False, stop_words_file=None):
super().__init__(alpha)
self.use_bigram = use_bigram
self.stop_words = self._load_stop_words(stop_words_file) if stop_words_file else set()
def _load_stop_words(self, filepath):
"""从文件加载停用词"""
with open(filepath, 'r', encoding='utf-8') as f:
return set(f.read().splitlines())
def _tokenize(self, text):
"""增强的分词功能,支持n-gram"""
# 基础处理
tokens = super()._tokenize(text)
# 去除停用词
tokens = [t for t in tokens if t not in self.stop_words]
# 可选:生成bigram
if self.use_bigram and len(tokens) > 1:
bigrams = ['_'.join(tokens[i:i+2]) for i in range(len(tokens)-1)]
tokens.extend(bigrams)
return tokens
def feature_selection(self, min_df=2, max_df=0.8):
"""特征选择:基于文档频率"""
# 计算每个词的出现文档数
word_doc_count = Counter()
total_docs = sum(self.class_probabilities.values())
for category in self.word_probabilities:
for word, prob in self.word_probabilities[category].items():
if prob > 0:
word_doc_count[word] += 1
# 过滤词汇
filtered_vocab = set()
for word, count in word_doc_count.items():
doc_freq = count / total_docs
if min_df <= count and doc_freq <= max_df:
filtered_vocab.add(word)
# 更新词汇表
self.vocabulary = filtered_vocab
# 重新计算概率
for category in self.word_probabilities:
self.word_probabilities[category] = {
word: prob
for word, prob in self.word_probabilities[category].items()
if word in filtered_vocab
}
print(f"特征选择后词汇量: {len(self.vocabulary)}")
批量处理多个文件
def batch_predict_files(classifier, file_list, output_file=None):
"""批量预测多个文件"""
results = []
for filepath in file_list:
if os.path.isfile(filepath):
predicted_class, probabilities = classifier.predict(filepath)
results.append({
'file': filepath,
'predicted': predicted_class,
'confidence': max(probabilities.values()) if probabilities else 0,
'probabilities': probabilities
})
# 可选:保存结果到文件
if output_file:
with open(output_file, 'w', encoding='utf-8') as f:
f.write("文件\t预测类别\t置信度\n")
for result in results:
f.write(f"{result['file']}\t{result['predicted']}\t{result['confidence']:.4f}\n")
return results
# 使用示例
# results = batch_predict_files(classifier, ['file1.txt', 'file2.txt', 'file3.txt'], 'predictions.txt')
关键技术点总结
- 拉普拉斯平滑: 避免零概率问题
- 对数概率: 防止数值下溢
- 文本预处理: 分词、停用词过滤
- 模型持久化: 保存和加载训练好的模型
- 性能评估: 准确率、混淆矩阵
这个实现可以根据具体需求进行调整,比如词干提取、TF-IDF特征、增量学习等改进。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播