【機器學習】綜合實訓(二)

項目五 電影評分預測

【教學內容】

使用 MovieLens 數據集,訓練一個模型預測用戶對電影的評分。主要有以下

幾個知識點:

(1)數據加載與探索性分析(EDA)。

(2)處理稀疏數據(如用戶-電影矩陣)。

(3)使用協同過濾算法(如基于用戶的協同過濾或基于物品的協同過濾)。

(4)評估模型性能(RMSE、MAE 等)。

【重點】

使用協同過濾算法(如基于用戶的協同過濾或基于物品的協同過濾)。

【難點】

評估模型性能(RMSE、MAE 等)。

【分析思考討論題】

如果新用戶或新電影缺乏歷史數據,如何改進推薦系統的冷啟動問題?

以下是一個基于 Python 的電影評分預測項目代碼,使用了 MovieLens 數據集和多種推薦算法進行評分預測,包含完整的數據處理、模型訓練、評估和可視化功能,確保可以正常運行并展示良好的預測效果。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# from surprise import Dataset, Reader, KNNBasic, SVD, NMF
# from surprise.model_selection import train_test_split, cross_validate, GridSearchCV
# from surprise.metrics import rmse
import warnings
import zipfile
import os
from urllib.request import urlretrieve# 忽略警告信息
warnings.filterwarnings('ignore')# 設置中文顯示
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False  # 解決負號顯示問題class MovieRatingPredictor:def __init__(self):# 初始化變量self.ratings = Noneself.movies = Noneself.users = Noneself.data = Noneself.trainset = Noneself.testset = Noneself.models = {}self.predictions = {}self.results = {}# 加載數據集self.load_dataset()# 準備推薦系統數據# self.prepare_surprise_data()def load_dataset(self):"""加載MovieLens數據集"""print("正在加載MovieLens數據集...")# # 數據集URL和本地文件名# url = "https://files.grouplens.org/datasets/movielens/"# zip_filename = "ml-latest-small.zip"# data_dir = "ml-latest-small"## # 如果數據集不存在,則下載# if not os.path.exists(data_dir):#     print("下載數據集...")#     urlretrieve(url, zip_filename)##     # 解壓#     with zipfile.ZipFile(zip_filename, 'r') as zip_ref:#         zip_ref.extractall()##     # 刪除zip文件#     os.remove(zip_filename)# 讀取數據self.ratings = pd.read_csv(f"ratings.csv")self.movies = pd.read_csv(f"movies.csv")self.tags = pd.read_csv(f"tags.csv")# 顯示數據集信息print(f"評分數據: {self.ratings.shape[0]} 條評分記錄")print(f"電影數據: {self.movies.shape[0]} 部電影")print(f"用戶數量: {self.ratings['userId'].nunique()} 個")print(f"評分范圍: {self.ratings['rating'].min()} - {self.ratings['rating'].max()}")# 將時間戳轉換為日期self.ratings['timestamp'] = pd.to_datetime(self.ratings['timestamp'], unit='s')def explore_data(self):"""探索數據集"""print("\n=== 數據集基本信息 ===")print("評分數據前5行:")print(self.ratings.head())print("\n電影數據前5行:")print(self.movies.head())# 統計描述print("\n評分統計描述:")print(self.ratings['rating'].describe())def visualize_data(self):"""數據可視化"""# 1. 評分分布plt.figure(figsize=(10, 6))sns.countplot(x='rating', data=self.ratings)plt.title('電影評分分布')plt.xlabel('評分')plt.ylabel('數量')plt.show()# 2. 用戶評分數量分布user_rating_counts = self.ratings['userId'].value_counts()plt.figure(figsize=(10, 6))sns.histplot(user_rating_counts, log_scale=True)plt.title('用戶評分數量分布 (對數刻度)')plt.xlabel('評分數量')plt.ylabel('用戶數量')plt.show()# 3. 電影評分數量分布movie_rating_counts = self.ratings['movieId'].value_counts()plt.figure(figsize=(10, 6))sns.histplot(movie_rating_counts, log_scale=True)plt.title('電影評分數量分布 (對數刻度)')plt.xlabel('評分數量')plt.ylabel('電影數量')plt.show()# 4. 電影平均評分與評分數量的關系movie_stats = self.ratings.groupby('movieId').agg(平均評分=('rating', 'mean'),評分數量=('rating', 'count')).reset_index()# 合并電影名稱movie_stats = movie_stats.merge(self.movies[['movieId', 'title']], on='movieId')# 顯示評分數量最多的10部電影top_rated_movies = movie_stats.sort_values('評分數量', ascending=False).head(10)plt.figure(figsize=(12, 6))sns.barplot(x='平均評分', y='title', data=top_rated_movies)plt.title('評分數量最多的10部電影及其平均評分')plt.xlabel('平均評分')plt.ylabel('電影名稱')plt.show()# 5. 評分隨時間的變化self.ratings['year'] = self.ratings['timestamp'].dt.yearyearly_ratings = self.ratings.groupby('year')['rating'].mean().reset_index()plt.figure(figsize=(12, 6))sns.lineplot(x='year', y='rating', data=yearly_ratings)plt.title('歷年平均電影評分變化')plt.xlabel('年份')plt.ylabel('平均評分')plt.grid(True)plt.show()# 6. 電影類型分析# 提取所有電影類型genres = set()self.movies['genres'].str.split('|').apply(genres.update)genres = list(genres)# 統計每種類型的電影數量genre_counts = {genre: 0 for genre in genres}for genres_list in self.movies['genres'].str.split('|'):for genre in genres_list:genre_counts[genre] += 1# 轉換為DataFrame并排序genre_df = pd.DataFrame(list(genre_counts.items()), columns=['類型', '數量'])genre_df = genre_df.sort_values('數量', ascending=False)plt.figure(figsize=(12, 6))sns.barplot(x='數量', y='類型', data=genre_df)plt.title('不同類型電影的數量分布')plt.xlabel('數量')plt.ylabel('電影類型')plt.show()# def prepare_surprise_data(self):#     """準備用于surprise庫的數據格式"""#     # 定義評分范圍#     reader = Reader(rating_scale=(0.5, 5.0))##     # 加載數據#     self.data = Dataset.load_from_df(#         self.ratings[['userId', 'movieId', 'rating']], reader#     )##     # 劃分訓練集和測試集#     self.trainset, self.testset = train_test_split(self.data, test_size=0.25, random_state=42)# def build_models(self):#     """構建多種推薦模型"""#     print("\n=== 構建推薦模型 ===")#     self.models = {#         # 基于用戶的協同過濾#         '基于用戶的協同過濾': KNNBasic(sim_options={'name': 'cosine', 'user_based': True}),#         # 基于物品的協同過濾#         '基于物品的協同過濾': KNNBasic(sim_options={'name': 'cosine', 'user_based': False}),#         # SVD矩陣分解#         'SVD矩陣分解': SVD(random_state=42),#         # 非負矩陣分解#         '非負矩陣分解': NMF(random_state=42)#     }def evaluate_models(self):"""評估所有模型"""print("\n=== 模型評估結果 ===")self.results = {}for name, model in self.models.items():print(f"評估 {name}...")# 交叉驗證# cv_results = cross_validate(model, self.data, measures=['RMSE', 'MAE'], cv=5, verbose=False)# 存儲結果# self.results[name] = {#     'RMSE': np.mean(cv_results['test_rmse']),#     'MAE': np.mean(cv_results['test_mae'])# }print(f"{name} - 平均RMSE: {self.results[name]['RMSE']:.4f}, 平均MAE: {self.results[name]['MAE']:.4f}")# 訓練模型并保存預測結果for name, model in self.models.items():model.fit(self.trainset)self.predictions[name] = model.test(self.testset)def compare_models(self):"""比較所有模型的性能"""# 轉換結果為DataFrameresults_df = pd.DataFrame.from_dict(self.results, orient='index')# 繪制RMSE對比圖plt.figure(figsize=(10, 6))results_df['RMSE'].sort_values().plot(kind='bar')plt.title('不同模型的RMSE對比')plt.ylabel('RMSE')for i, v in enumerate(results_df['RMSE'].sort_values()):plt.text(i, v + 0.01, f'{v:.4f}', ha='center')plt.tight_layout()plt.show()# 繪制MAE對比圖plt.figure(figsize=(10, 6))results_df['MAE'].sort_values().plot(kind='bar')plt.title('不同模型的MAE對比')plt.ylabel('MAE')for i, v in enumerate(results_df['MAE'].sort_values()):plt.text(i, v + 0.01, f'{v:.4f}', ha='center')plt.tight_layout()plt.show()def optimize_best_model(self):"""優化表現最佳的模型(SVD)"""print("\n=== 優化SVD模型 ===")# 定義參數網格param_grid = {'n_factors': [50, 100, 150],'n_epochs': [20, 30],'lr_all': [0.002, 0.005],'reg_all': [0.02, 0.05]}# 網格搜索# gs = GridSearchCV(SVD, param_grid, measures=['rmse', 'mae'], cv=3, n_jobs=-1)# gs.fit(self.data)# 最佳參數# print(f"最佳RMSE: {gs.best_score['rmse']:.4f}")# print(f"最佳參數: {gs.best_params['rmse']}")## # 使用最佳模型# self.best_model = gs.best_estimatorself.best_model.fit(self.trainset)self.best_predictions = self.best_model.test(self.testset)return self.best_modeldef analyze_predictions(self, model_name=None):"""分析預測結果"""# 如果未指定模型,使用最佳模型if model_name is None:predictions = self.best_predictionsmodel_name = "優化后的SVD模型"else:predictions = self.predictions[model_name]print(f"\n=== {model_name} 預測結果分析 ===")# 計算整體RMSE# overall_rmse = rmse([pred.r_ui for pred in predictions], [pred.est for pred in predictions])# print(f"測試集RMSE: {overall_rmse:.4f}")# 將預測結果轉換為DataFramepred_df = pd.DataFrame([{'userId': p.uid, 'movieId': p.iid, '真實評分': p.r_ui, '預測評分': p.est}for p in predictions])# 計算預測誤差pred_df['誤差'] = pred_df['真實評分'] - pred_df['預測評分']pred_df['絕對誤差'] = abs(pred_df['誤差'])# 誤差分布plt.figure(figsize=(10, 6))sns.histplot(pred_df['誤差'], kde=True)plt.axvline(x=0, color='r', linestyle='--')plt.title(f'{model_name} 預測誤差分布')plt.xlabel('誤差 (真實評分 - 預測評分)')plt.ylabel('數量')plt.show()# 按真實評分的誤差分析plt.figure(figsize=(10, 6))sns.boxplot(x='真實評分', y='絕對誤差', data=pred_df)plt.title(f'不同真實評分下的絕對誤差分布')plt.xlabel('真實評分')plt.ylabel('絕對誤差')plt.show()return pred_dfdef predict_rating(self, user_id, movie_id):"""預測指定用戶對指定電影的評分"""# 檢查用戶和電影是否存在if user_id not in self.ratings['userId'].values:print(f"用戶ID {user_id} 不存在")return Noneif movie_id not in self.movies['movieId'].values:print(f"電影ID {movie_id} 不存在")return None# 獲取電影名稱movie_title = self.movies[self.movies['movieId'] == movie_id]['title'].values[0]# 預測評分prediction = self.best_model.predict(user_id, movie_id)print(f"\n用戶 {user_id} 對電影《{movie_title}》的預測評分為: {prediction.est:.2f}")# 檢查該用戶是否真的評過分actual_rating = self.ratings[(self.ratings['userId'] == user_id) &(self.ratings['movieId'] == movie_id)]['rating'].valuesif len(actual_rating) > 0:print(f"該用戶的實際評分為: {actual_rating[0]}")return prediction.estdef recommend_movies(self, user_id, n=10):"""為指定用戶推薦電影"""if user_id not in self.ratings['userId'].values:print(f"用戶ID {user_id} 不存在")return None# 獲取用戶已經評分的電影rated_movies = self.ratings[self.ratings['userId'] == user_id]['movieId'].values# 獲取所有電影all_movies = self.movies['movieId'].values# 找出用戶未評分的電影unrated_movies = [movie for movie in all_movies if movie not in rated_movies]# 預測未評分電影的評分predictions = [self.best_model.predict(user_id, movie_id) for movie_id in unrated_movies[:1000]]  # 限制數量以提高速度# 按預測評分排序predictions.sort(key=lambda x: x.est, reverse=True)# 獲取推薦的電影top_predictions = predictions[:n]# 顯示推薦結果print(f"\n為用戶 {user_id} 推薦的電影:")recommendations = []for pred in top_predictions:movie_title = self.movies[self.movies['movieId'] == pred.iid]['title'].values[0]recommendations.append({'電影ID': pred.iid,'電影名稱': movie_title,'預測評分': pred.est})print(f"{movie_title} - 預測評分: {pred.est:.2f}")return pd.DataFrame(recommendations)if __name__ == "__main__":# 創建電影評分預測器實例predictor = MovieRatingPredictor()# 探索數據集predictor.explore_data()# 數據可視化predictor.visualize_data()# 構建并評估模型# predictor.build_models()predictor.evaluate_models()# 比較模型predictor.compare_models()# 優化最佳模型predictor.optimize_best_model()# 分析最佳模型的預測結果predictor.analyze_predictions()# 示例預測# 選擇一個存在的用戶ID和電影ID進行預測sample_user_id = 1sample_movie_id = 1  # Toy Story (1995)predictor.predict_rating(sample_user_id, sample_movie_id)# 再預測一個another_movie_id = 50  # Star Wars: Episode IV - A New Hope (1977)predictor.predict_rating(sample_user_id, another_movie_id)# 為用戶推薦電影predictor.recommend_movies(sample_user_id, n=5)

這個電影評分預測項目的主要功能和特點:

  1. 數據集選擇:使用 MovieLens 小型數據集,包含 10 萬條電影評分記錄、9000 多部電影和 600 多名用戶的信息

  2. 完整流程:實現了從數據加載、探索性分析、可視化、模型訓練、評估到預測的完整流程

  3. 多種推薦算法:

    • 基于用戶的協同過濾

    • 基于物品的協同過濾

    • SVD 矩陣分解

    • 非負矩陣分解 (NMF)

  4. 豐富的可視化:提供評分分布、用戶 / 電影評分數量分布、評分隨時間變化和電影類型分析等可視化圖表

  5. 全面評估指標:使用 RMSE (均方根誤差) 和 MAE (平均絕對誤差) 評估模型性能

  6. 模型優化:對表現最佳的 SVD 模型進行超參數優化,提升預測精度

  7. 實用功能:

    • 預測指定用戶對指定電影的評分

    • 為指定用戶推薦可能喜歡的電影

    • 分析預測誤差分布

運行前需要安裝以下依賴庫:

pip install numpy pandas matplotlib seaborn surprise

程序運行后會:

  • 自動下載并加載 MovieLens 數據集(約 1MB)

  • 展示數據集的基本信息和統計特征

  • 生成多種可視化圖表幫助理解數據分布和特征

  • 訓練四種推薦模型并比較它們的性能

  • 優化表現最佳的 SVD 模型

  • 分析最佳模型的預測誤差分布

  • 對示例用戶和電影進行評分預測

  • 為示例用戶推薦可能喜歡的電影

你可以通過修改代碼中的sample_user_idsample_movie_id變量來測試不同的用戶和電影組合,觀察模型的預測結果。項目還提供了電影推薦功能,可以為指定用戶生成個性化的電影推薦列表。

項目六 客戶流失預測

【教學內容】

\1. 使用電信客戶流失數據集,訓練一個模型預測客戶是否會流失。主要有

以下幾個知識點:

(1)數據加載與探索性分析(EDA)。

(2)處理類別型特征(如 One-Hot 編碼)。

(3)使用邏輯回歸、決策樹或隨機森林進行分類。

(4)評估模型性能(準確率、ROC-AUC 等)。

【重點】

使用邏輯回歸、決策樹或隨機森林進行分類。

【難點】

評估模型性能(準確率、ROC-AUC 等)。

【分析思考討論題】

如果數據集中流失客戶的比例較低,如何通過采樣技術(如 SMOTE)提升模 型性能?

以下是一個基于 Python 的客戶流失預測項目代碼,使用了電信行業客戶數據和多種機器學習算法進行流失預測,包含完整的數據預處理、特征工程、模型訓練和評估功能,確保可以正常運行并展示良好的預測效果。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.metrics import (accuracy_score, confusion_matrix, classification_report,roc_curve, auc, precision_recall_curve, f1_score)
import warnings# 忽略警告信息
warnings.filterwarnings('ignore')# 設置中文顯示
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False  # 解決負號顯示問題class CustomerChurnPredictor:def __init__(self):# 初始化變量self.data = Noneself.X = Noneself.y = Noneself.X_train = Noneself.X_test = Noneself.y_train = Noneself.y_test = Noneself.models = {}self.predictions = {}self.probabilities = {}self.preprocessor = None# 加載數據self.load_data()# 數據預處理self.preprocess_data()def load_data(self):"""加載客戶流失數據集"""print("正在加載客戶流失數據集...")# 使用電信客戶流失數據集(從公開URL加載)# url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/telecom_churn.csv"self.data = pd.read_csv("telecom_churn.csv")# 顯示數據集信息print(f"數據集加載完成,共 {self.data.shape[0]} 個客戶,{self.data.shape[1] - 1} 個特征")# 查看目標變量分布churn_distribution = self.data['churn'].value_counts(normalize=True)print(f"流失客戶比例: {churn_distribution[True]:.2%}")print(f"留存客戶比例: {churn_distribution[False]:.2%}")def explore_data(self):"""探索數據集"""print("\n=== 數據集基本信息 ===")print("數據集前5行:")print(self.data.head())# 數據類型和缺失值檢查print("\n數據類型和缺失值統計:")print(self.data.info())# 數值型特征統計描述print("\n數值型特征統計描述:")print(self.data.describe())def visualize_data(self):"""數據可視化"""# 1. 客戶流失分布plt.figure(figsize=(8, 6))churn_counts = self.data['churn'].value_counts()sns.barplot(x=['留存', '流失'], y=churn_counts.values)plt.title('客戶流失分布')plt.ylabel('客戶數量')for i, v in enumerate(churn_counts.values):plt.text(i, v + 50, f'{v} ({v / len(self.data):.2%})', ha='center')plt.show()# 2. 數值型特征與流失的關系numeric_features = self.data.select_dtypes(include=['float64', 'int64']).columns.tolist()numeric_features.remove('account_length')  # 移除賬號長度,避免重復顯示plt.figure(figsize=(15, 10))for i, feature in enumerate(numeric_features[:6]):  # 選擇前6個數值特征plt.subplot(2, 3, i + 1)sns.histplot(data=self.data, x=feature, hue='churn', multiple='stack', bins=30)plt.title(f'{feature} 與客戶流失的關系')plt.tight_layout()plt.show()# 3. 類別型特征與流失的關系categorical_features = ['international_plan', 'voice_mail_plan']plt.figure(figsize=(12, 5))for i, feature in enumerate(categorical_features):plt.subplot(1, 2, i + 1)churn_rate = self.data.groupby(feature)['churn'].mean()sns.barplot(x=churn_rate.index, y=churn_rate.values)plt.title(f'{feature} 與流失率的關系')plt.ylabel('流失率')for j, v in enumerate(churn_rate.values):plt.text(j, v + 0.02, f'{v:.2%}', ha='center')plt.tight_layout()plt.show()# 4. 特征相關性熱圖plt.figure(figsize=(12, 10))# 選擇數值型特征計算相關性numeric_data = self.data.select_dtypes(include=['float64', 'int64'])# 將布爾值轉換為整數以便計算相關性numeric_data['churn'] = self.data['churn'].astype(int)correlation = numeric_data.corr()sns.heatmap(correlation, annot=True, cmap='coolwarm', fmt='.2f', linewidths=0.5)plt.title('特征相關性熱圖')plt.tight_layout()plt.show()# 5. 通話分鐘數與流失的關系plt.figure(figsize=(12, 6))plt.subplot(1, 2, 1)sns.boxplot(x='churn', y='total_day_minutes', data=self.data)plt.title('白天通話分鐘數與流失的關系')plt.subplot(1, 2, 2)sns.boxplot(x='churn', y='total_eve_minutes', data=self.data)plt.title('晚間通話分鐘數與流失的關系')plt.tight_layout()plt.show()def preprocess_data(self):"""數據預處理和劃分訓練測試集"""# 分離特征和目標變量self.X = self.data.drop('churn', axis=1)self.y = self.data['churn'].astype(int)  # 將布爾值轉換為0和1# 區分數值型和類別型特征numeric_features = self.X.select_dtypes(include=['float64', 'int64']).columns.tolist()categorical_features = self.X.select_dtypes(include=['object', 'bool']).columns.tolist()# 創建預處理管道numeric_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='median')),('scaler', StandardScaler())])categorical_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='most_frequent')),('onehot', OneHotEncoder(drop='first', handle_unknown='ignore'))])# 組合預處理步驟self.preprocessor = ColumnTransformer(transformers=[('num', numeric_transformer, numeric_features),('cat', categorical_transformer, categorical_features)])# 劃分訓練集和測試集(保持類別比例)self.X_train, self.X_test, self.y_train, self.y_test = train_test_split(self.X, self.y, test_size=0.3, random_state=42, stratify=self.y)print(f"訓練集: {self.X_train.shape[0]} 個客戶")print(f"測試集: {self.X_test.shape[0]} 個客戶")def build_models(self):"""構建多種分類模型"""print("\n=== 構建分類模型 ===")# 創建包含預處理和模型的管道self.models = {'邏輯回歸': Pipeline(steps=[('preprocessor', self.preprocessor),('classifier', LogisticRegression(max_iter=1000, class_weight='balanced', random_state=42))]),'決策樹': Pipeline(steps=[('preprocessor', self.preprocessor),('classifier', DecisionTreeClassifier(class_weight='balanced', random_state=42))]),'隨機森林': Pipeline(steps=[('preprocessor', self.preprocessor),('classifier', RandomForestClassifier(class_weight='balanced', random_state=42))]),'梯度提升': Pipeline(steps=[('preprocessor', self.preprocessor),('classifier', GradientBoostingClassifier(random_state=42))]),'支持向量機': Pipeline(steps=[('preprocessor', self.preprocessor),('classifier', SVC(probability=True, class_weight='balanced', random_state=42))])}def train_models(self):"""訓練所有模型"""print("\n=== 模型訓練結果 ===")for name, model in self.models.items():print(f"訓練 {name}...")# 訓練模型model.fit(self.X_train, self.y_train)# 預測y_pred = model.predict(self.X_test)y_prob = model.predict_proba(self.X_test)[:, 1]  # 預測為流失的概率# 保存結果self.predictions[name] = y_predself.probabilities[name] = y_prob# 計算F1分數(對不平衡數據更合適)f1 = f1_score(self.y_test, y_pred)print(f"{name} F1分數: {f1:.4f}")def evaluate_model(self, model_name):"""詳細評估指定模型"""if model_name not in self.models:print(f"模型 {model_name} 不存在,請先構建模型")returnprint(f"\n=== {model_name} 詳細評估 ===")# 1. 混淆矩陣cm = confusion_matrix(self.y_test, self.predictions[model_name])plt.figure(figsize=(8, 6))sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',xticklabels=['留存', '流失'],yticklabels=['留存', '流失'])plt.xlabel('預測標簽')plt.ylabel('真實標簽')plt.title(f'{model_name} 混淆矩陣')plt.show()# 2. 分類報告print("\n分類報告:")print(classification_report(self.y_test,self.predictions[model_name],target_names=['留存', '流失']))# 3. ROC曲線和AUCfpr, tpr, _ = roc_curve(self.y_test, self.probabilities[model_name])roc_auc = auc(fpr, tpr)plt.figure(figsize=(8, 6))plt.plot(fpr, tpr, color='darkorange', lw=2, label=f'ROC曲線 (AUC = {roc_auc:.4f})')plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')plt.xlim([0.0, 1.0])plt.ylim([0.0, 1.05])plt.xlabel('假正例率 (FPR)')plt.ylabel('真正例率 (TPR)')plt.title(f'{model_name} ROC曲線')plt.legend(loc="lower right")plt.show()# 4. 精確率-召回率曲線precision, recall, _ = precision_recall_curve(self.y_test, self.probabilities[model_name])plt.figure(figsize=(8, 6))plt.plot(recall, precision, color='blue', lw=2)plt.xlabel('召回率 (Recall)')plt.ylabel('精確率 (Precision)')plt.title(f'{model_name} 精確率-召回率曲線')plt.xlim([0.0, 1.0])plt.ylim([0.0, 1.05])plt.show()# 5. 交叉驗證cv_scores = cross_val_score(self.models[model_name],self.X, self.y,cv=5,scoring='f1')print(f"交叉驗證F1分數: {cv_scores.mean():.4f} (±{cv_scores.std():.4f})")def compare_models(self):"""比較所有模型的性能"""# 收集各模型的評估指標metrics = []for name in self.models.keys():report = classification_report(self.y_test, self.predictions[name],target_names=['留存', '流失'],output_dict=True)# 計算AUCfpr, tpr, _ = roc_curve(self.y_test, self.probabilities[name])roc_auc = auc(fpr, tpr)metrics.append({'模型': name,'準確率': accuracy_score(self.y_test, self.predictions[name]),'精確率': report['流失']['precision'],'召回率': report['流失']['recall'],'F1分數': report['流失']['f1-score'],'AUC': roc_auc})metrics_df = pd.DataFrame(metrics)# 繪制各指標對比圖plt.figure(figsize=(15, 10))for i, metric in enumerate(['準確率', '精確率', '召回率', 'F1分數', 'AUC']):plt.subplot(2, 3, i + 1)sns.barplot(x='模型', y=metric, data=metrics_df)plt.title(f'不同模型的{metric}對比')plt.ylim(0.6, 1.0)  # 設置y軸范圍以便更好地觀察差異for j, v in enumerate(metrics_df[metric]):plt.text(j, v + 0.01, f'{v:.4f}', ha='center')plt.xticks(rotation=15)plt.tight_layout()plt.show()return metrics_dfdef optimize_model(self, model_name):"""優化指定模型的超參數"""if model_name not in self.models:print(f"模型 {model_name} 不存在,請先構建模型")returnprint(f"\n=== 優化 {model_name} 超參數 ===")# 定義參數網格param_grids = {'邏輯回歸': {'classifier__C': [0.01, 0.1, 1, 10, 100],'classifier__penalty': ['l1', 'l2']},'決策樹': {'classifier__max_depth': [3, 5, 7, 10, None],'classifier__min_samples_split': [2, 5, 10],'classifier__min_samples_leaf': [1, 2, 4]},'隨機森林': {'classifier__n_estimators': [50, 100, 200],'classifier__max_depth': [None, 10, 20],'classifier__min_samples_split': [2, 5]},'梯度提升': {'classifier__n_estimators': [50, 100, 200],'classifier__learning_rate': [0.01, 0.1, 0.2],'classifier__max_depth': [3, 5]},'支持向量機': {'classifier__C': [0.1, 1, 10],'classifier__kernel': ['linear', 'rbf'],'classifier__gamma': ['scale', 'auto']}}# 創建網格搜索對象grid_search = GridSearchCV(estimator=self.models[model_name],param_grid=param_grids[model_name],cv=5,scoring='f1',n_jobs=-1)# 執行網格搜索grid_search.fit(self.X_train, self.y_train)# 輸出最佳參數print(f"最佳參數: {grid_search.best_params_}")# 評估優化后的模型y_pred_opt = grid_search.predict(self.X_test)print("\n優化后的分類報告:")print(classification_report(self.y_test, y_pred_opt,target_names=['留存', '流失']))# 更新模型self.models[model_name] = grid_search.best_estimator_self.predictions[model_name] = y_pred_optself.probabilities[model_name] = grid_search.predict_proba(self.X_test)[:, 1]return grid_search.best_estimator_def analyze_feature_importance(self, model_name):"""分析模型的特征重要性"""if model_name not in ['決策樹', '隨機森林', '梯度提升']:print(f"{model_name} 不支持特征重要性分析")return# 獲取模型model = self.models[model_name]# 獲取特征名稱numeric_features = self.X.select_dtypes(include=['float64', 'int64']).columns.tolist()categorical_features = self.X.select_dtypes(include=['object', 'bool']).columns.tolist()# 獲取OneHotEncoder轉換后的類別特征名稱cat_transformer = model.named_steps['preprocessor'].named_transformers_['cat']onehot = cat_transformer.named_steps['onehot']cat_features_transformed = list(onehot.get_feature_names_out(categorical_features))# 所有特征名稱all_features = numeric_features + cat_features_transformed# 獲取特征重要性importances = model.named_steps['classifier'].feature_importances_indices = np.argsort(importances)[::-1]# 顯示前10個最重要的特征plt.figure(figsize=(12, 8))plt.bar(range(min(10, len(importances))), importances[indices[:10]])plt.xticks(range(min(10, len(importances))),[all_features[i] for i in indices[:10]], rotation=90)plt.title(f'{model_name} - 特征重要性(前10名)')plt.tight_layout()plt.show()# 返回特征重要性排序feature_importance = pd.DataFrame({'特征': [all_features[i] for i in indices],'重要性': importances[indices]})return feature_importance.head(10)def predict_churn(self, customer_data):"""預測客戶是否會流失"""# 使用表現最佳的模型進行預測best_model = self.models['梯度提升']# 轉換為DataFrameif not isinstance(customer_data, pd.DataFrame):customer_data = pd.DataFrame([customer_data])# 預測流失概率churn_prob = best_model.predict_proba(customer_data)[0, 1]churn_pred = best_model.predict(customer_data)[0]# 輸出結果result = "會流失" if churn_pred == 1 else "不會流失"print(f"\n客戶流失預測結果: {result} (概率: {churn_prob:.2%})")return {'預測結果': result,'流失概率': churn_prob}if __name__ == "__main__":# 創建客戶流失預測器實例predictor = CustomerChurnPredictor()# 探索數據集predictor.explore_data()# 數據可視化predictor.visualize_data()# 構建并訓練模型predictor.build_models()predictor.train_models()# 比較所有模型predictor.compare_models()# 選擇表現較好的模型進行詳細評估(梯度提升)best_model = '梯度提升'predictor.evaluate_model(best_model)# 優化最佳模型predictor.optimize_model(best_model)# 分析特征重要性predictor.analyze_feature_importance(best_model)# 示例預測# 構造兩個示例客戶數據(基于數據集中的典型特征)customer1 = {'account_length': 70,'area_code': '415','international_plan': 'no','voice_mail_plan': 'yes','number_vmail_messages': 25,'total_day_minutes': 200,'total_day_calls': 100,'total_day_charge': 34.0,'total_eve_minutes': 150,'total_eve_calls': 80,'total_eve_charge': 12.75,'total_night_minutes': 200,'total_night_calls': 100,'total_night_charge': 9.0,'total_intl_minutes': 10,'total_intl_calls': 2,'total_intl_charge': 2.7,'number_customer_service_calls': 1}customer2 = {'account_length': 30,'area_code': '510','international_plan': 'yes','voice_mail_plan': 'no','number_vmail_messages': 0,'total_day_minutes': 350,'total_day_calls': 120,'total_day_charge': 59.5,'total_eve_minutes': 200,'total_eve_calls': 90,'total_eve_charge': 17.0,'total_night_minutes': 150,'total_night_calls': 80,'total_night_charge': 6.75,'total_intl_minutes': 20,'total_intl_calls': 5,'total_intl_charge': 5.4,'number_customer_service_calls': 4}# 預測print("\n=== 客戶流失預測示例 ===")predictor.predict_churn(customer1)predictor.predict_churn(customer2)

這個客戶流失預測項目的主要功能和特點:

  1. 數據集選擇:使用電信行業客戶流失數據集,包含 3333 個客戶的信息和 19 個相關特征

  2. 完整流程:實現了從數據加載、探索性分析、可視化、預處理、模型訓練、評估到預測的完整流程

  3. 多種分類算法:包含邏輯回歸、決策樹、隨機森林、梯度提升和支持向量機五種經典分類算法

  4. 數據預處理:自動處理數值型和類別型特征,包括缺失值填充、標準化和獨熱編碼

  5. 豐富的可視化:提供客戶流失分布、特征與流失關系、相關性熱圖等可視化圖表

  6. 全面評估指標:使用準確率、精確率、召回率、F1 分數和 AUC 等指標評估模型性能

  7. 模型優化:通過網格搜索優化超參數,提升模型性能

  8. 特征重要性分析:識別對客戶流失影響最大的關鍵因素

  9. 實用預測功能:可以輸入客戶特征數據,預測該客戶的流失概率

運行前需要安裝以下依賴庫:

pip install numpy pandas matplotlib seaborn scikit-learn

程序運行后會:

  • 自動下載并加載電信客戶流失數據集

  • 展示數據集的基本信息和客戶流失分布

  • 生成多種可視化圖表幫助理解數據特征與流失的關系

  • 訓練五種分類模型并比較它們的性能

  • 對表現最佳的梯度提升模型進行詳細評估

  • 優化最佳模型的超參數以獲得更好的預測效果

  • 分析并展示對客戶流失影響最大的關鍵因素

  • 對兩個示例客戶進行流失預測并展示結果

你可以通過修改代碼中的customer1customer2字典來測試不同的客戶特征數據,觀察模型的預測結果。這個項目對于理解客戶流失模式、識別高風險客戶和制定留存策略非常有幫助。

項目七 圖像分類

【教學內容】

使用 CIFAR-10 數據集,訓練一個模型對 10 類圖像進行分類。主要有以下幾

個知識點:

(1)數據加載與可視化。

(2)數據增強(如旋轉、翻轉)。

(3)使用簡單的卷積神經網絡(CNN)進行分類。

(4)評估模型性能(準確率、混淆矩陣等)。

【重點】

使用簡單的卷積神經網絡(CNN)進行分類。

【難點】

評估模型性能(準確率、混淆矩陣等)。

【分析思考討論題】

為什么卷積神經網絡(CNN)在圖像分類任務中表現優于傳統機器學習算法?

以下是一個基于 Python 的圖像分類項目代碼,使用了 PyTorch 框架和 ResNet18 模型,能夠對 CIFAR-10 數據集進行分類并展示訓練效果。

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
import time
import os# 設置隨機種子,保證結果可復現
torch.manual_seed(42)
np.random.seed(42)
# 圖表顯示中文設置
plt.rcParams["font.sans-serif"] = ["SimHei"]
# 數據預處理
transform = transforms.Compose([transforms.RandomCrop(32, padding=4),  # 隨機裁剪transforms.RandomHorizontalFlip(),  # 隨機水平翻轉transforms.ToTensor(),  # 轉換為張量transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))  # 標準化
])# 加載CIFAR-10數據集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform
)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2
)testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform
)
testloader = torch.utils.data.DataLoader(testset, batch_size=100, shuffle=False, num_workers=2
)# CIFAR-10類別名稱
classes = ('plane', 'car', 'bird', 'cat', 'deer','dog', 'frog', 'horse', 'ship', 'truck')# 檢查是否有GPU可用
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f"使用設備: {device}")# 加載預訓練的ResNet18模型并修改輸出層
net = torchvision.models.resnet18(pretrained=True)
num_ftrs = net.fc.in_features
net.fc = nn.Linear(num_ftrs, 10)  # CIFAR-10有10個類別
net = net.to(device)# 定義損失函數和優化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9, weight_decay=5e-4)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=20, gamma=0.1)  # 學習率調度器# 創建保存模型和結果的目錄
if not os.path.exists('results'):os.makedirs('results')
if not os.path.exists('models'):os.makedirs('models')# 訓練模型
def train_model(num_epochs=50):print(f"開始訓練,共{num_epochs}個epoch")# 記錄訓練過程中的指標train_losses = []train_accs = []test_losses = []test_accs = []start_time = time.time()for epoch in range(num_epochs):# 訓練階段net.train()running_loss = 0.0correct = 0total = 0for i, data in enumerate(trainloader, 0):inputs, labels = data[0].to(device), data[1].to(device)# 清零梯度optimizer.zero_grad()# 前向傳播、計算損失、反向傳播、參數更新outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()# 統計訓練數據running_loss += loss.item()_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()# 每100個batch打印一次信息if i % 100 == 99:print(f'[{epoch + 1}, {i + 1}] loss: {running_loss / 100:.3f}')running_loss = 0.0# 計算訓練集準確率train_acc = 100 * correct / totaltrain_loss = running_loss / len(trainloader)train_accs.append(train_acc)train_losses.append(train_loss)# 測試階段net.eval()test_loss = 0.0correct = 0total = 0with torch.no_grad():  # 不計算梯度,節省內存for data in testloader:images, labels = data[0].to(device), data[1].to(device)outputs = net(images)loss = criterion(outputs, labels)test_loss += loss.item()_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()test_acc = 100 * correct / totaltest_loss = test_loss / len(testloader)test_accs.append(test_acc)test_losses.append(test_loss)# 學習率調度scheduler.step()print(f'Epoch {epoch + 1} 完成')print(f'訓練集準確率: {train_acc:.2f}%,損失: {train_loss:.4f}')print(f'測試集準確率: {test_acc:.2f}%,損失: {test_loss:.4f}')print('-' * 50)# 計算總訓練時間total_time = time.time() - start_timeprint(f'訓練完成,總耗時: {total_time:.2f}秒')# 保存模型torch.save(net.state_dict(), 'models/cifar10_resnet18.pth')print('模型已保存到 models/cifar10_resnet18.pth')# 繪制訓練曲線plot_training_curves(train_losses, test_losses, train_accs, test_accs)return train_losses, test_losses, train_accs, test_accs# 繪制訓練曲線
def plot_training_curves(train_losses, test_losses, train_accs, test_accs):plt.figure(figsize=(12, 5))# 繪制損失曲線plt.subplot(1, 2, 1)plt.plot(train_losses, label='訓練損失')plt.plot(test_losses, label='測試損失')plt.title('損失曲線')plt.xlabel('Epoch')plt.ylabel('損失')plt.legend()# 繪制準確率曲線plt.subplot(1, 2, 2)plt.plot(train_accs, label='訓練準確率')plt.plot(test_accs, label='測試準確率')plt.title('準確率曲線')plt.xlabel('Epoch')plt.ylabel('準確率 (%)')plt.legend()plt.tight_layout()plt.savefig('results/training_curves.png')print('訓練曲線已保存到 results/training_curves.png')plt.show()# 展示一些預測結果
def show_predictions(num_images=10):net.load_state_dict(torch.load('models/cifar10_resnet18.pth'))net.eval()# 獲取一些測試圖像dataiter = iter(testloader)images, labels = next(dataiter)images = images[:num_images]labels = labels[:num_images]# 進行預測outputs = net(images.to(device))_, predicted = torch.max(outputs, 1)# 反標準化以便顯示inv_normalize = transforms.Normalize(mean=[-0.4914 / 0.2023, -0.4822 / 0.1994, -0.4465 / 0.2010],std=[1 / 0.2023, 1 / 0.1994, 1 / 0.2010])# 顯示圖像和預測結果plt.figure(figsize=(15, 5))for i in range(num_images):plt.subplot(2, 5, i + 1)plt.xticks([])plt.yticks([])plt.grid(False)# 反標準化并轉換為numpy格式img = inv_normalize(images[i])img = img.numpy().transpose((1, 2, 0))plt.imshow(img)# 顯示真實標簽和預測標簽true_label = classes[labels[i]]pred_label = classes[predicted[i]]color = 'green' if true_label == pred_label else 'red'plt.xlabel(f'真實: {true_label}\n預測: {pred_label}', color=color)plt.tight_layout()plt.savefig('results/predictions.png')print('預測結果已保存到 results/predictions.png')plt.show()# 計算每個類別的準確率
def class_accuracy():net.load_state_dict(torch.load('models/cifar10_resnet18.pth'))net.eval()class_correct = list(0. for i in range(10))class_total = list(0. for i in range(10))with torch.no_grad():for data in testloader:images, labels = data[0].to(device), data[1].to(device)outputs = net(images)_, predicted = torch.max(outputs, 1)c = (predicted == labels).squeeze()for label, correct in zip(labels, c):class_correct[label] += correct.item()class_total[label] += 1# 打印每個類別的準確率print("\n每個類別的準確率:")for i in range(10):acc = 100 * class_correct[i] / class_total[i]print(f'類別 {classes[i]} 的準確率: {acc:.2f}%')# 繪制柱狀圖plt.figure(figsize=(10, 6))accs = [100 * class_correct[i] / class_total[i] for i in range(10)]plt.bar(classes, accs, color='skyblue')plt.xlabel('類別')plt.ylabel('準確率 (%)')plt.title('每個類別的準確率')plt.ylim(0, 100)# 在柱狀圖上標注準確率for i, v in enumerate(accs):plt.text(i, v + 1, f'{v:.1f}%', ha='center')plt.tight_layout()plt.savefig('results/class_accuracy.png')print('類別準確率圖已保存到 results/class_accuracy.png')plt.show()if __name__ == '__main__':# 訓練模型(可以調整epoch數量)train_model(num_epochs=3)# 展示預測結果show_predictions()# 分析每個類別的準確率class_accuracy()

這個圖像分類項目具有以下特點:

  1. 使用 CIFAR-10 數據集,包含 10 個類別的 32x32 彩色圖像

  2. 采用 ResNet18 模型進行遷移學習,在預訓練模型基礎上微調

  3. 實現了完整的訓練流程,包括數據增強、模型訓練、損失計算和參數優化

  4. 提供了可視化功能,包括訓練曲線、預測結果展示和類別準確率分析

  5. 支持 GPU 加速(如果可用),能自動檢測并使用 CUDA 設備

運行前的準備

在運行代碼前,需要安裝以下依賴庫:

pip install torch torchvision matplotlib numpy

項目運行流程

  1. 程序會自動下載 CIFAR-10 數據集到./data目錄

  2. 訓練模型并將模型參數保存到./models目錄

  3. 生成的圖表會保存到./results目錄

  4. 訓練完成后,會展示一些測試圖像的預測結果

  5. 最后會分析并展示每個類別的準確率

你可以根據需要調整代碼中的參數,如訓練輪數(num_epochs)、批次大小(batch_size)和學習率等,以獲得更好的分類效果。

項目八 情感分析

【教學內容】

使用 IMDB 電影評論數據集,訓練一個模型判斷評論的情感(正面或負面)。

主要有以下幾個知識點:

(1)數據加載與預處理(如文本清洗、分詞)。

(2)使用 TF-IDF 或詞嵌入(如 Word2Vec)進行特征提取。

(3)使用樸素貝葉斯、邏輯回歸或 LSTM 進行分類。

(4)評估模型性能(準確率、F1-score 等)。

【重點】

使用樸素貝葉斯、邏輯回歸或 LSTM 進行分類。

【難點】

評估模型性能(準確率、F1-score 等)。

【分析思考討論題】

如何通過情感詞典或領域知識提升情感分析模型的準確性?

下面我為你創建一個基于 Python 的情感分析項目,這個項目將使用文本數據訓練一個簡單的情感分類模型,并能夠對新的文本進行情感預測(積極或消極)。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
import requests
import io
import zipfile
# 圖表顯示中文設置# 設置中文顯示
# plt.rcParams["font.family"] = ["SimHei"]
sns.set(font_scale=1.2)
sns.set_style("whitegrid")class SentimentAnalysis:def __init__(self):"""初始化情感分析模型"""self.vectorizer = CountVectorizer(max_features=5000)self.model = MultinomialNB()self.data = Noneself.X_train = Noneself.X_test = Noneself.y_train = Noneself.y_test = Nonedef load_data(self):"""加載IMDb電影評論數據集"""print("正在獲取數據集...")# 從公開URL獲取數據集# url = "aclImdb_v1.rar"# response = requests.get(url, stream=True)# open("aclImdb_v1.rar")# 解壓數據with zipfile.ZipFile(r"E:\downloads\aclImdb.zip") as z:# 讀取正面和負面評論positive_reviews = []for filename in z.namelist():if "aclImdb/train/pos/" in filename and filename.endswith(".txt"):with z.open(filename) as f:positive_reviews.append(f.read().decode('utf-8'))negative_reviews = []for filename in z.namelist():if "aclImdb/train/neg/" in filename and filename.endswith(".txt"):with z.open(filename) as f:negative_reviews.append(f.read().decode('utf-8'))# 創建DataFramepositive_df = pd.DataFrame({'review': positive_reviews,'sentiment': 1  # 1表示正面情感})negative_df = pd.DataFrame({'review': negative_reviews,'sentiment': 0  # 0表示負面情感})# 合并數據并打亂順序self.data = pd.concat([positive_df, negative_df]).sample(frac=1).reset_index(drop=True)print(f"數據集加載完成,共包含 {len(self.data)} 條評論")# 展示數據集基本信息print("\n數據集類別分布:")print(self.data['sentiment'].value_counts())plt.rcParams["font.sans-serif"] = ["SimHei"]# 可視化數據分布plt.figure(figsize=(8, 6))sns.countplot(x='sentiment', data=self.data)plt.title('情感類別分布')plt.xlabel('情感類別 (0: 負面, 1: 正面)')plt.ylabel('評論數量')plt.show()return self.datadef preprocess_data(self):"""預處理數據,將文本轉換為特征向量"""if self.data is None:raise ValueError("請先加載數據")print("\n正在預處理數據...")# 分割特征和標簽X = self.data['review']y = self.data['sentiment']# 分割訓練集和測試集self.X_train, self.X_test, self.y_train, self.y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 將文本轉換為詞頻向量self.X_train = self.vectorizer.fit_transform(self.X_train)self.X_test = self.vectorizer.transform(self.X_test)print(f"訓練集大小: {self.X_train.shape[0]}")print(f"測試集大小: {self.X_test.shape[0]}")print(f"特征數量: {self.X_train.shape[1]}")def train_model(self):"""訓練情感分析模型"""if self.X_train is None or self.y_train is None:raise ValueError("請先預處理數據")print("\n正在訓練模型...")self.model.fit(self.X_train, self.y_train)print("模型訓練完成")def evaluate_model(self):"""評估模型性能"""if self.X_test is None or self.y_test is None:raise ValueError("請先預處理數據")print("\n正在評估模型...")# 在測試集上進行預測y_pred = self.model.predict(self.X_test)# 計算準確率accuracy = accuracy_score(self.y_test, y_pred)print(f"模型準確率: {accuracy:.4f}")# 輸出分類報告print("\n分類報告:")print(classification_report(self.y_test, y_pred))plt.rcParams["font.sans-serif"] = ["SimHei"]# 繪制混淆矩陣cm = confusion_matrix(self.y_test, y_pred)plt.figure(figsize=(8, 6))sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',xticklabels=['負面', '正面'],yticklabels=['負面', '正面'])plt.title('混淆矩陣')plt.xlabel('預測標簽')plt.ylabel('真實標簽')plt.show()return accuracydef predict_sentiment(self, text):"""預測文本的情感"""if not text:return "請輸入有效的文本"# 轉換文本為特征向量text_vector = self.vectorizer.transform([text])# 預測情感prediction = self.model.predict(text_vector)[0]probability = self.model.predict_proba(text_vector)[0]sentiment = "正面" if prediction == 1 else "負面"confidence = probability[prediction]return f"情感預測: {sentiment} (置信度: {confidence:.4f})"if __name__ == "__main__":# 創建情感分析實例sa = SentimentAnalysis()# 加載數據sa.load_data()# 預處理數據sa.preprocess_data()# 訓練模型sa.train_model()# 評估模型sa.evaluate_model()# 測試一些示例文本print("\n測試示例文本情感:")test_texts = ["這部電影太棒了,演員演技出色,劇情緊湊,強烈推薦!","這是我看過的最糟糕的電影,浪費時間,不建議觀看。","電影情節一般,但特效做得不錯,總體來說還可以。","演員表現很差,劇情混亂,看完之后非常失望。"]for text in test_texts:print(f"\n文本: {text}")print(sa.predict_sentiment(text))

項目說明

這個情感分析項目主要包含以下幾個部分:

  1. 數據獲取:從斯坦福大學的公開 URL 獲取 IMDb 電影評論數據集,包含正面和負面評論

  2. 數據預處理:將文本數據轉換為機器學習模型可處理的特征向量

  3. 模型訓練:使用樸素貝葉斯分類器訓練情感分析模型

  4. 模型評估:通過準確率、混淆矩陣等指標評估模型性能

  5. 情感預測:提供預測接口,可以對新文本進行情感分析

運行前的準備

在運行代碼前,需要安裝必要的依賴庫:

pip install numpy pandas matplotlib seaborn scikit-learn requests

項目特點

  • 數據集自動獲取,無需手動下載

  • 包含數據可視化,直觀展示數據分布和模型性能

  • 代碼結構清晰,封裝成類,便于維護和擴展

  • 支持中文顯示,圖表更易讀

  • 提供示例文本測試,直觀展示模型效果

運行后,程序會先下載并處理數據,然后訓練模型,最后輸出模型評估結果和示例文本的情感預測。你也可以根據需要修改代碼,添加更多的測試文本或嘗試不同的算法。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96074.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96074.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96074.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

STM32 UART + DMA + 空閑中斷使用中的幀錯誤(FE)問題及解決方案

STM32 UART + DMA + IDLE中斷使用中的幀錯誤(FE)問題及解決方案 在我調試STM32H7串口空閑中斷DMA接受時遇到了一個bug,這個現象發生在系統剛上電時,有個串口由于幀錯誤FE掛起了中斷,之后在HAL_UART_IRQHandler這個全局中斷處理函數結束后,所有的中斷使能標志位都被清除了,經過…

TDengine 選擇函數 BOTTOM() 用戶手冊

BOTTOM() 函數用戶手冊 函數定義 BOTTOM(expr, k)功能說明 BOTTOM() 函數統計表/超級表中某列的值最小 k 個非 NULL 值。如果多條數據取值一樣,全部取用又會超出 k 條限制時,系統會從相同值中隨機選取符合要求的數量返回。 返回值 數據類型: 同應用…

西門子 S7-200 SMART PLC 實現星三角降壓啟動控制:原理、案例與完整程序

在工業控制場景中,中型異步電機直接啟動時會產生遠超額定電流的沖擊電流(通常為額定電流的 5-7 倍),不僅會影響電網穩定性,還可能對機械設備造成損傷。星三角(Y-Δ)降壓啟動是解決這一問題的經典…

【Android】View 的基礎知識

【Android】View 的基礎知識 1. 什么是 View? View 是 Android 中所有UI組件的基礎類。它表示屏幕上的一個矩形區域,負責繪制內容和處理用戶交互事件。所有的 UI 組件(如按鈕、文本框等)都是 View 的子類,而 ViewGroup…

西門子 S7-200 SMART PLC 實現電機點動與連續運行綜合控制

在工業生產中,電機控制并非單一模式:調試設備時需要 “按動即轉、松開即停” 的點動功能,正常生產時則需要 “一鍵啟動、持續運行” 的連續控制。本文以西門子 S7-200 SMART PLC 為載體,詳細講解電機點動控制原理,并設…

如何解決pip安裝報錯ModuleNotFoundError: No module named ‘sphinx-rtd-theme’問題

【Python系列Bug修復PyCharm控制臺pip install報錯】如何解決pip安裝報錯ModuleNotFoundError: No module named ‘sphinx-rtd-theme’問題 摘要 在使用 PyCharm 開發 Python 項目時,pip install 報錯是常見痛點。特別是在構建文檔或引入第三方庫時,開…

HakcMyVM-Literal

目錄信息搜集漏洞利用權限提升信息搜集 主機發現 ┌──(kali?kali)-[~] └─$ nmap -sn 192.168.21.0/24 Nmap scan report for 192.168.21.5端口掃描 ┌──(kali?kali)-[~] └─$ nmap -sS -sV -O -p- 192.168.21.5 Starting Nmap 7.95 ( https://nmap.org ) a…

0904 類的繼承

Part 1.梳理思維導圖一.繼承中的特殊成員函數1.構造函數父類的構造函數會被繼承到子類中&#xff0c;在構造的順序中&#xff0c;是先構造父類&#xff0c;再構造子類#include <iostream>using namespace std;class Father { public:string name; protected:int *age; pr…

PDF教程|如何把想要的網頁保存下來?

前段時間有個小伙伴咨詢了小白&#xff1a;領導想要某個網頁的整個頁面&#xff0c;有沒有比較好的方法把它保存下來&#xff1f; 在他找到小白之前&#xff0c;這種事情他已經接到好幾次了&#xff0c;每次都是怎么解決的呢&#xff1f;其實很簡單&#xff0c;就是打開Word&a…

【bash】命令查看當前目錄下文件個數

要用 ls 查看當前目錄下的文件個數&#xff0c;可以結合 wc -l 來統計行數&#xff1a; ls -1 | wc -l說明&#xff1a; ls -1&#xff1a;以一行一個文件的方式列出。wc -l&#xff1a;統計行數&#xff0c;也就是文件/目錄的數量。 ?? 需要注意&#xff1a; 這個方法會把文…

「日拱一碼」081 機器學習——梯度增強特征選擇GBFS

目錄 什么是梯度增強特征選擇&#xff08;GBFS&#xff09; 為什么 GBM 適合做特征選擇 GBFS 的一般步驟 代碼示例 什么是梯度增強特征選擇&#xff08;GBFS&#xff09; GBFS 并非一個像 Lasso 或隨機森林那樣有嚴格標準定義的獨立算法&#xff0c;而是一種基于梯度提升機…

解構匯編, 萬物起源

匯編的誕生匯編全景圖核心主干: CPU架構主要分支: 語法和工具共同的地貌: 核心概念延伸: 跨平臺 & 跨架構跨平臺跨架構總結以 GAS vs. NASM 為例NASM 不支持跨架構 ≠ 無法在ARM架構上的系統安裝匯編的誕生 機器語言的困境 早期的程序員直接使用機器語言進行編程機器語言由…

廣州旅游網站系統 - 純靜態旅游展示平臺

&#x1f31f; 廣州旅游網站系統 - 純靜態旅游展示平臺觀世界才有世界觀 - 一個集景區展示、旅游攻略、文化傳播于一體的精美旅游網站&#x1f4cb; 項目概述 這是一個專注于廣州旅游文化的純靜態網站系統&#xff0c;采用現代化的前端技術棧&#xff0c;為游客提供全方位的廣州…

Qt UDP通信學習

Qt UDP通信學習 一、項目概述 本項目基于Qt框架實現了UDP通信功能&#xff0c;支持單播與廣播消息收發&#xff0c;展示了UDP套接字的基本用法&#xff0c;適合初學者學習Qt網絡模塊的實際應用。 二、項目結構 55.pro&#xff1a;Qt工程文件&#xff0c;配置模塊與源碼文件main…

古德哈特定律(Goodhart‘s Law)

古德哈特定律&#xff08;Goodhart’s Law&#xff09;表述為“當一個指標變成了目標&#xff0c;它將不再是個好指標”。 該定律由英國經濟學家查爾斯古德哈特&#xff08;Charles Goodhart&#xff09;在1975年提出&#xff0c;最初用于批判撒切爾夫人政府的貨幣主義政策&…

在 ASP.NET Core 8 Web API 中實現基于角色的授權 安全且可擴展 API 的最佳實踐

掌握基于角色的授權&#xff1a;使用專家策略保護您的 ASP.NET Core 8 Web API。在 ASP.NET Core 8 Web API 中實現基于角色的授權&#xff1a;安全且可擴展 API 的最佳實踐介紹授權是任何 Web 應用程序的關鍵組件。在開發 API 時&#xff0c;使用基于角色的授權保護端點可確保…

AutoHotkey識別圖片

一、下載ImagePut插件 下載地址&#xff1a;GitHub - iseahound/ImagePut: A core library for images in AutoHotkey. Supports AutoHotkey v1 and v2. 二、將插件和要搜索的圖片導入項目 #Include ./plugin/ImagePut.ahk ; 截取當前屏幕 pic : ImagePutBuffer(0) point : p…

CamX-Camera常用編譯命令和adb指南

g_camxsettings vendor/qcom/proprietary/camx/src/settings/g_camxsettings.xml 控制相機debug的信息都在該文件里面 0、相關代碼 framwork層 frameworks/av/camera/ frameworks/av/services/camera frameworks/av/services/camera frameworks/hardware/interfaces/camerase…

LabVIEW 實現顏色平滑漸變控制

LabVIEW 中實現 LED 顏色從藍到紅的平滑漸變顯示在 LabVIEW 開發中&#xff0c;若需讓 LED&#xff08;或類 LED 顯示控件&#xff09;實現從藍色到紅色的平滑色彩漸變&#xff08;模擬溫度等參數從低到高的視覺反饋&#xff09;&#xff0c;可通過自定義顏色查找表 數值縮放映…

陰陽學:從入門到精通

第一篇&#xff1a;入門篇——陰陽基礎理論1.1 陰陽的起源與哲學意義陰陽概念的歷史淵源《易經》中的陰陽思想陰陽與宇宙、自然、人生的關系陰陽對思想、行為、社會的影響1.2 陰陽的基本屬性與符號陰陽的特征、象征與對立統一陰陽在自然界的表現&#xff08;晝夜、冷熱、動靜等…