import jieba
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import gridspec
from wordcloud import WordCloud
import numpy as np
from PIL import Image
from gensim.models import Word2Vec
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import accuracy_score, classification_report
import joblib
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
# 读取数据
file_path = r'D:\.AAAA单雨萱重要文件\A大三下\自然语言处理\A课设\新闻分类数据\教育新闻数据.xlsx'
df = pd.read_excel(file_path)
df = df.drop_duplicates()# 去除重复行
df = df.dropna()# 删除含缺失值的行
# 清理文本干扰字符
def clean_text(text):
if isinstance(text, str):
return text.replace("\n", "").replace("\t", "").replace("\xa0", "").replace("\u3000", "")
return ""
df["新闻内容"] = df["新闻内容"].apply(clean_text)
# 绘制各栏目总发布量柱状图
column_counts = df["栏目名称"].value_counts()
plt.figure(figsize=(10, 6))
plt.bar(column_counts.index, column_counts.values)
plt.xlabel("栏目类型"),plt.ylabel("发布数量")
plt.title("各个栏目的新闻发布数量"),plt.xticks(rotation=45)
for x, y in enumerate(column_counts.values):
plt.text(x, y + 2, f"{y}", ha="center", va="bottom", fontsize=9)
plt.tight_layout()
plt.show()
# 处理时间,提取月份
df['发布时间'] = pd.to_datetime(df['发布时间'])
df['月份'] = df['发布时间'].dt.to_period('M')
grouped = df.groupby(['栏目名称', '月份']).size().reset_index(name='发布数量')
pivot_df = grouped.pivot(index='月份', columns='栏目名称', values='发布数量')
# 绘制各栏目各月份折线图
fig=plt.figure(figsize=(12, 7))
gs = gridspec.GridSpec(1, 2, width_ratios=[3, 7])
ax1 = fig.add_subplot(gs[0])
ax1.plot( pivot_df.index.astype(str),pivot_df['滚动'],marker='o',linestyle='--',)
plt.xlabel('月份'),plt.ylabel('发布数量')
plt.title('滚动栏目新闻发布数量变化趋势'),plt.xticks(rotation=45)
plt.legend()
ax2 = fig.add_subplot(gs[1])
markers = ['s', '^', 'D', 'v', '*', 'p','h']
linestyles = ['-.', ':', '-', '--', '-.', ':', '-']
for i, col in enumerate(pivot_df.columns):
if col != '滚动':
# 为每个栏目循环使用不同的标记和线型
marker = markers[i % len(markers)]
linestyle = linestyles[i % len(linestyles)]
plt.plot(pivot_df.index.astype(str),pivot_df[col],marker=marker, linestyle=linestyle, label=col)
plt.xlabel('月份'),plt.ylabel('发布数量')
plt.title('其余栏目新闻发布数量变化趋势'),plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()
# 加载停用词
stopwords = set()
with open('stopword.txt', 'r', encoding='gbk') as f:
for line in f:
stopwords.add(line.strip())
# 补充空格等特殊符号到停用词
stopwords.add(' ')
stopwords.add('\u3000')
def process_text(text):
words = jieba.lcut(text)
# 过滤停用词、空字符串、特殊符号
return [word for word in words if word not in stopwords and word.strip() != '']
# 对新闻内容批量处理
df['分词结果'] = df['新闻内容'].apply(process_text)
# 构建词频统计
all_words = []
for words in df['分词结果']:
all_words.extend(words)
# 统计词频
word_freq = pd.Series(all_words).value_counts()
x = [word for word in all_words if len(word) > 1]
word_freq1 = pd.Series(x).value_counts()
# 绘制词云图
mask = np.array(Image.open('background.jpg'))
wordcloud = WordCloud(font_path=r"C:\WINDOWS\FONTS\SIMHEI.TTF",width=800,height=600,background_color='white',mask=mask).generate_from_frequencies(word_freq)
plt.figure(figsize=(10, 6))
plt.imshow(wordcloud)
plt.axis('off')
plt.title('新闻文本词云图')
plt.tight_layout()
plt.show()
# 绘制排名前10的词语词频饼图
top10_words = word_freq1.head(10)
plt.figure(figsize=(8, 8))
plt.pie(top10_words,labels=top10_words.index,autopct='%.1f%%',startangle=140)
plt.title('排名前10词语词频占比饼图')
plt.tight_layout()
plt.show()
#训练192维词向量模型
print("开始训练192维词向量模型...")
# 提取所有分词结果(格式需为句子列表,每个句子是词语列表)
corpus = df['分词结果'].tolist()
# 配置Word2Vec参数(vector_size=192)
model = Word2Vec(
sentences=corpus,
vector_size=192, # 关键参数:设置192维向量
window=5, # 上下文窗口大小
min_count=2, # 最小词频
workers=4, # 并行线程数
sg=1, # 1表示使用Skip-gram模型
epochs=10 # 训练轮次
)
# 保存训练好的模型
model.save('education_news_word2vec.model')
print("192维词向量模型训练完成,已保存为education_news_word2vec.model")
# 生成文本词向量矩阵
# 定义函数:将单篇新闻的分词转换为192维向量(词向量求和后平均)
def text_to_vector(words):
vector = np.zeros(192) # 初始化192维零向量
valid_words = 0
for word in words:
if word in model.wv: # 只处理在词向量模型中的词
vector += model.wv[word]
valid_words += 1
if valid_words > 0:
return vector / valid_words # 求平均
return vector # 若无有效词,返回零向量
# 对所有新闻生成词向量
print("开始生成新闻文本的192维向量...")
df['word_vector'] = df['分词结果'].apply(text_to_vector)
df.to_pickle('news_with_192d_vectors.pkl')# 保存带词向量的数据集
# 提取特征矩阵和标签
X = np.array(df['word_vector'].tolist()) # 192维特征矩阵
y = df['栏目名称'].values # 分类标签
# 标签编码(将文本标签转为数字)
le = LabelEncoder()
y_encoded = le.fit_transform(y)
# 划分训练集与测试集(80%训练,20%测试)
X_train, X_test, y_train, y_test = train_test_split(
X, y_encoded, test_size=0.2, random_state=42
)
#模型定义与参数调优
models = {
'SVM': SVC(random_state=42),
'K近邻': KNeighborsClassifier(),
'随机森林': RandomForestClassifier(random_state=42)
}
param_grids = {
'SVM': {
'C': [0.1, 1, 10, 100], # 正则化强度
'kernel': ['linear', 'rbf','sigmoid'], # 核函数
'gamma': ['scale', 'auto', 0.1, 0.01] # RBF核参数
},
'K近邻': {
'n_neighbors': [3, 5, 7, 9], # K值
'weights': ['uniform', 'distance'], # 权重策略
'metric': ['euclidean', 'manhattan'] # 距离度量
},
'随机森林': {
'n_estimators': [100, 200, 300], # 树的数量
'max_depth': [None, 10, 20], # 树的最大深度
'min_samples_split': [2, 5, 10] # 分裂节点的最小样本数
}
}
# 存储最佳模型和评估结果
best_models = {}
all_results = {}
# 对每个模型进行网格搜索和交叉验证
for model_name, model in models.items():
print(f"\n=== 开始评估 {model_name} 模型 ===")
# 初始化网格搜索
grid_search = GridSearchCV(
estimator=model,
param_grid=param_grids[model_name],
cv=5, # 5折交叉验证
n_jobs=-1, # 使用所有CPU核心
scoring='accuracy', # 评估指标:准确率
verbose=1 # 输出详细信息
)
# 模型训练
grid_search.fit(X_train, y_train)
# 记录最佳模型和参数
best_model = grid_search.best_estimator_
best_params = grid_search.best_params_
best_cv_score = grid_search.best_score_
best_models[model_name] = best_model
# 在测试集上评估
y_pred = best_model.predict(X_test)
test_accuracy = accuracy_score(y_test, y_pred)
# 输出评估结果
print(f"最佳参数: {best_params}")
print(f"5折交叉验证准确率: {best_cv_score:.4f}")
print(f"测试集准确率: {test_accuracy:.4f}")
print(f"分类报告:\n{classification_report(y_test, y_pred)}")
# 保存结果
all_results[model_name] = {
'params': best_params,
'cv_score': best_cv_score,
'test_accuracy': test_accuracy
}
# 比较各模型的测试集准确率
model_accuracies = {name: results['test_accuracy'] for name, results in all_results.items()}
best_model_name = max(model_accuracies, key=model_accuracies.get)
best_accuracy = model_accuracies[best_model_name]
print(f"\n=== 模型比较结果 ===")
for name, accuracy in model_accuracies.items():
print(f"{name} 测试集准确率: {accuracy:.4f}")
print(f"\n最佳模型: {best_model_name},准确率: {best_accuracy:.4f}")
# # 保存最佳模型到文件
# model_save_path = 'best_education_news_classifier.pkl'
# joblib.dump(best_models[best_model_name], model_save_path)
# print(f"最佳模型已保存至: {model_save_path}")
此代码运行后模型部分结果:
=== 模型比较结果 ===
SVM 测试集准确率: 0.6522
K近邻 测试集准确率: 0.6285
随机森林 测试集准确率: 0.6482
最佳模型: SVM,准确率: 0.6522
给出详细的方法优化准确率,并给出完整代码,不改变输出格式和东西
最新发布