TỔNG QUAN
Lý do chọn đề tài
Thị trường tài chính ngày càng sôi động với sự tham gia của đông đảo nhà đầu tư
Nhu cầu dự đoán xu hướng giá cổ phiếu để đưa ra quyết định đầu tư sáng suốt ngày càng tăng cao Trong bối cảnh đó, "Dự đoán xu hướng giá cổ phiếu công ty Vinamilk" sẽ đầy tiềm năng, ứng dụng công nghệ Big Data tiên tiến để giải mã thị trường tài chính phức tạp.
Vinamilk, với vị thế "Ông vua sữa Việt Nam", sở hữu thị phần áp đảo, thương hiệu uy tín và sản phẩm được tin dùng rộng rãi Cổ phiếu VNM của Vinamilk luôn nằm trong top thanh khoản cao nhất thị trường chứng khoán, thu hút sự quan tâm của đông đảo nhà đầu tư
Do đó, dự đoán xu hướng giá cổ phiếu VNM trở thành vấn đề then chốt, ảnh hưởng trực tiếp đến quyết định đầu tư của nhiều người.
Tuy nhiên, dự đoán giá cổ phiếu là bài toán khó, chịu ảnh hưởng bởi nhiều yếu tố nội tại và ngoại vi của công ty, cũng như biến động thị trường chung Việc xây dựng mô hình dự đoán chính xác đòi hỏi kiến thức chuyên môn về tài chính, thống kê, học máy và khả năng phân tích dữ liệu chuyên sâu Big Data mang đến giải pháp đột phá, giúp thu thập và phân tích lượng lớn dữ liệu một cách nhanh chóng và hiệu quả Nhờ Big Data, chúng ta có thể:
● Tiếp cận dữ liệu đa dạng: thu thập dữ liệu lịch sử giá cổ phiếu VNM, dữ liệu tài chính của công ty, dữ liệu kinh tế vĩ mô, tâm lý thị trường,
● Xử lý dữ liệu phức tạp: làm sạch, chuẩn hóa, và tổng hợp dữ liệu từ nhiều nguồn khác nhau.
● Xây dựng mô hình dự đoán chính xác: áp dụng các thuật toán học máy tiên tiến như mạng nơ-ron nhân tạo, học sâu, để dự đoán xu hướng giá cổ phiếu VNM với độ chính xác cao.
Dự án "Dự đoán xu hướng giá cổ phiếu công ty Vinamilk" có thể mang lại nhiều lợi ích thiết thực:
● Hỗ trợ nhà đầu tư: cung cấp công cụ hỗ trợ nhà đầu tư đưa ra quyết định đầu tư sáng suốt về cổ phiếu Vinamilk, giảm thiểu rủi ro và tối ưu hóa lợi nhuận.
● Nâng cao hiệu quả thị trường: góp phần tạo ra thị trường chứng khoán minh bạch, hiệu quả và sôi động hơn.
● Thúc đẩy ứng dụng Big Data: mở ra tiềm năng ứng dụng Big Data vào lĩnh vực tài chính, hỗ trợ các hoạt động đầu tư, phân tích thị trường và quản lý rủi ro.
Hướng tiếp cận
● Mục tiêu: Xây dựng mô hình dự đoán xu hướng giá cổ phiếu Vinamilk với độ chính xác cao, hỗ trợ nhà đầu tư đưa ra quyết định đầu tư sáng suốt.
● Phạm vi: Phân tích dữ liệu lịch sử giá cổ phiếu VNM, dữ liệu tài chính của công ty, dữ liệu kinh tế vĩ mô và các yếu tố thị trường liên quan.
Hình 1: Mô tả bài toán
1.2.3 Dữ liệu cổ phiếu của Vinamilk
Dữ liệu cổ phiếu Vinamilk (VNM) từ 2013-2023 là một tập dữ liệu bao gồm thông tin lịch sử về giá cổ phiếu VNM, khối lượng giao dịch, giá trị giao dịch và các yếu tố thị trường liên quan trong giai đoạn từ năm 2013 đến năm 2023 Dữ liệu này được thu thập từ Sở Giao dịch Chứng khoán TP.HCM (HOSE) và các nguồn uy tín khác.
● Giá Mở: Giá mà cổ phiếu VNM bắt đầu giao dịch trong một phiên giao dịch.
● Giá Cao: Mức giá cao nhất mà cổ phiếu VNM đạt được trong một phiên giao dịch.
● Giá Thấp: Mức giá thấp nhất mà cổ phiếu VNM đạt được trong một phiên giao dịch.
● Giá Đóng: Giá mà cổ phiếu VNM kết thúc giao dịch trong một phiên giao dịch.
● Giá Đóng Điều chỉnh: Giá đóng sau khi điều chỉnh cho các sự kiện như chia cổ tức, chia cổ phiếu và phát hành cổ phiếu mới.
● Khối lượng: Tổng số cổ phiếu VNM được giao dịch trong một phiên giao dịch.
● Ngày: Thời gian giao dịch cổ phiếu 1.2.4 Thu thập dữ liệu:
● Trang web của Vinamilk (https://www.vinamilk.com.vn/)
● Dữ liệu từ: https://vn.investing.com/equities/vietnam-dairy-products-jsc
Ngôn ngữ và thư viện ứng dụng
● pandas: Dùng để đọc và thao tác dữ liệu dạng bảng.
● numpy: Dùng để xử lý dữ liệu số và ma trận.
● matplotlib.pyplot: Dùng để vẽ biểu đồ và đồ thị.
● sklearn.preprocessing.MinMaxScaler: Dùng để chuẩn hóa dữ liệu vào khoảng [0, 1].
● tensorflow.keras.models: Dùng để xây dựng và huấn luyện mô hình học sâu.
● tensorflow.keras.callbacks.ModelCheckpoint: Dùng để lưu lại mô hình có hiệu suất tốt nhất trong quá trình huấn luyện.
● keras.layers.LSTM: Dùng để xây dựng mô hình mạng nơ-ron nhân tạo kiểu LSTM
(Long Short-Term Memory) - phù hợp cho các bài toán dự đoán chuỗi thời gian.
● keras.layers.Dropout: Dùng để áp dụng kỹ thuật Dropout nhằm tránh học tủ trong mô hình.
● keras.layers.Dense: Dùng để xây dựng lớp đầu ra của mô hình.
● sklearn.metrics.r2_score: Dùng để tính toán hệ số xác định R^2, đánh giá mức độ phù hợp của mô hình.
● sklearn.metrics.mean_absolute_error: Dùng để tính toán sai số tuyệt đối trung bình
● sklearn.metrics.mean_absolute_percentage_error: Dùng để tính toán sai số tuyệt đối phần trăm trung bình (MAPE)
CƠ SỞ LÝ THUYẾT
Thư viện Pandas
Pandas là thư viện Python mã nguồn mở được ưa chuộng trong lĩnh vực khoa học dữ liệu Nhờ khả năng xử lý và phân tích dữ liệu dạng bảng hiệu quả, Pandas được sử dụng rộng rãi trong cả nghiên cứu lẫn phát triển ứng dụng Pandas là cấu trúc dữ liệu DataFrame linh hoạt, cung cấp nhiều chức năng thao tác và xử lý dữ liệu mạnh mẽ Nhờ vậy, Pandas giúp người dùng dễ dàng khai thác thông tin từ các tập dữ liệu lớn.
Khả năng đọc và thao tác dữ liệu:
Pandas cung cấp nhiều hàm và phương thức để đọc dữ liệu từ các nguồn khác nhau, bao gồm: Tệp tin văn bản (CSV, Excel, JSON), Cổng dữ liệu SQL, Cấu trúc dữ liệu Python
Sau khi đọc dữ liệu, Pandas cho phép người dùng thực hiện nhiều thao tác trên dữ liệu, chẳng hạn như:
● Lọc dữ liệu theo điều kiện
● Thực hiện phép tính trên dữ liệu
● Ghép nối dữ liệu từ nhiều nguồn
● Thay đổi cấu trúc dữ liệu
Pandas tích hợp nhiều hàm và phương thức để phân tích dữ liệu, bao gồm:
● Tính toán thống kê mô tả (tâm trung bình, trung vị, độ lệch chuẩn, v.v.)
● Phân tích thống kê nâng cao (phân phối t-test, hồi quy tuyến tính, v.v.)
● Hình dung dữ liệu (biểu đồ, đồ thị, v.v.)
Thư viện Numpy
NumPy (viết tắt của Numerical Python) là thư viện Python mã nguồn mở, chuyên dụng cho việc xử lý dữ liệu số và ma trận Nó cung cấp nhiều tính năng mạnh mẽ, giúp người dùng thao tác với dữ liệu hiệu quả một cách dễ dàng.
Khả năng chính của NumPy:
● Tạo và thao tác với mảng đa chiều
● Thực hiện các phép toán toán học
● Tối ưu hóa hiệu suất
● Tích hợp với các thư viện khoa học dữ liệu khác Ứng dụng của NumPy:
● Xử lý ảnh (lọc ảnh, biến đổi ảnh, phân tích ảnh)
● Học máy (tính toán và thao tác dữ liệu huấn luyện/thử nghiệm)
● Phân tích dữ liệu khoa học (vật lý, hóa học, kỹ thuật, tài chính)
● Phát triển trò chơi (mô phỏng chuyển động, xử lý va chạm)
Thư viện Keras.Layers LSTM
Lớp Keras.Layers LSTM được sử dụng để xây dựng mô hình mạng nơ-ron nhân tạo kiểu LSTM (Long Short-Term Memory) trong TensorFlow/Keras Mạng LSTM là một loại mạng nơ-ron tuần hoàn (RNN) được thiết kế để xử lý các chuỗi dữ liệu phụ thuộc theo thời gian, đặc biệt hiệu quả cho các bài toán dự đoán chuỗi thời gian. Đặc điểm chính:
● Khả năng ghi nhớ dài hạn
Lớp Keras.Layers LSTM bao gồm các thành phần chính sau:
● Tế bào: Lưu trữ thông tin trạng thái của mạng tại mỗi thời điểm.
● Cổng quên: Quyết định thông tin nào từ trạng thái trước sẽ được lưu giữ.
● Cổng đầu vào: Quyết định thông tin mới nào sẽ được thêm vào trạng thái.
● Cổng ra: Quyết định thông tin nào từ trạng thái hiện tại sẽ được sử dụng làm đầu ra.
Cách sử dụng: Để sử dụng lớp Keras.Layers LSTM trong mô hình Keras, bạn cần thực hiện các bước sau:
3 Thêm lớp LSTM vào mô hình:
4 Biên dịch và huấn luyện mô hình:
Kỹ thuật Dropout
Kỹ thuật Dropout là một phương pháp chính quy hóa trong học máy nhằm giảm thiểu tình trạng học tủ (overfitting) trong mô hình mạng nơ-ron nhân tạo Dropout hoạt động bằng cách ngẫu nhiên loại bỏ một tỷ lệ phần trăm các nơ-ron trong mỗi lớp trong quá trình huấn luyện, buộc mô hình phải học tập dựa vào nhiều nơ-ron khác nhau thay vì phụ thuộc vào một vài nơ-ron cụ thể.
Lớp keras.layers.Dropout được sử dụng để áp dụng kỹ thuật Dropout trong
TensorFlow/Keras Nó cho phép bạn xác định tỷ lệ phần trăm nơ-ron sẽ bị loại bỏ trong mỗi lớp.
Python from tensorflow import keras from tensorflow.keras.layers import Dropout dropout_layer = Dropout(rate=0.5)
● rate: Tỷ lệ phần trăm nơ-ron sẽ bị loại bỏ (thông thường từ 0.2 đến 0.5).
● Cải thiện khả năng khái quát hóa của mô hình
● Tăng cường khả năng chống nhiễu
Thư viện keras.layers.Dense
Lớp keras.layers.Dense được sử dụng để xây dựng lớp đầu ra của mô hình mạng nơ-ron nhân tạo trong TensorFlow/Keras Lớp này thực hiện phép nhân ma trận giữa đầu vào và ma trận trọng số, sau đó áp dụng hàm kích hoạt để tạo ra đầu ra.
Python from tensorflow import keras from tensorflow.keras.layers import Dense dense_layer = Dense(units, activation='softmax')
● units: Số lượng nơ-ron trong lớp Dense.
● activation: Hàm kích hoạt được áp dụng cho đầu ra của lớp (ví dụ: 'relu', 'sigmoid', 'softmax').
Lớp Dense thường được sử dụng như lớp đầu ra cuối cùng của mô hình để:
● Phân loại đa lớp: (ví dụ: phân loại ảnh thành 10 lớp khác nhau)
● Hồi quy tuyến tính: (ví dụ: dự đoán giá trị liên tục)
Mô hình LSTM
Mô hình LSTM (Long Short-Term Memory) hay còn gọi là mạng nơ-ron ngắn hạn dài hạn là một loại mạng nơ-ron tuần hoàn (RNN) được phát triển để giải quyết vấn đề biến mất gradient (vanishing gradient problem) trong các mạng RNN thông thường Vấn đề biến mất gradient hạn chế khả năng học tập các phụ thuộc dài hạn trong dữ liệu tuần tự LSTM sử dụng cơ chế tế bào nhớ với các đơn vị gating để điều khiển lưu lượng thông tin, giúp mạng có thể học tập và lưu giữ thông tin trong thời gian dài.
Cấu trúc của một tế bào LSTM:
Một tế bào LSTM bao gồm bốn thành phần chính:
1 Cổng quên (Forget Gate): Điều chỉnh thông tin từ trạng thái tế bào trước (C_t-1) được quên.
2 Cổng vào (Input Gate): Kiểm soát thông tin từ đầu vào hiện tại (X_t) được thêm vào trạng thái tế bào.
3 Trạng thái tế bào (Cell State): Lưu trữ bộ nhớ dài hạn của mạng.
4 Cổng ra (Output Gate): Xác định thông tin từ trạng thái tế bào được truyền đến tế bào tiếp theo và lớp đầu ra.
Hoạt động của các đơn vị LSTM:
Hoạt động bên trong một đơn vị LSTM liên quan đến việc cập nhật cổng quên (f_t), cổng vào(i_t), trạng thái tế bào (C_t) và cổng ra (o_t) tại mỗi bước thời gian (t):
5 Đầu ra tế bào: h_t = o_t * tanh(C_t) Ứng dụng của LSTM:
Dự báo chuỗi thời gian: Dự đoán các giá trị trong tương lai của dữ liệu chuỗi thời gian, chẳng hạn như giá cổ phiếu, kiểu thời tiết hoặc số liệu bán hàng.
Xử lý ngôn ngữ tự nhiên (NLP): Dịch máy, tóm tắt văn bản, phân tích tình cảm và trả lời câu hỏi.
Nhận dạng giọng nói: Chuyển đổi ngôn ngữ nói thành văn bản.
Tạo nhạc: Sáng tác các tác phẩm âm nhạc mới hoặc tạo nhạc dựa trên phong cách hoặc thể loại cụ thể.
Các phương pháp đánh giá hiệu suất mô hình
Có nhiều phương pháp khác nhau để đánh giá hiệu suất mô hình dự đoán giá cổ phiếu.
Một số phương pháp phổ biến bao gồm:
● R-squared (R^2): Đây là một chỉ số thống kê đo lường mối quan hệ tuyến tính giữa giá trị dự đoán và giá trị thực tế Giá trị R^2 càng cao, mô hình dự đoán càng chính xác.
● Mean absolute error (MAE): Đây là sai số trung bình tuyệt đối giữa giá trị dự đoán và giá trị thực tế MAE càng nhỏ, mô hình dự đoán càng chính xác.
● Mean absolute percentage error (MAPE): Đây là sai số phần trăm trung bình tuyệt đối giữa giá trị dự đoán và giá trị thực tế MAPE được sử dụng khi giá trị thực tế có thể có giá trị lớn, giúp so sánh hiệu suất mô hình trên các tập dữ liệu có mức giá khác nhau.
● Root mean squared error (RMSE): Đây là sai số bình phương trung bình giữa giá trị dự đoán và giá trị thực tế RMSE nhạy cảm với các sai số lớn hơn, giúp đánh giá mức độ ảnh hưởng của các sai số lớn đối với hiệu suất mô hình.
Cách sử dụng các phương pháp đánh giá:
● R-squared: Tính toán R^2 bằng cách sử dụng công thức sau:
R^2 = 1 - (sum((y_true - y_pred)^2) / sum((y_true - mean(y_true))^2))
y_true là giá trị thực tế.
y_pred là giá trị dự đoán.
mean(y_true) là giá trị trung bình của giá trị thực tế.
Giá trị R^2 nằm trong khoảng [0, 1] Giá trị R^2 càng gần 1, mô hình dự đoán càng chính xác.
● MAE: Tính toán MAE bằng cách sử dụng công thức sau:
MAE = mean(abs(y_true - y_pred))
y_true là giá trị thực tế.
y_pred là giá trị dự đoán.
abs() là hàm giá trị tuyệt đối.
Giá trị MAE càng nhỏ, mô hình dự đoán càng chính xác.
● MAPE: Tính toán MAPE bằng cách sử dụng công thức sau:
MAPE = mean(abs((y_true - y_pred) / y_true)) * 100
y_true là giá trị thực tế.
y_pred là giá trị dự đoán.
abs() là hàm giá trị tuyệt đối.
Giá trị MAPE càng nhỏ, mô hình dự đoán càng chính xác.
● RMSE: Tính toán RMSE bằng cách sử dụng công thức sau:
RMSE = sqrt(mean((y_true - y_pred)^2))
y_true là giá trị thực tế.
y_pred là giá trị dự đoán.
sqrt() là hàm căn bậc hai.
Giá trị RMSE càng nhỏ, mô hình dự đoán càng chính xác.
Lựa chọn phương pháp đánh giá:
Việc lựa chọn phương pháp đánh giá phù hợp phụ thuộc vào mục đích đánh giá và đặc điểm của tập dữ liệu.
● R-squared: Thích hợp khi ta muốn đánh giá mối quan hệ tuyến tính giữa giá trị dự đoán và giá trị thực tế.
● MAE: Thích hợp khi ta muốn đánh giá mức độ sai số trung bình giữa giá trị dự đoán và giá trị thực tế.
● MAPE: Thích hợp khi ta muốn đánh giá mức độ sai số phần trăm trung bình giữa giá trị dự đoán và giá trị thực tế, đặc biệt khi giá trị thực tế có thể có giá trị lớn
BỘ DỮ LIỆU ĐỀ XUẤT
Thông tin dữ liệu
Nguồn dữ liệu được lấy từ trang web Investing ( https://vn.investing.com/) Đây là một trang web cung cấp thông tin và công cụ đầu tư hàng đầu cho nhà đầu tư toàn cầu Trang web cung cấp dữ liệu thị trường theo thời gian thực, tin tức và phân tích, công cụ biểu đồ, lịch kinh tế và diễn đàn Website được coi là nguồn tài nguyên hữu ích giúp người dùng đưa ra quyết định đầu tư sáng suốt Địa chỉ dữ liệu: https://vn.investing.com/equities/vietnam-dairy-products-jsc Đây là dữ liệu lịch sử giá cổ phiếu của công ty Cổ phần sữa Việt Nam (VNM) lấy trong khoảng thời gian từ 10-07-2013 tới 21-07-2023.
Mô tả dữ liệu
Bộ dữ liệu bao gồm: Ngày, Đóng cửa, Mở cửa, Cao nhất, Thấp nhất, KL và % Thay đổi.
Dữ liệu lịch sử giá cổ phiếu chứa đựng nhiều thông tin quan trọng dành cho các nhà đầu tư và nhà giao dịch Giá đóng cửa, mở cửa, cao nhất, thấp nhất là những chỉ số quan trọng giúp đánh giá mức độ biến động và rủi ro của cổ phiếu trong ngày Khối lượng giao dịch phản ánh sự quan tâm của thị trường đối với cổ phiếu đó, trong khi % thay đổi giá so với ngày trước đo lường hiệu suất của cổ phiếu trong ngày.
Dựa trên những thông tin này, nhà đầu tư có thể phân tích xu hướng tăng/giảm giá hoặc sự đi ngang của cổ phiếu thông qua sự thay đổi của giá và khối lượng giao dịch Họ cũng có thể so sánh hiệu suất của nhiều cổ phiếu khác nhau dựa trên % thay đổi giá Từ những phân tích này, nhà đầu tư có thể đưa ra các quyết định giao dịch như mua, bán hay nắm giữ cổ phiếu một cách khoa học và hiệu quả hơn Đây là công cụ quan trọng giúp nhà đầu tư đưa ra các quyết định giao dịch chứng khoán một cách khoa học và hiệu quả hơn.
Test thử 5 dòng dữ liệu đầu tiên Để kiểm tra xem dữ liệu có chạy không thì chúng ta sử dụng đoạn code như sau
Hình 3: Code hiển thị 5 dòng dữ liệu
Và kết quả như sau:
Hình 4: 5 dòng dữ liệu đầu tiên của dataset
Các kiểu dữ liệu của thuộc tính trong dataset Để kiểm tra các kiểu sử liệu của thuộc tính trong dataset, đoạn code sau đây sẽ được sử dụng:
Hình 5: Code xác định các kiểu dữ liệu của dataset
Hình 6: Kết quả kiểm tra kiểu dữ liệu của thuộc tính trong dataset
Kết quả kiểm tra cho thấy bộ dữ liệu lịch sử giá cổ phiếu của VNM có các đặc điểm sau:
Số lượng mẫu dữ liệu: Bộ dữ liệu chứa 2505 mẫu, được đánh chỉ số từ 0 đến 2504.
Số lượng cột: Có tổng cộng 5 cột dữ liệu.
Tên và kiểu dữ liệu các cột:
Ngày: Kiểu dữ liệu datetime64[ns], có nghĩa là lưu trữ thông tin về ngày tháng.
Đóng cửa, Mở cửa, Cao nhất, Thấp nhất: Các cột này đều có kiểu dữ liệu object Điều này cho thấy các giá trị trong các cột này không phải là số thực (float) mà có thể là chuỗi
(string) chứa các ký tự đặc biệt hoặc có định dạng không chuẩn.
Dữ liệu không bị thiếu: Tất cả các cột đều có 2505 giá trị không null, nghĩa là không có giá trị nào bị thiếu trong bộ dữ liệu.
Bộ nhớ sử dụng: Bộ dữ liệu sử dụng khoảng 98.0+ KB bộ nhớ.
Kiểm tra mức độ hoàn thiện của dataset Đoạn code được sử dụng để kiểm tra mức độ hoàn thiện của dataset như sau:
Hình 7: Code kiểm tra mức độ hoàn thiện của dataset
Bảng mô tả trên cung cấp thông tin về cột dữ liệu Ngày trong dataset lịch sử giá cổ phiếu của VNM Cột này chứa thông tin về thời gian, cụ thể là ngày giao dịch chứng khoán.
Dưới đây là mô tả chi tiết về các thuộc tính của cột dữ liệu này:
● Số lượng mẫu (count): Có tổng cộng 2505 ngày giao dịch trong dataset.
● Giá trị trung bình (mean): Ngày trung bình là 17-07-2018, lúc 16:17:14 Tuy nhiên, giá trị này không mang nhiều ý nghĩa thực tiễn vì ngày tháng không thể tính trung bình theo cách thông thường.
● Giá trị nhỏ nhất (min): Ngày giao dịch sớm nhất trong dataset là 10-07 -2013.
● Trung vị (50%): 50% số ngày giao dịch nằm trước ngày 19-07-2018, và 50% nằm sau ngày này.
● Các điểm phân vị (25% và 75%): 25% số ngày giao dịch nằm trước ngày 13-01-2016 và 75% số ngày giao dịch nằm trước ngày 14-01-2021 Điều này cho thấy dữ liệu có sự phân bố không đều, với mật độ ngày giao dịch tăng dần theo thời gian.
● Giá trị lớn nhất (max): Ngày giao dịch gần đây nhất trong dataset là 21 -07-2023.
=> Dữ liệu trong cột Ngày cho thấy dữ liệu lịch sử giá cổ phiếu của VNM bao gồm các ngày giao dịch từ 10-07-2013 đến 21-07-2023, với mật độ ngày giao dịch tăng dần theo thời gian.
THỰC NGHIỆM VÀ PHÂN TÍCH
Tiền xử lý dữ liệu
Bước này sẽ giúp bộ dữ liệu của chúng ta được chuẩn hóa định dạng Bộ dữ liệu hiện tại còn tồn tại ở nhiều định dạng khác nhau như chuỗi, số nguyên, số thực, v.v Tiền xử lý dữ liệu giúp đảm bảo rằng tất cả các dữ liệu được đưa về định dạng thích hợp cho việc phân tích và xử lý tiếp theo.
Hình 9: Code tiền xử lý dữ liệu
Nhóm thực hiện các bước sau:
● Chuyển đổi cột "Ngày" sang dạng datetime: Sử dụng phương thức `pd.to_datetime()` từ thư viện Pandas để chuyển đổi dữ liệu trong cột "Ngày" từ chuỗi sang định dạng datetime Định dạng datetime này sẽ giúp làm việc với dữ liệu thời gian một cách hiệu quả hơn.
● Sắp xếp lại dữ liệu theo thứ tự thời gian: Sử dụng phương thức `sort_values()` từ thư viện Pandas để sắp xếp lại DataFrame theo cột "Ngày" Điều này giúp có được dữ liệu được sắp xếp theo thứ tự thời gian từ trước đến sau.
● Chuyển đổi định dạng các cột giá thành số thực: Sử dụng phương thức `str.replace()` để loại bỏ dấu phẩy trong các giá trị trong cột "Đóng cửa", "Mở cửa", "Cao nhất", "Thấp nhất", sau đó sử dụng `astype(float)` để chuyển đổi các giá trị sang dạng số thực (float). Điều này cần thiết để có thể thực hiện các phép tính toán hoặc vẽ biểu đồ dựa trên các giá trị này một cách chính xác.
Trực quan hóa dữ liệu
Trực quan hóa dữ liệu là một bước rất quan trọng trong quá trình phân tích và hiểu dữ liệu Trực quan hóa dữ liệu giúp chúng ta nhìn vào dữ liệu một cách trực quan và dễ hiểu hơn Thay vì phải đọc hàng loạt các con số, chúng ta có thể nhìn vào biểu đồ để nắm bắt thông tin một cách nhanh chóng Biểu đồ cho phép chúng ta nhận ra các xu hướng, mô hình và biến động trong dữ liệu một cách trực quan Điều này giúp chúng ta hiểu rõ hơn về cách mà dữ liệu thay đổi theo thời gian hoặc các yếu tố khác Trực quan hóa dữ liệu còn cho phép chúng ta so sánh và phân tích các quan hệ giữa các biến một cách dễ dàng Bằng cách đặt các biến lên cùng một biểu đồ, chúng ta có thể thấy được mối tương quan hoặc khác biệt giữa chúng Biểu đồ giúp chúng ta trình bày thông tin một cách rõ ràng và hấp dẫn hơn Điều này làm cho dữ liệu dễ hiểu hơn cho người đọc và người xem Trực quan hóa dữ liệu giúp chúng ta đưa ra quyết định dựa trên thông tin số liệu một cách chính xác và đáng tin cậy hơn Việc thấy được dữ liệu trên biểu đồ giúp chúng ta đưa ra những quyết định thông minh và hợp lý hơn.
4.2.1 Biểu đồ giá cổ phiếu khi kết phiên của Vinamilk qua các năm
Hình 10: Code tạo biểu đồ giá kết phiên của Vinamilk qua các năm
Nhóm sử dụng phương thức `dt.year` của đối tượng datetime trong Pandas để trích xuất thông tin về năm từ cột "Ngày" Thông tin về năm được lưu vào một cột mới có tên là
"Năm" trong DataFrame `df` Tạo một figure với kích thước 10x5 inches bằng
`plt.figure(figsize=(10, 5))` Sử dụng `plt.plot()` để vẽ biểu đồ giá đóng cửa theo thời gian, với trục x là cột "Ngày" và trục y là cột "Đóng cửa" Đặt nhãn cho trục x là "Năm" và trục y là "Giá đóng cửa" bằng `plt.xlabel()` và `plt.ylabel()` Đặt tiêu đề cho biểu đồ bằng
`plt.title()` Thêm chú thích cho đường vẽ bằng `plt.legend()` để biểu thị là "Giá đóng cửa".
Sử dụng `YearLocator` để chỉ định vị trí của các năm trên trục x Sử dụng `DateFormatter` để định dạng hiển thị của các năm là chuỗi năm Thêm `MonthLocator` để xác định vị trí của các tháng trên trục x Sử dụng các phương thức `set_major_locator()` và
`set_major_formatter()` để áp dụng các định dạng và vị trí này cho trục x của biểu đồ Sử dụng `plt.tight_layout()` để loại bỏ các thành phần trùng lặp và tạo biểu đồ sao cho hợp lý.
Cuối cùng, sử dụng `plt.show()` để hiển thị biểu đồ ra màn hình.
Hình 11: Biểu đồ giá kết phiên của Vinamilk qua các năm
● Giá cổ phiếu VNM có xu hướng tăng trong giai đoạn này.
● Giá cổ phiếu có biến động mạnh trong từng năm, đặc biệt là trong giai đoạn 2017 - 2020.
● Giá cổ phiếu đạt đỉnh vào năm 2018 với mức giá hơn 149.000 đồng/cổ phiếu và đạt đáy vào năm 2012 với mức giá hơn 32.000 đồng/cổ phiếu.
Phân tích theo từng giai đoạn:
● Giai đoạn 2014 - 2016: Giá cổ phiếu VNM có xu hướng tăng nhẹ, với mức tăng trưởng trung bình khoảng 10% mỗi năm.
● Giai đoạn 2017 - 2020: Giá cổ phiếu VNM có biến động mạnh, với mức tăng trưởng cao nhất vào năm 2017 (hơn 70%) và mức giảm mạnh nhất vào năm 2020 (hơn 30%)
Biến động này chủ yếu do ảnh hưởng của các yếu tố kinh tế vĩ mô, như chiến tranh thương mại Mỹ - Trung Quốc và đại dịch COVID-19.
● Giai đoạn 2021 - 2024: Giá cổ phiếu VNM có xu hướng tăng ổn định, với mức tăng trưởng trung bình khoảng 15% mỗi năm.
4.2.2 Biểu đồ thể hiện mối tương quan giữa các biến
Hình 12: : Code vẽ biểu đồ Scatter matrix
Nhóm sử dụng biểu đồ scatter matrix - một công cụ hữu ích để hiểu mối quan hệ giữa các cặp biến trong bộ dữ liệu Mỗi điểm trên biểu đồ thể hiện một cặp giá trị từ hai biến khác nhau, và việc phân tán của các điểm có thể giúp phát hiện các mô hình, xu hướng hoặc sự tương quan giữa chúng `pd.plotting.scatter_matrix()` được nhóm sử dụng để vẽ biểu đồ scatter matrix từ DataFrame `df` với kích thước 12x8 inches Mỗi ô trong ma trận sẽ chứa một biểu đồ scatter plot cho mỗi cặp biến trong DataFrame Cuối cùng, `plt.show()` được sử dụng để hiển thị biểu đồ scatter matrix ra màn hình Điều này sẽ hiển thị một ma trận các biểu đồ scatter plot, mỗi cặp biến sẽ có một biểu đồ riêng, và các trục của các biểu đồ sẽ hiển thị các giá trị của các biến tương ứng.
Hình 13: Biểu đồ Scatter Matrix thể hiện mối tương quan giữa các biến
● Mức cao nhất và mức thấp nhất: Có mối tương quan dương mạnh Điều này có nghĩa là khi mức cao nhất tăng, mức thấp nhất cũng có xu hướng tăng và ngược lại.
● Mức cao nhất và mở cửa: Có mối tương quan dương trung bình Điều này có nghĩa là khi mức cao nhất tăng, giá mở cửa cũng có xu hướng tăng, nhưng mức độ tăng không mạnh bằng mức thấp nhất.
● Mức thấp nhất và mở cửa: Có mối tương quan dương trung bình Điều này có nghĩa là khi mức thấp nhất tăng, giá mở cửa cũng có xu hướng tăng, nhưng mức độ tăng không mạnh bằng mức cao nhất.
● Thời gian (năm) và mức cao nhất: Có mối tương quan dương yếu Điều này có nghĩa là theo thời gian, mức cao nhất có xu hướng tăng, nhưng mức độ tăng không mạnh.
● Thời gian (năm) và mức thấp nhất: Có mối tương quan dương yếu Điều này có nghĩa là theo thời gian, mức thấp nhất có xu hướng tăng, nhưng mức độ tăng không mạnh.
● Thời gian (năm) và mở cửa: Có mối tương quan dương yếu Điều này có nghĩa là theo thời gian, giá mở cửa có xu hướng tăng, nhưng mức độ tăng không mạnh.
Biểu đồ Scatter Matrix cho thấy mối quan hệ tương quan dương mạnh giữa giá đóng cửa, mức cao nhất và mức thấp nhất Điều này cho thấy rằng ba biến này có ảnh hưởng lẫn nhau và có thể được sử dụng để dự đoán giá trị của nhau Mối quan hệ giữa giá đóng cửa và giá mở cửa cũng tương quan dương, nhưng mức độ tương quan yếu hơn Mối quan hệ giữa giá đóng cửa và thời gian (năm) cũng tương quan dương, nhưng mức độ tương quan yếu nhất.
Nhóm sử dụng biểu đồ boxplot để có một cái nhìn tổng quan về phân phối của dữ liệu Chúng ta có thể xem được phần lớn dữ liệu tập trung ở đâu và phạm vi của dữ liệu là như thế nào.
Hình 14: Code tạo biểu đồ Boxplot Đầu tiên, thư viện seaborn được nhóm import để sử dụng chức năng vẽ biểu đồ Boxplot DataFrame `df_boxplot` được tạo bằng cách chọn các cột "Đóng cửa", "Mở cửa",
"Cao nhất", "Thấp nhất" từ DataFrame gốc `df` Bằng cách sử dụng phương thức
`astype(float)`, các giá trị trong DataFrame `df_boxplot` được chuyển đổi thành dạng số thực.
Xây dựng và huấn luyện mô hình học máy
Nhóm sẽ xây dựng và huấn luyện mô hình học máy trong quá trình phân tích dữ liệu nhằm mục tiêu chính là tạo ra các mô hình có khả năng dự đoán giá cổ phiếu trong tương lai dựa trên các mẫu đã được huấn luyện trước đó
Tạo một DataFrame mới `df1` chỉ chứa cột 'Đóng cửa' và có chỉ số là cột 'Ngày' từDataFrame gốc.
Hình 30: Code tạo Data frame mới
Sử dụng `pd.DataFrame(df,columns=['Ngày','Đóng cửa'])`: Tạo một Data Frame mới.
`df1.index = df1.Ngày`: Gán cột 'Ngày' của DataFrame mới `df1` làm chỉ số (index) của DataFrame, điều này có nghĩa là cột 'Ngày' sẽ được sử dụng để chỉ mục các dòng trong DataFrame thay vì chỉ mục mặc định từ 0 đến n-1 `df1.drop('Ngày',axis=1,inplace=True)`:
Loại bỏ cột 'Ngày' khỏi DataFrame `df1` Tham số `axis=1` chỉ ra rằng ta muốn loại bỏ một cột, và `inplace=True` cho phép thực hiện thay đổi trực tiếp trên DataFrame `df1` thay vì tạo ra một bản sao mới.
Tiếp theo nhóm sẽ chia dữ liệu thành các tập huấn luyện và kiểm tra để đánh giá hiệu suất của mô hình trên dữ liệu mới mà nó chưa từng thấy Điều này giúp đảm bảo rằng mô hình có khả năng tổng quát hóa và dự đoán tốt trên dữ liệu thực tế.
Hình 32: Code chia tập dữ liệu thành 2 tập
`data = df1.values`: Chuyển DataFrame `df1` thành một mảng NumPy, trong đó mỗi hàng của DataFrame trở thành một mảng con (array) trong mảng NumPy Điều này làm cho việc xử lý dữ liệu dễ dàng hơn khi sử dụng các thư viện học máy `train_data = data[:1500]`:
Chia dữ liệu thành tập huấn luyện Ở đây, `train_data` chứa 1500 hàng đầu tiên của mảng
`data`, tức là dữ liệu từ dòng đầu tiên đến dòng thứ 1500 `test_data = data[1500:]`: Chia dữ liệu thành tập kiểm tra `test_data` chứa các hàng còn lại của mảng `data`, tức là dữ liệu từ dòng 1500 trở đi.
Nhóm sẽ tiến hành chuẩn hóa dữ liệu
Hình 33: Code chuẩn hóa dữ liệu
`MinMaxScaler(feature_range=(0,1))`: Tạo một đối tượng `MinMaxScaler` để chuẩn hóa dữ liệu `MinMaxScaler` được sử dụng để chuyển đổi dữ liệu sao cho nó nằm trong khoảng [0, 1] `sc_train = sc.fit_transform(data)`: Sử dụng phương thức `fit_transform` của đối tượng `MinMaxScaler` để chuẩn hóa dữ liệu Phương thức này thực hiện hai bước:
Bước 1: Phương thức `fit` sẽ tính toán các tham số (min, max) cần thiết cho việc chuẩn hóa từ dữ liệu huấn luyện (`train_data`).
Bước 2: Phương thức `transform` sẽ áp dụng các tham số đã tính được từ bước trước vào dữ liệu (`data`), biến đổi nó sao cho nằm trong khoảng [0, 1].
Kết quả cuối cùng là `sc_train`, một mảng NumPy chứa dữ liệu đã được chuẩn hóa.
Tạo vòng lặp các giá trị Vòng lặp được sử dụng để tạo dữ liệu huấn luyện cho mô hình dự đoán chuỗi thời gian
Hình 34: Code tạo vòng lặp
`x_train`: Là một danh sách (list) chứa các mảng con (array) biểu diễn các mẫu đầu vào (input) cho mô hình huấn luyện Mỗi mẫu đầu vào được tạo bằng cách lấy 50 giá trị đóng cửa liên tiếp từ dữ liệu đã được chuẩn hóa (`sc_train`) Do đó, `x_train` sẽ chứa các mảng có kích thước (50, 1) với 50 giá trị đóng cửa `y_train`: Là một danh sách chứa các giá trị mục tiêu (target) tương ứng với mỗi mẫu đầu vào trong `x_train` Giá trị mục tiêu là giá đóng cửa của ngày tiếp theo sau 50 ngày đã được chọn Cụ thể, với mỗi vòng lặp từ `iP` đến
`len(train_data)`, ta lấy 50 giá trị đóng cửa từ dữ liệu chuẩn hóa (`sc_train`) và thêm chúng vào danh sách `x_train`, sau đó lấy giá trị đóng cửa của ngày tiếp theo và thêm vào danh sách
`y_train` Điều này tạo ra cặp dữ liệu huấn luyện `(x_train[i], y_train[i])` cho mỗi vòng lặp
Biến `x_train` là một danh sách chứa các mảng con, mỗi mảng con đại diện cho một mẫu dữ liệu đầu vào cho mô hình huấn luyện Mỗi mảng con này chứa 50 giá trị đóng cửa liên tiếp từ dữ liệu đã được chuẩn hóa
Trong đó, mỗi mảng con có kích thước (50,) và chứa 50 giá trị đóng cửa liên tiếp.
Tổng số mảng con trong `x_train` sẽ bằng `len(train_data) - 50` vì cần ít nhất 50 giá trị liên tiếp để tạo một mẫu đầu vào hoàn chỉnh.
Biến `y_train` là một danh sách chứa các giá trị mục tiêu tương ứng với mỗi mẫu dữ liệu đầu vào trong `x_train` Mỗi giá trị này đại diện cho giá đóng cửa của ngày tiếp theo sau50 ngày đã được chọn
Số lượng giá trị trong `y_train` sẽ bằng số lượng mẫu dữ liệu trong `x_train`, nghĩa là
Hình 37: Code chia dữ liệu thành các mảng
`np.array(x_train)`: Chuyển đổi danh sách `x_train` thành một mảng NumPy Điều này sẽ tạo ra một mảng 2D, trong đó mỗi hàng đại diện cho một mẫu dữ liệu đầu vào, và mỗi cột chứa các giá trị đóng cửa trong mỗi mẫu `np.array(y_train)`: Chuyển đổi danh sách
`y_train` thành một mảng NumPy Mảng này sẽ chứa giá trị mục tiêu tương ứng với mỗi mẫu dữ liệu đầu vào trong `x_train` `np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1))`:
Sử dụng phương thức `reshape` của NumPy để thay đổi hình dạng của mảng `x_train` từ 2D thành 3D Kích thước mới sẽ là `(số mẫu, số lượng giá trị đóng cửa trong mỗi mẫu, 1)` Điều này làm cho dữ liệu đầu vào phù hợp với đầu vào của một mô hình LSTM, trong đó cần có kích thước (số mẫu, số lượng bước thời gian, số lượng đặc trưng) `np.reshape(y_train,(y_train.shape[0], 1))`: Tương tự như trên, cũng thay đổi hình dạng của mảng `y_train` thành một mảng 2D, với mỗi hàng chứa một giá trị mục tiêu Điều này làm cho dữ liệu mục tiêu phù hợp với đầu ra của mô hình LSTM.
Tiếp theo nhóm sẽ sử dụng thư viện Keras để xây dựng một mô hình mạng nơ-ron sử dụng kiến trúc LSTM (Long Short-Term Memory)
Hình 38: Code xây dựng mô hình
`model = Sequential()`: Khởi tạo một mô hình tuần tự, tức là một chuỗi các lớp xếp chồng lên nhau `model.add(LSTM(units8, input_shape=(x_train.shape[1], 1), return_sequences=True))`: Thêm một lớp LSTM với 128 đơn vị (units) vào mô hình Đây là lớp đầu tiên trong mạng, nó nhận đầu vào có kích thước `(x_train.shape[1], 1)` (số lượng bước thời gian trong mỗi mẫu và số lượng đặc trưng là 1), và trả về chuỗi các đầu ra (return_sequences=True) `model.add(LSTM(unitsd))`: Thêm một lớp LSTM với 64 đơn vị vào mô hình Lớp này không trả về chuỗi các đầu ra, chỉ trả về đầu ra của bước thời gian cuối cùng (mặc định là False) `model.add(Dropout(0.5))`: Thêm một lớp Dropout với tỷ lệ loại bỏ 50% Lớp này giúp giảm nguy cơ overfitting bằng cách loại bỏ một phần các đơn vị (neurons) trong quá trình huấn luyện `model.add(Dense(1))`: Thêm một lớp Dense (hoàn toàn kết nối) với 1 đơn vị, là lớp đầu ra của mô hình.
Tái sử dụng mô hình
Hình 42: Code xử lý dữ liệu test
`test = df1[len(train_data)-50:].values`: Lấy dữ liệu kiểm tra từ tập dữ liệu gốc, bắt đầu từ vị trí cuối của tập dữ liệu huấn luyện và lấy 50 mẫu dữ liệu `test = test.reshape(-1,1)`:
Reshape dữ liệu kiểm tra để phù hợp với quy định đầu vào của mô hình `sc_test sc.transform(test)`: Chuẩn hóa dữ liệu kiểm tra theo phạm vi đã được sử dụng trong quá trình huấn luyện Tiếp theo, chuẩn bị dữ liệu kiểm tra (`x_test`) bằng cách chia thành các cửa sổ có độ dài 50 giá trị giống như quá trình chuẩn bị dữ liệu huấn luyện `y_test = data[1500:]`: Lấy giá trị thực tế của dữ liệu kiểm tra từ vị trí 1500 trở đi `y_test_predict final_model.predict(x_test)`: Dùng mô hình để dự đoán giá đóng cửa trên dữ liệu kiểm tra.
`y_test_predict = sc.inverse_transform(y_test_predict)`: Chuyển đổi lại giá trị dự đoán từ dạng chuẩn hóa về dạng ban đầu để có thể so sánh với giá trị thực tế.
Nhóm sẽ vẽ biểu đồ để quan sát độ chính xác của mô hình
Hình 43: Code biểu đồ so sánh giá trị dự đoán
`train_data1` và `test_data1` là hai phần của dữ liệu gốc được chia thành tập huấn luyện và tập kiểm tra Dữ liệu dự đoán từ cả tập huấn luyện và tập kiểm tra được thêm vào tập dữ liệu huấn luyện và kiểm tra tương ứng Biểu đồ được vẽ để so sánh giá trị thực tế với giá trị dự đoán trên cả tập huấn luyện và tập kiểm tra Các đường màu đỏ là giá trị thực tế, đường màu xanh lá cây là giá trị dự đoán trên tập huấn luyện và đường màu xanh dương là giá trị dự đoán trên tập kiểm tra
Hình 44: Biểu đồ so sánh giá dự báo và giá thực tế
Dựa trên biểu đồ so sánh giá dự đoán và giá thực tế của cổ phiếu Vinamilk được cung cấp, có thể nhận thấy:
● Độ lệch giữa giá dự đoán và giá thực tế: Độ lệch giữa giá dự đoán và giá thực tế tương đối nhỏ trong hầu hết các thời điểm.
● Xu hướng của giá dự đoán: Xu hướng của giá dự đoán phù hợp với xu hướng của giá thực tế.
● Độ biến động của giá dự đoán: Độ biến động của giá dự đoán phù hợp với độ biến động của giá thực tế.
⇒ Dựa trên phân tích biểu đồ so sánh giá dự đoán và giá thực tế của cổ phiếu Vinamilk, có thể nhận thấy mô hình dự đoán giá cổ phiếu có hiệu quả tương đối tốt
Nhóm tiếp tục đo lường độ sai số trên tập train và tập test
Hình 45: Code đo lường sai số trên tập train
Hình 46: Code đo lường sai số trên tập test Độ phù hợp được tính bằng hàm `r2_score`, nó đo lường mức độ phù hợp giữa dữ liệu thực tế và dữ liệu dự đoán bởi mô hình trên tập huấn luyện và test Kết quả càng gần 1 thì mô hình càng phù hợp với dữ liệu Sai số tuyệt đối trung bình (MAE) được tính bằng hàm
`mean_absolute_error`, nó đo lường độ lớn trung bình của sự chênh lệch giữa giá trị thực tế và giá trị dự đoán trên tập huấn luyện và test Phần trăm sai số tuyệt đối trung bình (MAPE) được tính bằng hàm `mean_absolute_percentage_error`, nó đo lường tỉ lệ phần trăm trung bình của sai số tuyệt đối giữa giá trị thực tế và giá trị dự đoán trên tập huấn luyện và test Đây là một phép đo thường được sử dụng để đánh giá sự chính xác của mô hình.
Hình 47: Kết quả đo lường của tập train
Kết quả đo lường trên tập huấn luyện rất tích cực: Độ phù hợp (R2): Độ phù hợp trên tập huấn luyện là 0.991, gần với 1.0 Điều này cho thấy mô hình giải thích được hầu hết sự biến thiên của dữ liệu.
Sai số tuyệt đối trung bình (MAE): Sai số trung bình trên tập huấn luyện là khoảng 1,419.87 VNĐ Điều này có nghĩa là, trung bình, mô hình dự đoán sai số khoảng 1,419.87 VNĐ so với giá trị thực tế.
Phần trăm sai số tuyệt đối trung bình (MAPE): Phần trăm sai số trung bình trên tập huấn luyện là khoảng 1.33% Điều này chỉ ra rằng, trên mức trung bình, mô hình dự đoán sai số khoảng 1.33% so với giá trị thực tế.
⇒ Tổng thể, các kết quả này cho thấy mô hình khá tốt trên tập huấn luyện
Hình 48: Kết quả đo lường của tập test
Kết quả đo lường trên tập test cũng rất đáng khích lệ: Độ phù hợp (R2): Độ phù hợp trên tập kiểm tra là 0.980, gần với 1.0 Điều này cho thấy mô hình vẫn giữ được tính tổng quát và khả năng dự đoán tốt trên dữ liệu mới.
Sai số tuyệt đối trung bình (MAE): Sai số trung bình trên tập kiểm tra là khoảng 1,252.24 VNĐ, cũng khá thấp Điều này có nghĩa là mô hình dự đoán giá trị sai số trung bình khoảng 1,252.24 VNĐ so với giá trị thực tế.
Phần trăm sai số tuyệt đối trung bình (MAPE): Phần trăm sai số trung bình trên tập kiểm tra là khoảng 1.55%, cũng tương đối thấp Điều này chỉ ra rằng mô hình dự đoán sai số khoảng 1.55% so với giá trị thực tế trên mức trung bình.
Tổng thể, kết quả này cũng chứng tỏ mô hình vẫn giữ được độ chính xác và hiệu suất tốt trên cả tập huấn luyện và tập kiểm tra Điều này là một dấu hiệu tích cực về tính tổng quát và khả năng dự đoán của mô hình.
Tiếp theo nhóm sẽ dự đoán giá cổ phiếu trong tương lai:
Hình 49: Code dự báo giá cổ phiếu tương lai
Hình 50: Code vẽ biểu đồ mới với dự đoán cho ngày tiếp theo
Nhóm sử dụng hàm `iloc[-1]` để lấy ngày cuối cùng trong tập dữ liệu, sau đó tăng thêm 1 ngày để lấy ngày kế tiếp Sử dụng `transform` để chuẩn hóa giá trị đóng cửa của ngày cuối cùng Sử dụng 50 giá trị cuối cùng trong tập dữ liệu để dự đoán giá đóng cửa của ngày tiếp theo Tạo một DataFrame mới chứa ngày và giá dự đoán của ngày kế tiếp và nối nó vào DataFrame gốc Vẽ biểu đồ so sánh giá dự báo và giá thực tế, bao gồm cả dự đoán cho ngày kế tiếp Điều này giúp xem xét sự phù hợp của mô hình dự báo với dữ liệu thực tế và dự đoán tiếp theo.
Hình 51: Biểu đồ giá dự báo
Hình 52: Code in ra giá trị dự báo