Tự động hóa & Machine Learning: Tự động dự đoán doanh thu từ dữ liệu trong SQL Server bằng mô hình Python
Tự động dự đoán doanh thu từ dữ liệu trong SQL Server bằng mô hình Python
Giới thiệu
Trong thời đại số hóa hiện nay, việc dự đoán doanh thu dựa trên dữ liệu lịch sử đã trở thành một nhu cầu thiết yếu của các doanh nghiệp. Bằng cách kết hợp sức mạnh của SQL Server để lưu trữ dữ liệu và Python để xây dựng các mô hình Machine Learning, chúng ta có thể tạo ra một hệ thống dự đoán doanh thu tự động, cung cấp những thông tin giá trị cho việc ra quyết định kinh doanh.
Bài viết này sẽ hướng dẫn chi tiết cách xây dựng một hệ thống dự đoán doanh thu tự động bằng cách kết hợp SQL Server và các mô hình Machine Learning trong Python.
Tổng quan về quy trình
Quy trình dự đoán doanh thu tự động bao gồm các bước chính sau:
- Thu thập và chuẩn bị dữ liệu từ SQL Server
- Phân tích và tiền xử lý dữ liệu với Python
- Xây dựng và huấn luyện mô hình Machine Learning
- Đánh giá và tối ưu hóa mô hình
- Triển khai mô hình để dự đoán tự động
1. Thu thập và chuẩn bị dữ liệu từ SQL Server
Cấu trúc cơ sở dữ liệu
Đầu tiên, chúng ta cần có một cơ sở dữ liệu chứa thông tin về doanh thu lịch sử:
-- Tạo bảng dữ liệu doanh thu CREATE TABLE DuLieuDoanhThu ( ID INT PRIMARY KEY IDENTITY(1,1), NgayThang DATE NOT NULL, SanPham NVARCHAR(100) NOT NULL, DanhMuc NVARCHAR(50) NOT NULL, KhuVuc NVARCHAR(50) NOT NULL, Kenh NVARCHAR(50) NOT NULL, SoLuong INT NOT NULL, DonGia DECIMAL(18,2) NOT NULL, DoanhThu DECIMAL(18,2) NOT NULL, ChiPhiMarketing DECIMAL(18,2) NULL, ChiPhiVanChuyen DECIMAL(18,2) NULL, NgayTao DATETIME DEFAULT GETDATE() );
Truy xuất dữ liệu từ SQL Server
-- Stored procedure để lấy dữ liệu huấn luyện mô hình CREATE PROCEDURE sp_LayDuLieuHuanLuyen @TuNgay DATE, @DenNgay DATE AS BEGIN SELECT YEAR(NgayThang) AS Nam, MONTH(NgayThang) AS Thang, DAY(NgayThang) AS Ngay, DATEPART(dw, NgayThang) AS ThuTrongTuan, DanhMuc, KhuVuc, Kenh, SUM(DoanhThu) AS TongDoanhThu, SUM(SoLuong) AS TongSoLuong, SUM(ChiPhiMarketing) AS TongChiPhiMarketing, AVG(DonGia) AS GiaTrungBinh FROM DuLieuDoanhThu WHERE NgayThang BETWEEN @TuNgay AND @DenNgay GROUP BY YEAR(NgayThang), MONTH(NgayThang), DAY(NgayThang), DATEPART(dw, NgayThang), DanhMuc, KhuVuc, Kenh ORDER BY Nam, Thang, Ngay; END;
2. Phân tích và tiền xử lý dữ liệu với Python
import pandas as pd import numpy as np import pyodbc from sklearn.preprocessing import OneHotEncoder, StandardScaler from sklearn.model_selection import train_test_split # Kết nối đến SQL Server conn = pyodbc.connect('DRIVER={SQL Server};SERVER=yourserver;DATABASE=yourdatabase;UID=youruser;PWD=yourpassword') # Lấy dữ liệu từ SQL Server query = """ EXEC sp_LayDuLieuHuanLuyen @TuNgay = '2022-01-01', @DenNgay = '2023-12-31' """ df = pd.read_sql(query, conn) # Kiểm tra giá trị thiếu print(f"Số lượng giá trị thiếu trong mỗi cột:\n{df.isnull().sum()}") # Xử lý giá trị thiếu df['TongChiPhiMarketing'].fillna(df['TongChiPhiMarketing'].mean(), inplace=True) # Tạo thêm các đặc trưng (feature engineering) df['NgayLe'] = 0 # Có thể cập nhật bằng danh sách các ngày lễ df['TyLeChiPhiMarketing'] = df['TongChiPhiMarketing'] / df['TongDoanhThu'] df['MuaVu'] = df['Thang'].apply(lambda x: 'Xuan' if x in [1, 2, 3] else 'Ha' if x in [4, 5, 6] else 'Thu' if x in [7, 8, 9] else 'Dong') # Mã hóa các biến phân loại (one-hot encoding) categorical_cols = ['DanhMuc', 'KhuVuc', 'Kenh', 'MuaVu'] encoder = OneHotEncoder(sparse=False, drop='first') encoded_features = encoder.fit_transform(df[categorical_cols]) encoded_feature_names = encoder.get_feature_names_out(categorical_cols) # Kết hợp các đặc trưng đã mã hóa với dữ liệu gốc encoded_df = pd.DataFrame(encoded_features, columns=encoded_feature_names) df_final = pd.concat([df.drop(categorical_cols, axis=1).reset_index(drop=True), encoded_df.reset_index(drop=True)], axis=1) # Phân chia dữ liệu thành tập huấn luyện và tập kiểm tra X = df_final.drop('TongDoanhThu', axis=1) y = df_final['TongDoanhThu'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # Chuẩn hóa dữ liệu scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test)
3. Xây dựng và huấn luyện mô hình Machine Learning
from sklearn.linear_model import LinearRegression, Ridge, Lasso from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor from sklearn.svm import SVR from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error import joblib # Huấn luyện mô hình hồi quy tuyến tính linear_model = LinearRegression() linear_model.fit(X_train_scaled, y_train) # Huấn luyện mô hình Random Forest rf_model = RandomForestRegressor(n_estimators=100, random_state=42) rf_model.fit(X_train_scaled, y_train) # Huấn luyện mô hình Gradient Boosting gb_model = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1, random_state=42) gb_model.fit(X_train_scaled, y_train) # Dictionary để lưu các mô hình models = { 'Linear Regression': linear_model, 'Random Forest': rf_model, 'Gradient Boosting': gb_model } # Đánh giá các mô hình trên dữ liệu kiểm tra for name, model in models.items(): y_pred = model.predict(X_test_scaled) mse = mean_squared_error(y_test, y_pred) rmse = np.sqrt(mse) mae = mean_absolute_error(y_test, y_pred) r2 = r2_score(y_test, y_pred) print(f"Mô hình: {name}") print(f" - MSE: {mse:.2f}") print(f" - RMSE: {rmse:.2f}") print(f" - MAE: {mae:.2f}") print(f" - R^2: {r2:.4f}") print("") # Lưu mô hình tốt nhất (giả sử là Gradient Boosting) best_model = models['Gradient Boosting'] joblib.dump(best_model, 'best_model.pkl') joblib.dump(scaler, 'scaler.pkl') joblib.dump(encoder, 'encoder.pkl')
4. Đánh giá và tối ưu hóa mô hình
from sklearn.model_selection import GridSearchCV import matplotlib.pyplot as plt # Tối ưu hóa siêu tham số của mô hình Gradient Boosting param_grid = { 'n_estimators': [50, 100, 200], 'learning_rate': [0.01, 0.05, 0.1, 0.2], 'max_depth': [3, 5, 7], 'min_samples_split': [2, 5, 10] } grid_search = GridSearchCV( estimator=GradientBoostingRegressor(random_state=42), param_grid=param_grid, cv=5, scoring='neg_mean_squared_error', n_jobs=-1 ) grid_search.fit(X_train_scaled, y_train) print(f"Tham số tốt nhất: {grid_search.best_params_}") print(f"MSE tốt nhất: {-grid_search.best_score_:.2f}") # Lưu mô hình tối ưu optimized_model = grid_search.best_estimator_ joblib.dump(optimized_model, 'optimized_model.pkl') # Phân tích mức độ quan trọng của các đặc trưng feature_importance = optimized_model.feature_importances_ sorted_idx = np.argsort(feature_importance) plt.figure(figsize=(10, 8)) plt.barh(range(len(sorted_idx)), feature_importance[sorted_idx], align='center') plt.yticks(range(len(sorted_idx)), np.array(X.columns)[sorted_idx]) plt.title('Mức độ quan trọng của các đặc trưng') plt.savefig('feature_importance.png') # Vẽ biểu đồ so sánh giữa giá trị thực tế và dự đoán y_pred = optimized_model.predict(X_test_scaled) plt.figure(figsize=(10, 6)) plt.scatter(y_test, y_pred, alpha=0.5) plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--') plt.xlabel('Doanh thu thực tế') plt.ylabel('Doanh thu dự đoán') plt.title('So sánh giữa doanh thu thực tế và dự đoán') plt.savefig('actual_vs_predicted.png')
5. Triển khai mô hình để dự đoán tự động
Sau khi đã huấn luyện và tối ưu hóa mô hình, chúng ta cần tạo một ứng dụng để tự động dự đoán doanh thu. Dưới đây là một ví dụ về cách tạo một dịch vụ dự đoán tự động:
import pandas as pd import joblib import pyodbc import numpy as np from datetime import datetime, timedelta import schedule import time def predict_revenue(): # Kết nối đến SQL Server conn = pyodbc.connect('DRIVER={SQL Server};SERVER=yourserver;DATABASE=yourdatabase;UID=youruser;PWD=yourpassword') cursor = conn.cursor() # Lấy dữ liệu mới nhất để dự đoán query_historical = """ EXEC sp_LayDuLieuHuanLuyen @TuNgay = DATEADD(DAY, -90, GETDATE()), @DenNgay = GETDATE() """ df_historical = pd.read_sql(query_historical, conn) # Tạo dữ liệu cho dự đoán 30 ngày tiếp theo today = datetime.now() prediction_dates = [today + timedelta(days=i) for i in range(1, 31)] # Tạo DataFrame cho dự đoán prediction_data = [] for date in prediction_dates: # Lấy dữ liệu trung bình của các ngày tương tự trong quá khứ similar_days_query = f""" SELECT AVG(TongDoanhThu) as AvgRevenue, AVG(TongSoLuong) as AvgQuantity, AVG(TongChiPhiMarketing) as AvgMarketing, AVG(GiaTrungBinh) as AvgPrice FROM DuLieuDoanhThu WHERE DATEPART(dw, NgayThang) = {date.weekday() + 1} AND MONTH(NgayThang) = {date.month} """ avg_data = pd.read_sql(similar_days_query, conn) # Thêm vào dữ liệu dự đoán for category in df_historical['DanhMuc'].unique(): for region in df_historical['KhuVuc'].unique(): for channel in df_historical['Kenh'].unique(): prediction_data.append({ 'Nam': date.year, 'Thang': date.month, 'Ngay': date.day, 'ThuTrongTuan': date.weekday() + 1, 'DanhMuc': category, 'KhuVuc': region, 'Kenh': channel, 'TongSoLuong': avg_data['AvgQuantity'].values[0], 'TongChiPhiMarketing': avg_data['AvgMarketing'].values[0], 'GiaTrungBinh': avg_data['AvgPrice'].values[0], 'NgayLe': 0, # Cập nhật nếu là ngày lễ 'TyLeChiPhiMarketing': avg_data['AvgMarketing'].values[0] / max(1, avg_data['AvgRevenue'].values[0]), 'MuaVu': 'Xuan' if date.month in [1, 2, 3] else 'Ha' if date.month in [4, 5, 6] else 'Thu' if date.month in [7, 8, 9] else 'Dong' }) df_prediction = pd.DataFrame(prediction_data) # Tải mô hình và các công cụ xử lý dữ liệu model = joblib.load('optimized_model.pkl') scaler = joblib.load('scaler.pkl') encoder = joblib.load('encoder.pkl') # Xử lý dữ liệu dự đoán giống như dữ liệu huấn luyện categorical_cols = ['DanhMuc', 'KhuVuc', 'Kenh', 'MuaVu'] encoded_features = encoder.transform(df_prediction[categorical_cols]) encoded_feature_names = encoder.get_feature_names_out(categorical_cols) encoded_df = pd.DataFrame(encoded_features, columns=encoded_feature_names) df_final = pd.concat([df_prediction.drop(categorical_cols, axis=1).reset_index(drop=True), encoded_df.reset_index(drop=True)], axis=1) # Chuẩn hóa dữ liệu X_pred = scaler.transform(df_final) # Dự đoán y_pred = model.predict(X_pred) # Gắn kết quả dự đoán vào dữ liệu df_prediction['DoanhThuDuDoan'] = y_pred # Lưu kết quả dự đoán vào SQL Server for index, row in df_prediction.iterrows(): insert_query = f""" INSERT INTO DuLieuDuDoanDoanhThu ( NgayDuDoan, NgayThang, DanhMuc, KhuVuc, Kenh, DoanhThuDuDoan ) VALUES ( GETDATE(), '{row['Nam']}-{row['Thang']}-{row['Ngay']}', '{row['DanhMuc']}', '{row['KhuVuc']}', '{row['Kenh']}', {row['DoanhThuDuDoan']} ) """ cursor.execute(insert_query) conn.commit() conn.close() print(f"Dự đoán doanh thu hoàn tất vào: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") # Lập lịch chạy dự đoán mỗi tuần schedule.every().monday.at("01:00").do(predict_revenue) # Chạy một lần để kiểm tra predict_revenue() # Vòng lặp chờ lịch while True: schedule.run_pending() time.sleep(60)
6. Tạo báo cáo tự động với kết quả dự đoán
Để trình bày kết quả dự đoán một cách trực quan, chúng ta có thể sử dụng thư viện matplotlib và seaborn để tạo các biểu đồ và sau đó gửi báo cáo qua email:
import matplotlib.pyplot as plt import seaborn as sns import pandas as pd import pyodbc from datetime import datetime import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.image import MIMEImage def generate_forecast_report(): # Kết nối đến SQL Server conn = pyodbc.connect('DRIVER={SQL Server};SERVER=yourserver;DATABASE=yourdatabase;UID=youruser;PWD=yourpassword') # Lấy dữ liệu dự đoán gần nhất query = """ SELECT NgayThang, DanhMuc, KhuVuc, Kenh, DoanhThuDuDoan FROM DuLieuDuDoanDoanhThu WHERE NgayDuDoan = (SELECT MAX(NgayDuDoan) FROM DuLieuDuDoanDoanhThu) ORDER BY NgayThang """ df = pd.read_sql(query, conn) # Tổng hợp dữ liệu theo ngày daily_forecast = df.groupby('NgayThang')['DoanhThuDuDoan'].sum().reset_index() # Tổng hợp dữ liệu theo danh mục category_forecast = df.groupby('DanhMuc')['DoanhThuDuDoan'].sum().reset_index() # Tổng hợp dữ liệu theo khu vực region_forecast = df.groupby('KhuVuc')['DoanhThuDuDoan'].sum().reset_index() # Tạo biểu đồ dự báo theo thời gian plt.figure(figsize=(12, 6)) plt.plot(daily_forecast['NgayThang'], daily_forecast['DoanhThuDuDoan'], marker='o') plt.title('Dự báo doanh thu trong 30 ngày tới') plt.xlabel('Ngày') plt.ylabel('Doanh thu dự báo') plt.grid(True) plt.tight_layout() plt.savefig('daily_forecast.png') # Tạo biểu đồ dự báo theo danh mục plt.figure(figsize=(10, 6)) sns.barplot(x='DanhMuc', y='DoanhThuDuDoan', data=category_forecast) plt.title('Dự báo doanh thu theo danh mục sản phẩm') plt.xlabel('Danh mục') plt.ylabel('Tổng doanh thu dự báo') plt.xticks(rotation=45) plt.tight_layout() plt.savefig('category_forecast.png') # Tạo biểu đồ dự báo theo khu vực plt.figure(figsize=(10, 6)) sns.barplot(x='KhuVuc', y='DoanhThuDuDoan', data=region_forecast) plt.title('Dự báo doanh thu theo khu vực') plt.xlabel('Khu vực') plt.ylabel('Tổng doanh thu dự báo') plt.tight_layout() plt.savefig('region_forecast.png') # Gửi báo cáo qua email send_report_email() print("Báo cáo dự báo đã được tạo và gửi thành công.") def send_report_email(): # Cấu hình email sender_email = "your_email@gmail.com" receiver_email = "recipient@company.com" password = "your_password" # Tạo tin nhắn msg = MIMEMultipart() msg['Subject'] = f'Báo cáo dự báo doanh thu - {datetime.now().strftime("%Y-%m-%d")}' msg['From'] = sender_email msg['To'] = receiver_email # Thêm nội dung text = ''' Kính gửi Ban lãnh đạo, Đính kèm là báo cáo dự báo doanh thu 30 ngày tới được tạo tự động bởi hệ thống ML của chúng ta. Các điểm chính: - Dự báo doanh thu tổng cộng trong 30 ngày tới - Phân tích doanh thu theo danh mục sản phẩm - Phân tích doanh thu theo khu vực Xem file đính kèm để biết chi tiết. Trân trọng, Hệ thống dự báo tự động ''' msg.attach(MIMEText(text, 'plain')) # Đính kèm hình ảnh for image_file in ['daily_forecast.png', 'category_forecast.png', 'region_forecast.png']: with open(image_file, 'rb') as fp: img = MIMEImage(fp.read()) img.add_header('Content-Disposition', 'attachment', filename=image_file) msg.attach(img) # Gửi email with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server: server.login(sender_email, password) server.send_message(msg) # Chạy báo cáo generate_forecast_report()
Kết luận
Kết hợp SQL Server và các mô hình Machine Learning trong Python tạo nên một hệ thống dự đoán doanh thu mạnh mẽ, có khả năng tự động hóa cao. Hệ thống này không chỉ giúp doanh nghiệp dự đoán doanh số trong tương lai mà còn cung cấp những thông tin chi tiết về xu hướng doanh thu theo nhiều chiều khác nhau như danh mục sản phẩm, khu vực địa lý, kênh bán hàng.
Với việc tự động hóa toàn bộ quy trình từ thu thập dữ liệu, huấn luyện mô hình, đến tạo báo cáo, doanh nghiệp có thể tiết kiệm thời gian và nguồn lực đáng kể, đồng thời nâng cao khả năng ra quyết định dựa trên dữ liệu.
Bằng cách liên tục cải thiện và tối ưu hóa mô hình qua thời gian, doanh nghiệp sẽ có được một công cụ dự báo ngày càng chính xác, hỗ trợ đắc lực cho việc lập kế hoạch kinh doanh và chiến lược phát triển trong tương lai. 1