1. library(readr)
2. library(dplyr)
3. library(ggplot2)
4. library(scales)
5. library(tidyr)
6. library(readr)
7. Sales <- read_csv("D:/100000 Sales Records.csv")
8. colnames(Sales) <- c("Region","Country", "Item.Type", "Sales.Channel",
9. "Order.Priority" ,"Order.Date","Order.ID" ,"Ship.Date",
10. "Units.Sold","Unit.Price", "Unit.Cost", "Total.Revenue",
11. "Total.Cost", "Total.Profit")
12. options(scipen = 999)
13. comma_vn <- function(x) {
14. format(x, big.mark = ".", decimal.mark = ",", scientific = FALSE)
15. }
Nhận xét: Kết quả in ra cho thấy bộ dữ liệu gồm 100.000 dòng và 14 cột, trong đó có 7 biến ký tự là Region, Country, Item.Type, Sales.Channel, Order.Priority, Order.Date, Ship.Date và 7 biến số là Units.Sold, Unit.Price, Unit.Cost, Total.Revenue, Total.Cost, Total.Profit. Đây là một bộ dữ liệu lớn, có cấu trúc rõ ràng và bao quát nhiều khía cạnh trong hoạt động bán hàng.
Giải thích:
library(readr): tải thư viện xử lý dữ liệu văn bản nhanh, cần thiết để đọc file CSV lớn.Sales <- read_csv("D:/100000 Sales Records.csv"): đọc toàn bộ file vào biến Sales, mỗi dòng thành một giao dịch, mỗi cột lưu một đặc tính.colnames(Sales) <- c(...): đặt lại tên cột, mỗi tên thể hiện rõ khái niệm: khu vực, quốc gia, loại hàng, kênh bán, mức ưu tiên, ngày đặt, mã đơn, ngày giao, số lượng, giá bán lẻ, chi phí từng mặt hàng, doanh thu, chi phí toàn đơn, lợi nhuận toàn đơn.
1. meaning_variable <- data.frame(
2. Ten_bien = c("Region", "Country", "Item.Type", "Sales.Channel", "Order.Priority",
3. "Order.Date", "Order.ID", "Ship.Date", "Units.Sold", "Unit.Price",
4. "Unit.Cost", "Total.Revenue", "Total.Cost", "Total.Profit"),
5. Y_Nghia = c("Châu lục", "Đất nước", "Loại hàng hóa", "Kênh bán hàng",
6. "Mức độ ưu tiên cho đơn hàng", "Ngày đặt hàng", "Mã vận đơn",
7. "Ngày giao hàng", "Số lượng hàng hóa bán ra", "Giá của một đơn vị hàng hóa",
8. "Giá để sản xuất một đơn vị hàng hóa", "Tổng doanh thu",
9. "Tổng chi phí", "Tổng lợi nhuận"))
10. print(meaning_variable)
## Ten_bien Y_Nghia
## 1 Region Châu lục
## 2 Country Đất nước
## 3 Item.Type Loại hàng hóa
## 4 Sales.Channel Kênh bán hàng
## 5 Order.Priority Mức độ ưu tiên cho đơn hàng
## 6 Order.Date Ngày đặt hàng
## 7 Order.ID Mã vận đơn
## 8 Ship.Date Ngày giao hàng
## 9 Units.Sold Số lượng hàng hóa bán ra
## 10 Unit.Price Giá của một đơn vị hàng hóa
## 11 Unit.Cost Giá để sản xuất một đơn vị hàng hóa
## 12 Total.Revenue Tổng doanh thu
## 13 Total.Cost Tổng chi phí
## 14 Total.Profit Tổng lợi nhuận
Giải thích:
data.frame(...): tạo bảng định nghĩa biến, gồm tên biến (Ten_bien) và ý nghĩa tiếng Việt (Y_Nghia). Từng tên cột ứng với một trường thông tin; bảng này dùng để tra cứu nhanh ý nghĩa khi đọc code hoặc phân tích dữ liệu.
1. sapply(Sales, class)
## Region Country Item.Type Sales.Channel Order.Priority
## "character" "character" "character" "character" "character"
## Order.Date Order.ID Ship.Date Units.Sold Unit.Price
## "character" "numeric" "character" "numeric" "numeric"
## Unit.Cost Total.Revenue Total.Cost Total.Profit
## "numeric" "numeric" "numeric" "numeric"
Nhận xét: Bộ dữ liệu gồm các biến character như: Region, Country, Item.Type, Sales.Channel, Order.Priority, Order.Date, Ship.Date. Các biến numeric gồm: Order.ID, Units.Sold, Unit.Price, Unit.Cost, Total.Revenue, Total.Cost, Total.Profit .
1. str(Sales)
## spc_tbl_ [100,000 × 14] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ Region : chr [1:100000] "Middle East and North Africa" "Central America and the Caribbean" "Sub-Saharan Africa" "Sub-Saharan Africa" ...
## $ Country : chr [1:100000] "Azerbaijan" "Panama" "Sao Tome and Principe" "Sao Tome and Principe" ...
## $ Item.Type : chr [1:100000] "Snacks" "Cosmetics" "Fruits" "Personal Care" ...
## $ Sales.Channel : chr [1:100000] "Online" "Offline" "Offline" "Online" ...
## $ Order.Priority: chr [1:100000] "C" "L" "M" "M" ...
## $ Order.Date : chr [1:100000] "10/8/2014" "2/22/2015" "12/9/2015" "9/17/2014" ...
## $ Order.ID : num [1:100000] 535113847 874708545 854349935 892836844 129280602 ...
## $ Ship.Date : chr [1:100000] "10/23/2014" "2/27/2015" "1/18/2016" "10/12/2014" ...
## $ Units.Sold : num [1:100000] 934 4551 9986 9118 5858 ...
## $ Unit.Price : num [1:100000] 152.58 437.2 9.33 81.73 668.27 ...
## $ Unit.Cost : num [1:100000] 97.44 263.33 6.92 56.67 502.54 ...
## $ Total.Revenue : num [1:100000] 142510 1989697 93169 745214 3914726 ...
## $ Total.Cost : num [1:100000] 91009 1198415 69103 516717 2943879 ...
## $ Total.Profit : num [1:100000] 51501 791282 24066 228497 970846 ...
## - attr(*, "spec")=
## .. cols(
## .. Region = col_character(),
## .. Country = col_character(),
## .. `Item Type` = col_character(),
## .. `Sales Channel` = col_character(),
## .. `Order Priority` = col_character(),
## .. `Order Date` = col_character(),
## .. `Order ID` = col_double(),
## .. `Ship Date` = col_character(),
## .. `Units Sold` = col_double(),
## .. `Unit Price` = col_double(),
## .. `Unit Cost` = col_double(),
## .. `Total Revenue` = col_double(),
## .. `Total Cost` = col_double(),
## .. `Total Profit` = col_double()
## .. )
## - attr(*, "problems")=<externalptr>
Nhận xét: Kết quả cho thấy bộ dữ liệu gồm 100.000 dòng và 14 cột, trong đó có 7 biến ký tự là Region, Country, Item.Type, Sales.Channel, Order.Priority, Order.Date, Ship.Date và 7 biến số là Units.Sold, Unit.Price, Unit.Cost, Total.Revenue, Total.Cost, Total.Profit.
Giải thích:
str(Sales): hiện thông tin chi tiết, gồm số dòng, số cột, tên từng trường, kiểu dữ liệu (chữ hoặc số), một vài mẫu giá trị. Kết quả giúp xác định biến số, biến chữ, biến ngày tháng để chọn thao tác phù hợp cho phân tích về sau.
1. dim(Sales)
## [1] 100000 14
Nhận xét: Kết quả cho thấy bộ dữ liệu gồm 100.000 dòng và 14 biến.
1. table(Sales$Region)
##
## Asia Australia and Oceania
## 14547 8113
## Central America and the Caribbean Europe
## 10731 25877
## Middle East and North Africa North America
## 12580 2133
## Sub-Saharan Africa
## 26019
Nhận xét: Kết quả thống kê cho thấy số lượng đơn hàng được phân bổ rất khác biệt giữa các khu vực địa lý. Khu vực Sub-Saharan Africa chiếm số lượng đơn hàng lớn nhất với 26.019 đơn, tiếp đó là Europe với 25.877 đơn và Asia với 14.547 đơn. Ngược lại, North America chỉ có 2.133 đơn, thấp nhất trong bảng, phản ánh mức độ hoạt động bán hàng còn hạn chế tại đây. Australia and Oceania ghi nhận 8.113 đơn còn Middle East and North Africa có 12.580 đơn, vẫn ở mức trung bình so với các khu vực khác. Những số liệu này giúp chỉ ra khu vực trọng điểm cần tập trung nguồn lực kinh doanh và nhận diện được các vùng tiềm năng hoặc vùng cần điều chỉnh chính sách bán hàng để tối ưu doanh thu và lợi nhuận.
Giải thích:
table(Sales$Region): đếm số lần xuất hiện của từng khu vực trong cột Region.
Giải thích: Hàm
summary()cho 5 giá trị thống kê cơ bản: min, Q1, median, mean, Q3, max – là nền tảng để nhận diện phân bố dữ liệu.
1. summary(Sales$Units.Sold)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1 2505 5007 5001 7495 10000
Nhận xét: Phân bố khá đều, từ 1 đến 10.000, với trung vị và trung bình gần nhau (5.007 và 5.001), chứng tỏ không có nhiều ngoại lệ lớn, không bị lệch mạnh về một phía. Độ phân tán ổn định, tứ phân vị 1: 2.505, tứ phân vị 3: 7.495. Các sản phẩm bán ra đều, không hiện tượng quá thừa hoặc quá thiếu hàng tồn. Sản lượng tốt, thể hiện doanh nghiệp đang vận hành ổn định
1. summary(Sales$Unit.Price)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 9.33 109.28 205.70 266.70 437.20 668.27
Nhận xét: Khoảng giá mở rộng (từ 9,33 đến 668,27), trung vị: 205,70 và trung bình: 266,70 thì trung bình lớn hơn trung vị, cho thấy có một số mặt hàng giá cao kéo giá trị trung bình lên. Sản phẩm đa dạng phân khúc từ giá rẻ đến cao cấp. Doanh nghiệp có thể tiếp cận nhiều tệp khách hàng và tối ưu hóa doanh thu.
1. summary(Sales$Unit.Cost)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 6.92 56.67 117.11 188.02 364.69 524.96
Nhận xét: Khoảng chi phí từ 6,92 đến 524,96, trung vị: 117,11, trung bình: 188,02, thì trung bình lớn hơn trung vị, cho thấy có một số mặt hàng giá cao kéo giá trị trung bình lên. Sản phẩm đa dạng phân khúc từ giá rẻ đến cao cấp. Doanh nghiệp có thể tiếp cận nhiều tệp khách hàng và tối ưu hóa doanh thu.
1. summary(Sales$Total.Revenue)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 18.7 279753.3 789891.6 1336066.7 1836489.6 6682700.0
Nhận xét: Dao động rộng từ 18,7 đến 6.682.700, trung vị: 789.891, trung bình: 1.336.066, trung bình lớn hơn trung vị, cho thấy doanh thu bị lệch phải, doanh thu bị ảnh hưởng bởi một số giao dịch lớn. Hoạt động kinh doanh mang lại nguồn thu tốt, có những hợp đồng/giao dịch lớn giúp cải thiện kết quả tổng thể.
1. summary(Sales$Total.Cost)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 13.8 162928.3 467937.4 941975.5 1209474.7 5249075.0
Nhận xét: Có thể thấy dao động từ 14 đến 5.249.075, với trung vị là 467.937,4 và trung bình là 941.975,5. Việc trung bình lớn hơn trung vị cho thấy dữ liệu bị lệch phải, Điều này cho thấy rằng đa phần chi phí tương đối vừa phải, nhưng vẫn tồn tại một vài chi phí cực đại.
1. summary(Sales$Total.Profit)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 4.82 95900.00 283657.46 394091.24 568384.13 1738700.00
Nhận xét: Biến động từ 4,8 đến 1.738.700, trung vị 28.365,5 , trung bình 394.091,2, trung bình lớn hơn trung vị, cho thấy có một số nguồn lợi nhuận cực lớn làm trung bình bị kéo lên. Có thể do tình hình kinh doanh khả quan hoặc có nhiều sản phẩm/dịch vụ sinh lợi vượt trội.
1. sapply(Sales,function(Sales) sum(is.na(Sales)))
## Region Country Item.Type Sales.Channel Order.Priority
## 0 0 0 0 0
## Order.Date Order.ID Ship.Date Units.Sold Unit.Price
## 0 0 0 0 0
## Unit.Cost Total.Revenue Total.Cost Total.Profit
## 0 0 0 0
Nhận xét:Kết quả kiểm tra trả về toàn bộ giá trị bằng 0, nghĩa là không có bất kỳ giá trị thiếu nào trong 14 cột dữ liệu. Đây là một kết quả tốt vì dữ liệu đầy đủ, không bị NA. Điều này có nghĩa là không cần áp dụng thêm bất kỳ phương pháp xử lý bổ sung khác. Nhờ đó, các phân tích tiếp theo như tính tổng doanh thu, lợi nhuận hay vẽ biểu đồ đều đảm bảo chính xác và đáng tin cậy, không bị ảnh hưởng bởi lỗi thiếu dữ liệu.
Giải thích:
sapply(...): áp dụng kiểm tra cho từng cột trong bảng Sales, trả về một số cho mỗi cột.sum(is.na(Sales)): đếm tổng số giá trị bị thiếu trong mỗi cột, các giá trị thiếu được hàm is.na trả về TRUE.- Khi toàn bộ số lượng NA là 0, khẳng định dữ liệu đầy đủ, không có trường hợp bị trống, đảm bảo phân tích sau luôn chính xác và liền mạch.
1. Sales[duplicated(Sales),]
Nhận xét: Kết quả hiển thị là một bảng rỗng (# A tibble: 0 x 14), nghĩa là không có dòng dữ liệu nào bị trùng lặp. Kết quả này rất tốt vì đảm bảo các phép tính tổng hợp như doanh thu hoặc lợi nhuận không bị sai lệch do dữ liệu trùng. Dữ liệu có độ tin cậy cao và phản ánh đúng thực tế
Giải thích:
duplicated(Sales): kiểm tra từng dòng của bảng, trả về TRUE nếu dòng này trùng hoàn toàn với dòng phía trước.Sales[duplicated(Sales),]: lọc ra các dòng trùng, nếu bảng kết quả rỗng thì dữ liệu không bị lặp lại.
1. scale <- function(x){
2. if (!is.numeric(x)) {
3. message("Cot khong phai dang so. Khong the chuan hoa.")
4. return(NULL)}
5.
6. # Neu tat ca gia tri giong nhau
7. if (max(x) == min(x)) {
8. message("Tat ca gia tri giong nhau. Tra ve toan 0.")
9. return(rep(0, length(x)))}
10.
11. # Chuan hoa ve khoang [0, 1]
12. scaled <- (x - min(x)) / (max(x) - min(x))
13. return(scaled)}
Nhận xét: Việc chuẩn hóa giúp đưa các biến về cùng thang đo, thuận tiện khi so sánh hoặc vẽ biểu đồ. Đây là bước cần thiết trong các phân tích thống kê hoặc mô hình hóa vì nó giúp loại bỏ sự khác biệt về đơn vị đo lường giữa các biến (ví dụ doanh thu tính bằng triệu đồng trong khi giá đơn vị tính bằng nghìn đồng).
Giải thích:
- Dòng 1:
scale <- function(x){ ... }Định nghĩa một hàm tên là scale, nhận đối số là biến x (có thể là một vector).- Dòng 2:
if (!is.numeric(x)) { ... }: Kiểm tra nếu x không phải là kiểu số (numeric), thì: message(“Cot khong phai dang so. Khong the chuan hoa.”): Thông báo trên màn hình rằng cột không phải dạng số.return(NULL): Trả về giá trị rỗng, kết thúc hàm (không báo lỗi).- Dòng 7: Kiểm tra nếu tất cả giá trị trong x đều giống nhau (giá trị lớn nhất bằng giá trị nhỏ nhất):
message("Tat ca gia tri giong nhau. Tra ve toan 0."): Thông báo trên màn hình.return(rep(0, length(x))): Trả về một vector toàn giá trị 0, độ dài bằng độ dài của x.- Dòng 12: là công thức chuẩn hóa min-max, đưa mọi giá trị về khoảng từ 0 đến 1. Từng phần tử sẽ lấy giá trị trừ giá trị nhỏ nhất rồi chia cho hiệu số lớn nhất - nhỏ nhất
- Dòng 13:
return(scaled): Trả về vector đã chuẩn hóa.
1. Total.Profit <- as.data.frame(scale(Sales$Total.Profit))
2. colnames(Total.Profit) <- c("scale.Pr")
3. print(head(Total.Profit))
## scale.Pr
## 1 0.02961758
## 2 0.45509849
## 3 0.01383879
## 4 0.13141594
## 5 0.55837362
## 6 0.04852935
Nhận xét: Việc chuẩn hóa giúp đưa các biến về cùng thang đo, thuận tiện khi so sánh hoặc vẽ biểu đồ. Đây là bước cần thiết trong các phân tích thống kê hoặc mô hình hóa vì nó giúp loại bỏ sự khác biệt về đơn vị đo lường giữa các biến (ví dụ doanh thu tính bằng triệu đồng trong khi giá đơn vị tính bằng nghìn đồng).
Giải thích:
Total.Profit <- as.data.frame(scale(Sales$Total.Profit)): áp dụng hàm scale đã định nghĩa ở bước trước để chuẩn hóa toàn bộ giá trị từ cột Total.Profit trong bảng Sales. Kết quả chuẩn hóa được chuyển sang kiểu bảng dữ liệu bằngas.data.frame.colnames(Total.Profit) <- c("scale.Pr"): đặt lại tên cột cho bảng dữ liệu chuẩn hóa vừa tạo với tên cột là “scale.Pr”.
1. scale(Sales$Region)
## NULL
Nếu bộ dữ liệu không dưới dạng numeric, kết quả sẽ trả về “Cot khong phai dang so. Khong the chuan hoa” đúng như mục tiêu ban đầu khi viết một hàm mới
1. scale(Sales$Date) #kiểm tra xem việc chuẩn hóa diễn ra ntn
## NULL
1. Sales$Order.Priority[Sales$Order.Priority == "C"] <- "Critical"
2. Sales$Order.Priority[Sales$Order.Priority == "H"] <- "High"
3. Sales$Order.Priority[Sales$Order.Priority == "M"] <- "Medium"
4. Sales$Order.Priority[Sales$Order.Priority == "L"] <- "Low"
5. Tranform_Order_Priority <- Sales %>%
6. mutate(Order.Priority = as.numeric(factor(Order.Priority,
7. levels = c("Low","Medium","High","Critical"))))
8. Tranform_Order_Priority[, 5]
Nhận xét: Đầu tiên, các ký hiệu “C”, “H”, “M”, “L” trong cột Order.Priority được thay thế lần lượt bằng “Critical”, “High”, “Medium” và “Low” để dữ liệu dễ hiểu và thuận tiện cho phân tích. Sau đó, dữ liệu được phân tổ theo loại hàng (Item.Type) và độ ưu tiên (Order.Priority) để xem xét mức doanh thu tương ứng.
Giải thích:
Hàm factor()tạo các cấp độ (levels) có thứ tự rõ ràng, sau đó as.numeric() biến chúng thành số để thuận tiện cho tính toán, phân tích thống kê và mô hình hóa. Cột Order.Priority được chuyển từ dạng ký tự thành giá trị số (1–4) theo thứ tự ưu tiên: Low = 1, Medium = 2, High = 3, Critical = 4.
1. Sales$Order.Date <- as.Date(Sales$Order.Date, format = "%m/%d/%Y")
2. Sales$Ship.Date <- as.Date(Sales$Ship.Date, format = "%m/%d/%Y")
Giải thích: Hai dòng lệnh chuyển đổi cột Order.Date và Ship.Date từ kiểu ký tự (character) sang kiểu ngày tháng (Date) bằng hàm as.Date(). Định dạng ngày theo chuẩn “%m/%d/%Y” phù hợp với dữ liệu gốc, giúp R nhận diện chính xác kiểu dữ liệu ngày tháng.
1. library(ggplot2)
2. ggplot(Sales, aes(y = Units.Sold)) +
3. geom_boxplot(fill = "skyblue", color = "darkblue", width = 0.4, outlier.color = "red") +
4. labs(title = "Phân bố số lượng bán ra (Units Sold)",
5. y = "Units Sold") +
6. theme_minimal(base_size = 13)
Nhận xét: Số lượng sản phẩm bán ra dao động từ 1 đến 10.000 sản phẩm, thể hiện sự khác biệt lớn giữa các đơn hàng. Lượng lớn đơn hàng có lượng bán nằm trong khoảng 2.500 – 7.500 sản phẩm, được giới hạn bởi hai tứ phân vị thứ nhất và thứ 3. Giá trị trung vị (Q2 = 5.00) nằm gần giữa hộp, cho thấy dữ liệu phân bố khá cân đối quanh mức trung bình.
1. library(ggplot2)
2. library(scales)
3. comma_vn <- function(x) {
4. format(x, big.mark = ".", decimal.mark = ",", scientific = FALSE)
5. }
6. # Vẽ boxplot
7. ggplot(Sales, aes(y = Unit.Price)) +
8. geom_boxplot(fill = "skyblue", color = "darkblue", width = 0.4,
9. outlier.color = "red") +
10. scale_y_continuous(labels = comma_vn) +
11. labs(
12. title = "Unit.Price – Chi phí sản xuất mỗi sản phẩm",
13. y = "Unit Price",
14. x = ""
15. ) +
16. theme_minimal(base_size = 11) +
17. theme(
18. plot.title = element_text(face = "bold", hjust = 0.5),
19. axis.title.y = element_text(face = "bold")
20. )
Nhận xét: Giá bán mỗi sản phẩm có sự chênh lệch rõ rệt giữa các loại hàng. Một nửa số sản phẩm có giá nằm trong khoảng 100-430 đồng (Q1 – Q3). Giá trị trung vị (Q2 = 205) thể hiện mức giá phổ biến nhất rơi vào nhóm trung bình thấp, quanh 200 đồng. Giá thấp nhất là 9,33 đồng, trong khi cao nhất là gần 700 đồng,, cho thấy nhiều quốc gia đa dạng nhiều loại hàng hóa từ giá rẻ đến cao cấp. Biểu đồ có dạng lệch phải, nghĩa là phần lớn sản phẩm có giá thấp, chỉ một số ít có giá rất cao – thường là hàng cao cấp hoặc đặc biệt.
1. ggplot(Sales, aes(y = Unit.Cost)) +
2. geom_boxplot(fill = "skyblue", color = "darkblue", width = 0.4,
3. outlier.color = "red") +
4. scale_y_continuous(labels = comma_vn) +
5. labs(
6. title = "Unit.Cost – Chi phí sản xuất mỗi sản phẩm",
7. y = "Unit Cost",
8. x = ""
9. ) +
10. theme_minimal(base_size = 11) +
11. theme(
12. plot.title = element_text(face = "bold", hjust = 0.5),
13. axis.title.y = element_text(face = "bold"))
Nhận xét:Chi phí sản xuất dao động từ 7 đến 520 đồng, cho thấy mức độ khác biệt đáng kể giữa các mặt hàng. Khoảng giữa (Q1 – Q3) nằm trong khoảng 50-350 đồng, tức là 50% sản phẩm có chi phí ở mức trung bình. Giá trị trung vị (Q2 = 117,11) thấp hơn trung bình (188,02), phản ánh rằng đa số sản phẩm có chi phí thấp, chỉ một số ít sản phẩm đặc biệt có chi phí cao. Dữ liệu có dạng lệch phải, do một vài sản phẩm có chi phí cao vượt trội so với phần còn lại.
1. Sales$Year <- format(Sales$Order.Date, "%Y")
Giải thích: Lệnh
Sales$Year <- format(Sales$Order.Date, "%Y")tạo cột mới “Year” trong bảng dữ liệu Sales, chứa thông tin năm của từng đơn hàng. Hàmformat() lấy phần năm từ biến ngày, giúp việc phân tích theo từng năm thuận tiện hơn.
1. # Tính thống kê
2. avg_profit <- Sales %>%
3. group_by(Year) %>%
4. summarise(
5. Average_P = mean(Total.Profit, na.rm = TRUE),
6. Min_Profit = min(Total.Profit, na.rm = TRUE),
7. Max_Profit = max(Total.Profit, na.rm = TRUE)
8. )
9. # In trực tiếp với phân cách hàng nghìn
10. print(avg_profit %>%
11. mutate(
12. Average_P = comma(Average_P, big.mark = ".", decimal.mark = ","),
13. Min_Profit = comma(Min_Profit, big.mark = ".", decimal.mark = ","),
14. Max_Profit = comma(Max_Profit, big.mark = ".", decimal.mark = ",")))
## # A tibble: 8 × 4
## Year Average_P Min_Profit Max_Profit
## <chr> <chr> <chr> <chr>
## 1 2010 397.426 62,7 1.738.005
## 2 2011 391.841 4,8 1.737.135
## 3 2012 391.690 19,3 1.737.657
## 4 2013 393.710 33,7 1.736.440
## 5 2014 395.346 16,9 1.736.440
## 6 2015 396.583 15,7 1.738.178
## 7 2016 391.673 7,2 1.738.700
## 8 2017 394.809 14,5 1.737.309
Nhận xét: Trong các năm từ 2010 đến 2017, lợi nhuận trung bình của doanh nghiệp dao động trong khoảng từ 391.673 đến 397.426, thể hiện sự ổn định rất cao trong hoạt động kinh doanh. Khoản lợi nhuận nhỏ nhất khá thấp là 4,8 ở năm 2011, 7,23 ở năm 2016, và cao nhất là 62,7 ở năm 2010. Điều này có nghĩa doanh nghiệp có nhiều sản phẩm hoặc giao dịch có lợi nhuận rất nhỏ. Ngược lại, các khoản lợi nhuận lớn nhất mỗi năm đều ở mức cao, như 1.738.005 năm 2010, 1.738.178 năm 2015, cho thấy vẫn có những giao dịch cực kỳ thành công. Tổng thể, doanh nghiệp đang duy trì lợi nhuận ổn định qua các năm.
Giải thích:
- Dòng 3: dùng để nhóm dữ liệu theo từng năm dựa trên cột vừa tạo.
- Dòng 4:
summarise(...)tổng hợp các chỉ số: trung bình, nhỏ nhất, lớn nhất của lợi nhuận từng năm, sử dụng na.rm = TRUE để bỏ qua các giá trị NA khi tính toán, đảm bảo kết quả không bị sai do dữ liệu bị thiếu.- Dòng 11:
mutate(comma()): để chỉnh sửa cột và định dạng thành số có được phân cách hàng ngàn.
1. Profit_summary <- aggregate(
2. x = Sales$Total.Profit,
3. by = list(Region = Sales$Region, Order.Priority = Sales$Order.Priority),
4. FUN = mean)
5. colnames(Profit_summary) [3] <- "MeanProfit"
6. #Phân cách hàng ngàn
7. head(
8. Profit_summary %>%
9. transform(
10. MeanProfit = comma(MeanProfit, big.mark = ".", decimal.mark = ",")))
Nhận xét: Phân tích trung bình lợi nhuận theo từng khu vực và mức độ ưu tiên đơn hàng cho thấy hiệu quả kinh tế của việc vận hành và chính sách bán hàng của doanh nghiệp trên các thị trường khác nhau. Ta dễ thấy, tại khu vực châu Á, mức độ ưu tiên khẩn cấp mang lại lợi nhuận trung bình khoảng 396.745, còn ở mức độ ưu tiên cao mang lại lợi nhuận trung bình là 392.182. Việc đánh giá lợi nhuận trung bình theo từng vùng địa lý giúp nhận diện đâu là thị trường mang lại hiệu quả cao hơn, từ đó tối ưu hóa hoạt động marketing, bán hàng và đầu tư nguồn lực phù hợp.
Giải thích:
aggregate(...): Hàm này dùng để tính toán chỉ số (như trung bình, tổng,…) cho từng nhóm trong bộ dữ liệu.x = Sales$Total.Profit: Lấy cột lợi nhuận (Total.Profit) làm số liệu cần tổng hợp.by = list(Region = Sales$Region, Order.Priority = Sales$Order.Priority): Chia dữ liệu thành các nhóm nhỏ dựa theo từng khu vực (Region) và từng mức độ ưu tiên đơn hàng (Order.Priority).FUN = mean: Chỉ rõ lấy giá trị trung bình cho mỗi nhóm (hàm mean).
1. Sales$delivery_date <- Sales$Ship.Date - Sales$Order.Date
2. summary(Sales$delivery_date)
## Time differences in days
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.00 12.00 25.00 25.04 38.00 50.00
Nhận xét: Sau khi định dạng đúng ngày tháng đặt hàng và giao hàng, tiếp tục thực hiện thêm một cột là thời gian tổng ngày giao hàng ở bảng Sales.
- Dựa vào thống kê ngày giao hàng, phân làm ba mức ngày giao hàng theo tứ phân vị:
- Khoảng 1 nếu nhỏ hơn tứ phân vị 1 thì có tốc độ giao hàng nhanh.
- Khoảng 2 nếu nhỏ hơn tứ phân vị 3 thì có tốc độ giao hàng trung bình.
- Khoảng 3 nếu lớn hơn tứ phân vị 3 thì có tốc độ giao hàng nhanh.
Giải thích:
Sales$delivery_date <- Sales$Ship.Date - Sales$Order.DateTạo một cột mới tên là delivery_date trong bảng dữ liệu Sales. Phép trừ giữa hai cột ngày (Ship.Date trừ Order.Date) giúp tính số ngày từ khi đặt hàng tới khi giao hàng của từng đơn.
1. Sales$Sort_Date <- ifelse(
2. Sales$delivery_date < 12, "Tốc độ nhanh",
3. ifelse(
4. Sales$delivery_date < 38, "Tốc độ trung bình",
5. "Tốc độ chậm"))
6. table(Sales$Sort_Date)
##
## Tốc độ chậm Tốc độ nhanh Tốc độ trung bình
## 25709 23553 50738
Nhận xét: Khoảng 50% đơn hàng (50.738 đơn) thuộc nhóm tốc độ trung bình (12–38 ngày) tương ứng với mức phổ biến và ổn định nhất. Nhóm nhanh (<12 ngày) chiếm 23.553 đơn, phản ánh khả năng xử lý linh hoạt. Trong khi đó, nhóm chậm (>38 ngày) có 25.709 đơn, cho thấy vẫn tồn tại các hạn chế về vận chuyển hoặc khoảng cách.
Giải thích:
- Dòng 1 : Tạo cột mới tên “Sort_Date” để lưu kết quả phân nhóm tốc độ giao hàng.
- Dòng 3: Nếu ngày giao hàng nhỏ hơn 12, gán “Tốc độ nhanh”. Nếu lớn hơn hoặc bằng 12 nhưng nhỏ hơn 38, gán “Tốc độ trung bình” . Nếu lớn hơn hoặc bằng 38, gán “Tốc độ chậm”.
- Dòng 6: Đếm số lượng đơn hàng trong từng nhóm.
1. Reve_Item_Priority <- aggregate(Sales$Total.Revenue,
2. by = list(Item = Sales$Item.Type, Priority = Sales$Order.Priority),
3. FUN = sum)
4. # Sắp xếp giảm dần theo doanh thu
5. top5 <- Reve_Item_Priority[order(Reve_Item_Priority$x, decreasing = TRUE),][1:5, ]
6. # Thêm cột hiển thị với dấu phân cách hàng nghìn
7. top5$TotalRevenue_fmt <- format(top5$x, big.mark = ".", decimal.mark = ","
8. , scientific = FALSE)
9. print(top5)
## Item Priority x TotalRevenue_fmt
## 45 Office Supplies Medium 7092747489 7.092.747.489
## 31 Household Low 7075645433 7.075.645.433
## 43 Household Medium 6963174924 6.963.174.924
## 21 Office Supplies High 6934264465 6.934.264.465
## 7 Household Critical 6892145842 6.892.145.842
Nhận xét: Nhìn vào hai bảng dữ liệu, có thể thấy nhóm hàng Office Supplies và Household đạt doanh thu cao nhất ở các mức ưu tiên khác nhau, mức tổng doanh thu giao động từ 6,8 tỷ đến hơn 7 tỷ. Điều này cho thấy nhu cầu của khách hàng với các mặt hàng này rất ổn định, bất kể ở mức độ ưu tiên đơn hàng là Medium, Low hay High. Đây là các nhóm sản phẩm chiến lược mang lại nguồn thu lớn cho doanh nghiệp.
Giải thích:
- Dòng 1:
aggregate()dùng để gộp dữ liệu theo từng nhóm; ở đây tổng hợp doanh thu cho từng tổ hợp loại hàng và mức độ ưu tiên đơn hàng.- Dòng 2: nhóm loại đơn hàng và độ ưu tiên.
- Dòng 3: trong mỗi nhóm, cộng tổng các giá trị doanh thu.
- Dòng 5:
order(..., decreasing = TRUE): sắp xếp bảng theo cột x (doanh thu) từ cao xuống thấp.
1. Asia = Sales[Sales$Region=="Asia",]
2. head(Asia[, c("Region", "Country")])
Nhận xét: Khi lọc dữ liệu cho khu vực Asia, ta có thể phân tích sâu hơn theo từng mặt hàng. Việc tính trung bình số lợi nhuận theo từng quốc gia cho phép so sánh hiệu quả kinh doanh giữa các nước trong khu vực.
Giải thích:
Sales$Region=="Asia":điều kiện lọc, chỉ lấy những dòng có giá trị “Asia” trong cột Region.
1. library(dplyr)
2. Sold_asia <- Asia %>%
3. group_by(Country, Item.Type) %>%
4. summarise(
5. Mean_Profit = mean(Total.Profit, na.rm = TRUE),
6. Min_Profit = min(Total.Profit, na.rm = TRUE),
7. Max_Profit = max(Total.Profit, na.rm = TRUE),
8. Var_Profit = var(Total.Profit, na.rm = TRUE)
9. ) %>%
10. mutate(across(where(is.numeric),
11. ~ format(round(., 2), big.mark = ".",decimal.mark = ",",nsmall = 2)))
12. print(head(Sold_asia))
## # A tibble: 6 × 6
## # Groups: Country [1]
## Country Item.Type Mean_Profit Min_Profit Max_Profit Var_Profit
## <chr> <chr> <chr> <chr> <chr> <chr>
## 1 Bangladesh Baby Food "473.907,44" " 8.339,82" " 957.257,96" " 78.307.809.458…
## 2 Bangladesh Beverages " 87.225,79" " 2.192,40" " 155.848,32" " 1.599.797.611…
## 3 Bangladesh Cereal "526.303,07" "48.104,37" " 881.116,14" " 66.811.960.815…
## 4 Bangladesh Clothes "354.343,76" " 4.259,52" " 726.909,12" " 43.067.476.229…
## 5 Bangladesh Cosmetics "838.124,99" "50.074,56" "1.697.492,81" "195.751.227.673…
## 6 Bangladesh Fruits " 11.835,45" " 67,48" " 23.215,53" " 43.933.791…
Nhận xét: Lợi nhuận trung bình của mặt hàng Baby Food ở đất nước Bangladesh là 473.947.397,44. Biến mới giúp đánh giá hiệu quả kinh doanh giữa các quốc gia và sản phẩm.
Giải thích:
- Dòng 2: tạo bảng mới Sold_asia từ bảng Asia .
- Dòng 3:
group_by(Country, Item.Type): nhóm dữ liệu thành từng tổ,- Dòng 4:
summarise(...):tính toán thống kê, tổng hợp số liệu trên từng tổ đã nhóm.- Dòng 10:
mutate(across()): chỉnh sửa cột, chỗ nào có số thì sẽ phân cách hàng nghìn.
1. q_unit <- quantile(Asia$Units.Sold, probs = c(0.25, 0.75))
2. print(comma_vn(q_unit))
## 25% 75%
## "2.518" "7.494"
Nhận xét: Giá trị tứ phân vị thứ nhất bằng 2.518 và tứ phân vị thứ ba bằng 7.494, cho thấy phần lớn các đơn hàng ở khu vực châu Á có số lượng bán nằm trong khoảng từ 2.518 đến 7.494. Đây là mức dao động khá ổn, thể hiện rằng hoạt động bán hàng ở khu vực này phân bố tương đối đều.
Giải thích:
quantile(...): Hàm tính phân vị cho dữ liệu. Tức là chia một dãy số ra thành các phần đều nhau, lấy giá trị ở các điểm chia đó.probs = c(0.25, 0.75)): Tham số xác suất, ở đây cần lấy phân vị 25% và 75%.
1. q_profit <- quantile(Asia$Total.Profit, probs = c(0.25, 0.75))
2. print(comma_vn(q_profit))
## 25% 75%
## " 97.399,48" "566.433,75"
Nhận xét: Giá trị tứ phân vị thứ nhất bằng 97.399 và tứ phân vị thứ ba bằng 566.433 phản ánh mức lợi nhuận của phần lớn các đơn hàng ở khu vực châu Á nằm trong khoảng khá rộng, từ khoảng 97 nghìn đến hơn 566 nghìn. Khoảng tứ phân vị là 469.034.27 cho thấy lợi nhuận có sự phân tán mạnh, nghĩa là có sự khác biệt rõ giữa các đơn hàng có lợi nhuận thấp và cao.
Giải thích:
quantile(...): Hàm tính phân vị cho dữ liệu. Tức là chia một dãy số ra thành các phần đều nhau, lấy giá trị ở các điểm chia đó.probs = c(0.25, 0.75)): Tham số xác suất, ở đây cần lấy phân vị 25% và 75%. ### Phân tích theo mức phát triển
1. Asia$PhatTrien <- ifelse(
2. Asia$Units.Sold < q_unit[1] & Asia$Total.Profit < q_profit[1], "Phát triển chậm",
3. ifelse(
4. Asia$Units.Sold <= q_unit[2]&Asia$Total.Profit<=q_profit[2],"Phát triển trung bình",
5. "Phát triển tốt"))
6. freq_table <- Asia %>%
7. count(Nhom = PhatTrien) %>%
8. mutate(Ty_le = round(100 * n / sum(n), 2))
9. knitr::kable(freq_table, col.names = c("Nhóm phát triển", "Tần suất", "Tỷ lệ (%)"))
| Nhóm phát triển | Tần suất | Tỷ lệ (%) |
|---|---|---|
| Phát triển chậm | 2110 | 14.50 |
| Phát triển trung bình | 7102 | 48.82 |
| Phát triển tốt | 5335 | 36.67 |
1. print(freq_table)
## # A tibble: 3 × 3
## Nhom n Ty_le
## <chr> <int> <dbl>
## 1 Phát triển chậm 2110 14.5
## 2 Phát triển trung bình 7102 48.8
## 3 Phát triển tốt 5335 36.7
Nhận xét: Kết quả phân nhóm cho thấy phần lớn các đơn hàng tại thị trường châu Á thuộc nhóm phát triển trung bình với tỷ lệ 48.82%, phản ánh sự ổn định và chiếm thị phần chính của các sản phẩm này. Trong khi đó, nhóm phát triển tốt chiếm 36.67%, thể hiện có hơn một phần ba đơn hàng đạt hiệu quả kinh doanh cao, đây là nhóm cần được ưu tiên đầu tư mở rộng để tối đa hóa lợi nhuận. Ngược lại, chỉ 14.5% số đơn thuộc nhóm phát triển chậm, đa phần là các sản phẩm có lượng bán và lợi nhuận thấp; doanh nghiệp nên rà soát, điều chỉnh chính sách hoặc đổi mới sản phẩm đối với nhóm này để cải thiện hiệu quả hoạt động kinh doanh.
Giải thích:
- Dòng 1:
ifelse(...): Hàm phân loại từng dòng dữ liệu theo điều kiện.- Dòng 2:
Asia$Units.Sold < q_unit[1]: Kiểm tra số lượng bán nhỏ hơn tứ phân vị thứ nhất&: bắt buộc cả hai điều kiện phải đúng.Asia$Total.Profit < q_profit[1]: Kiểm tra lợi nhuận nhỏ hơn Q1. Nếu đều nhỏ hơn, gán giá trị “Phát triển chậm” cho dòng đó.- Dòng 4:
Asia$Units.Sold <= q_unit[2] & Asia$Total.Profit <= q_profit[2]: Nếu số lượng bán nhỏ hơn hoặc bằng Q3 và lợi nhuận nhỏ hơn hoặc bằng Q3, gán thành “Phát triển trung bình”.- Nếu không rơi vào hai điều kiện trên, mặc định là “Phát triển tốt”.
- Dòng 7:
count(PhatTrien): đếm số lần xuất hiện của mỗi nhóm “Phát triển chậm”, “Phát triển trung bình”, “Phát triển tốt”.- Dòng 8:
mutate(Ty_le = round(100 * n / sum(n), 2)): thêm cột tỷ lệ phần trăm cho từng nhóm, lấy đến 2 chữ số sau thập phân.- Dòng 10:
knitr::kable():Hàm tạo bảng gọn hơn.
1. profit_detail <- Sales %>%
2. group_by(Country, Item.Type) %>%
3. summarise(Profit = sum(Total.Profit, na.rm = TRUE), .groups = "drop")
4. profit_detail %>%
5. mutate(across(where(is.numeric), comma_vn)) %>%
6. head()
Nhận xét: Ở nước Afghanistan, Tổng lợi nhuận giao động với lớn với nhiều giá trị, nổi bật phải kể đến loại sản phẩm Comestic với tổng lợi nhuận là 37.763.173, cho thấy có thể đẩy mạnh thị trường này đến phát triển. Nhóm hàng cần quốc gia này xem xét là Fruits với lợi nhuận thấp nhất khoảng 620.179,8.
Giải thích:
Sales %>%: Lấy dữ liệu từ bảng Sales, chuyển cho các bước tiếp theo nhờ pipegroup_by(Country, Item.Type): Gom nhóm dữ liệu theo từng tổ hợp quốc gia (Country) và loại hàng (Item.Type).summarise(...): Tính toán cho từng nhómProfit = sum(Total.Profit, na.rm = TRUE): Tính tổng lợi nhuận cho mỗi nhóm.na.rm = TRUEnghĩa là bỏ qua giá trị NA khi tính toán.groups = "drop": Sau khi tổng hợp xong, kết quả là bảng bình thường không còn nhóm nữa. Điều này giúp code sau này chạy dễ, không lỗi ngầm do bảng còn phân nhóm.mutate(): chỉnh sửa cột hiện có để nơi nào có số thì phân cách hàng ngàn, vàcomma_vnđã được định nghĩa hàm ở trên, đặc biệt cho phân cách hàng ngàn
1. top_countries_list <- Sales %>%
2. group_by(Country) %>%
3. summarise(Total_Profit = sum(Total.Profit, na.rm = TRUE)) %>%
4. arrange(desc(Total_Profit)) %>%
5. slice(1:10) %>%
6. pull(Country)
7. print(top_countries_list)
## [1] "Sudan" "Hungary"
## [3] "Federated States of Micronesia" "Liberia"
## [5] "Australia" "Benin"
## [7] "New Zealand" "Bahrain"
## [9] "Marshall Islands" "Malta"
Nhận xét: Kết quả cho thấy không chỉ những quốc gia phát triển như Australia hay Hungary mà còn có các nước nhỏ hoặc mới nổi như Micronesia, Benin, Marshall Islands và Malta cũng nằm trong top có lợi nhuận hiệu quả. Điều này chứng minh cơ hội phân bổ tài nguyên doanh nghiệp không giới hạn ở thị trường truyền thống mà cần mở rộng tối ưu sang nhiều khu vực tiềm năng.
Giải thích:
-Dòng 1: tạo bảng
top_countries_listđể tính tổng lợi nhuận theo quốc gia - Dòng 5: slice(1:10): Lấy đúng 10 quốc gia đầu bảng. - Dòng 6: pull(Country): Rút danh sách tên quốc gia đó thành một vector, dùng để lọc tiếp.
1. profit_detail_top <- profit_detail %>%
2. filter(Country %in% top_countries_list) %>%
3. mutate(Country = factor(Country, levels = top_countries_list))%>%
4. mutate(Profit = comma(Profit, big.mark = ".", decimal.mark = ","))
5. print(profit_detail_top)
## # A tibble: 120 × 3
## Country Item.Type Profit
## <fct> <chr> <chr>
## 1 Australia Baby Food 25.691.534
## 2 Australia Beverages 2.801.010
## 3 Australia Cereal 22.616.407
## 4 Australia Clothes 18.712.071
## 5 Australia Cosmetics 52.036.335
## 6 Australia Fruits 608.467
## 7 Australia Household 48.380.067
## 8 Australia Meat 11.053.843
## 9 Australia Office Supplies 17.520.218
## 10 Australia Personal Care 5.492.977
## # ℹ 110 more rows
Nhận xét: Trong bảng dữ liệu sẽ gồm 10 nước có lợi nhuận các mặt hàng là cao nhất. Tại nước Australia, có 3 mặt hàng chủ yếu mang lại doanh thu nhiều nhất là Cosmetics, Baby Food và Household, với tổng lợi nhuận trên 25 triêu, còn lại giao động từ 2,8 triệu- 22 triệu, có mặt hàng Fruits với lợi nhuận thấp nhất là 608.467, dễ hiểu thì Australia là một nước lạnh, khó trồng cây. Nhìn chung, việc chỉ tập trung vào top 10 quốc gia mang lại lợi nhuận lớn nhất giúp doanh nghiệp dễ dàng nhận diện và phân tích sâu các thị trường trọng điểm.
Giải thích:
- Sử dụng toán tử pipe giúp chuyển sang bước tiếp theo dễ dàng.>- Dòng 2:
filter(Country %in% top_countries_list): Lọc các dòng sao cho chỉ giữ lại quốc gia nằm trong danh sách top 10 quốc gia lợi nhuận cao nhất,%in%là toán tử kiểm tra phần tử có thuộc danh sách không.- Dòng 3:
mutate(Country = factor(Country, levels = top_countries_list)):Sửa cột Country thành kiểu factor, với thứ tự các mức bằng đúng thứ tự trong danh sách top_countries_list.
1. prod_country_rev <- Sales %>%
2. group_by(Country, Item.Type) %>%
3. summarise(TotalRevenue = sum(Total.Revenue, na.rm=TRUE), .groups="drop")
4. prod_country_rev %>%
5. mutate(across(where(is.numeric), comma_vn)) %>%
6. print
## # A tibble: 2,220 × 3
## Country Item.Type TotalRevenue
## <chr> <chr> <chr>
## 1 Afghanistan Baby Food " 59.246.404"
## 2 Afghanistan Beverages " 9.782.007"
## 3 Afghanistan Cereal " 52.851.735"
## 4 Afghanistan Clothes " 24.088.481"
## 5 Afghanistan Cosmetics " 94.956.342"
## 6 Afghanistan Fruits " 2.400.945"
## 7 Afghanistan Household "175.055.331"
## 8 Afghanistan Meat "115.345.570"
## 9 Afghanistan Office Supplies "108.694.112"
## 10 Afghanistan Personal Care " 20.919.284"
## # ℹ 2,210 more rows
Nhận xét: Tổng doanh thu toàn ngành trên khắp thế giới cho biết quy mô của nước đó như thế nào và vai trò của ngành đó có đóng vai trò then chốt không. Có thể thấy trong nhóm loại sản phẩm của Afghanistan thì nổi bật phải kể đến Household(đồ dùng gia đình) với doanh thu 175.055.331, là nhóm cao nhất trong nước Afghanistan. Vì vậy có thể tập trung đẩy mạnh ở một lĩnh vực để phát triển loại sản phẩm đó lớn mạnh hơn, hoặc phân phối đều ra cho các loại có tỷ trọng thấp như Fruits, Beverage,… để tỷ trọng toàn ngành đồng thời tăng.
Giải thích:
- Dòng 1: Tính tổng doanh thu theo quốc gia và sản phẩm
- Dòng 3: groups=“drop”: Không giữ dạng nhóm cho bảng kết quả (trả về data.frame thông thường), giúp các thao tác sau thuận tiện hơn.
1. lowrev_countries <- prod_country_rev %>%
2. group_by(Country) %>%
3. summarise(SumRevenue = sum(TotalRevenue), .groups="drop") %>%
4. arrange(SumRevenue) %>% slice(1:10) %>% pull(Country)
5. print(lowrev_countries)
## [1] "Angola" "Jamaica"
## [3] "Palau" "Vietnam"
## [5] "Switzerland" "United States of America"
## [7] "Solomon Islands" "Iceland"
## [9] "Germany" "Kazakhstan"
Nhận xét: Việc xác định 10 quốc gia có doanh thu thấp nhất cho phép doanh nghiệp nhận diện các thị trường tiềm năng cần cải thiện hoặc rà soát lại hiệu quả hoạt động. Những quốc gia này có thể là thị trường nhỏ, gặp nhiều khó khăn về mặt cạnh tranh, mua sắm hoặc tiếp cận.
Giải thích:
- Dòng 1: Tính tổng doanh thu theo quốc gia
- Dòng 4: arrange(SumRevenue): Sắp xếp bảng vừa tổng hợp sao cho quốc gia có tổng doanh thu thấp nhất nằm ở phía trên. slice(1:10): Chỉ lấy 10 dòng đầu, tức là 10 quốc gia có doanh thu thấp nhất. pull(Country) Lệnh này rút cột Country của 10 quốc gia vừa lọc thành một vector (danh sách tên quốc gia)
1. library(ggplot2)
2. library(dplyr)
3. library(ggplot2)
4. library(dplyr)
5. # Có các cột: Region, Country, Item.Type, Total.Revenue
6. sales_asia <- Sales %>% filter(Region == "Asia")
7. # Tính doanh thu theo sản phẩm và quốc gia (chi tiết)
8. sum_by_product <- sales_asia %>% group_by(Country, Item.Type) %>%
9. summarise(TotalRevenue = sum(Total.Revenue), .groups = 'drop')
10. # Top 5 sản phẩm doanh thu lớn nhất toàn châu Á
11. top5_tbl <- sum_by_product %>% group_by(Item.Type) %>%
12. summarise(TotalRevenue = sum(TotalRevenue), .groups='drop') %>%
13. arrange(desc(TotalRevenue)) %>% slice_head(n = 5)
14. top5_items <- top5_tbl$Item.Type
15. # Gom các sản phẩm còn lại thành "Các sản phẩm khác"
16. plot_data <- sum_by_product %>%
17. mutate(Item.Type = ifelse(Item.Type %in% top5_items, Item.Type, "Các sản phẩm khác"))%>%
18. group_by(Item.Type) %>% summarise(TotalRevenue = sum(TotalRevenue), .groups='drop')
19. total_revenue_sum <- sum(plot_data$TotalRevenue)
20. plot_data <- plot_data %>% arrange(desc(TotalRevenue)) %>% mutate(
21. TotalRevenue_fmt = label_number(big.mark = ".", decimal.mark = ",")(TotalRevenue),
22. Share = TotalRevenue / sum(TotalRevenue),
23. Share_fmt = scales::percent(Share, accuracy = 0.1)
24. )
25. plot_data
Nhận xét: Dựa trên dữ liệu doanh thu của châu Á, top 5 sản phẩm chiếm khoảng 75,56% tổng doanh thu, cho thấy doanh thu tập trung mạnh vào một số mặt hàng chủ lực. Trong đó, Office Supplies (Văn phòng phẩm) dẫn đầu với doanh thu khoảng 4,03 tỷ, chiếm 20,88% tổng doanh thu, tiếp theo là Household (Đồ gia dụng) với khoảng 3,83 tỷ, chiếm 19,85%. Cosmetics (Mỹ phẩm) và Meat (Thịt) lần lượt chiếm 13,55% và 13,21%, là những sản phẩm có doanh thu cao, đáng để tập trung các chiến lược marketing và quản lý kho bãi. Baby Food (Thực phẩm trẻ em) chiếm thấp hơn, khoảng 8,07%, nhưng vẫn nằm trong top 5, thể hiện đây là một ngách thị trường có tiềm năng. Nhìn chung, dữ liệu cho thấy các sản phẩm chủ lực mang lại phần lớn doanh thu, trong khi các sản phẩm khác chiếm tỷ trọng nhỏ hơn, gợi ý cần cân nhắc chính sách phân phối và marketing phù hợp cho từng nhóm hàng.
Giải thích:
- Dòng 6: Lọc dữ liệu chỉ lấy các dòng khu vực Châu Á để tập trung phân tích doanh thu cho thị trường này.
- Dòng 8: Sử dụng toán tử pipe giúp nối các bước xử lý, group_by(): nhóm dữ liệu theo mục đích. summarise(), .groups = ‘drop’): Giúp thực hiện các thống kê cơ bản và .groups = ’drop’nghĩa là sau khi tính xong, bỏ cấu trúc nhóm đi và trả về khung dữ liệu thông thường.
- Dòng 16: Các sản phẩm không thuộc top5 sẽ được gộp tên thành “Các sản phẩm khác”. Sau đó tiếp tục cộng tổng doanh thu cho từng nhóm này.
- Dòng 20: Sắp xếp nhóm sản phẩm theo doanh thu giảm dần để trình bày đẹp trên biểu đồ. Tính tổng doanh thu tất cả nhóm để sử dụng ở chú thích trung tâm.
1. df_sum <- Sales %>%
2. group_by(Region, Year) %>%
3. summarise(
4. Revenue = sum(Total.Revenue, na.rm=TRUE),
5. Cost = sum(Total.Cost, na.rm=TRUE),
6. Profit = sum(Total.Profit, na.rm=TRUE),
7. .groups = "drop"
8. ) %>%
9. pivot_longer(cols = c("Revenue", "Cost", "Profit"), names_to = "Indicator",
10. values_to = "Value")%>%
11. mutate(Value_fmt = label_number(big.mark = ".", decimal.mark = ",")(Value))
12. head(df_sum[df_sum$Region == "Asia",],10)
Nhận xét: Việc tổng hợp doanh thu, chi phí, lợi nhuận theo từng khu vực (Region) và từng năm (Year) cho phép đánh giá chính xác hiệu quả hoạt động kinh doanh tại từng thị trường và so sánh các biến động theo thời gian. Tại năm 2010, khu vực châu Á có lợi nhuận 724 triệu, nhưng năm 2011 tăng lên 779triệu, năm 2012 thì lợi nhuận là 760 triệu, có thể thấy 3 năm liên tục tại khu vực châu Á chỉ xoay quanh 700 triệu, chưa có điểm đột phá đáng kể. Vì thế, qua bảng này, nhà quản trị có thể phát hiện khu vực nào đang đóng góp tốt cho doanh thu hoặc lợi nhuận, đồng thời kiểm tra các năm có dấu hiệu bất thường về chi phí, từ đó ra quyết định tối ưu phân bổ tài nguyên hoặc đổi chiến lược đầu tư cho từng vùng mục tiêu.
Giải thích:
- Dòng 1: tạo một bảng df_sum để tính tổng cái chỉ số theo năm
- Dòng 7: .groups = ’drop’nghĩa là sau khi tính xong, bỏ cấu trúc nhóm đi và trả về khung dữ liệu thông thường.
- Dòng 9: %>% pivot_longer(cols = …): Đưa bảng về dạng dài, gộp ba cột chỉ số thành hai cột: Indicator: chứa tên chỉ số (“Revenue”, “Cost”, “Profit”). Value: giá trị từng chỉ số tương ứng.
1. library(dplyr)
2. library(scales)
3. # Xác định top 3 quốc gia doanh thu cao nhất
4. country_total <- Sales %>%
5. group_by(Country) %>%
6. summarise(TotalRevenue = sum(Total.Revenue, na.rm = TRUE), .groups = "drop")
7. # Lấy tên 3 nước dẫn đầu
8. top3_countries <- country_total %>%
9. arrange(desc(TotalRevenue)) %>%
10. slice_head(n = 3) %>%
11. pull(Country)
12. # Bảng heatmap doanh thu từng sản phẩm trong 3 nước này
13. sales_heatmap <- Sales %>%
14. filter(Country %in% top3_countries) %>%
15. group_by(Item.Type, Country) %>%
16. summarise(TotalRevenue = sum(Total.Revenue, na.rm = TRUE),.groups = "drop") %>%
17. mutate(TotalRevenue_label = comma(TotalRevenue, big.mark = ".", decimal.mark = ","))
18. head(sales_heatmap)
Nhận xét: Bảng dữ liệu thu về cho ta biết top 3 doanh thu dẫn đầu với mỗi loại sản phẩm. Ở quốc gia Bahrain với loại sản phẩm Baby Food có tổng doanh thu 55 triệu. Doanh thu ở cả ba quốc gia đều rất cao, dao động từ 51–56 triệu.Điều này cho thấy nhu cầu tiêu dùng mặt hàng Baby Food ổn định và mạnh mẽ. Nhóm “Beverages” có doanh thu nhỏ hơn, chỉ 7–12 triệu, nhưng vẫn có tiềm năng phát triển. Nhìn chung, Bahrain là quốc gia có hiệu quả kinh doanh cao nhất ở cả hai nhóm hàng, là một quốc gia tìm lực.
Giải thích:
- Dòng 4: Tạo một bảng country_total: Tạo bảng tính doanh thu từng quốc gia.
- Dòng 8: Tạo một bảng: top3_countries lọc ra ba nước dẫn đầu về doanh thu, pull(Country) để trích ra thành vector tên quốc gia top 3 này.
- Dòng 13: Lọc dữ liệu gốc chỉ giữ lại dòng thuộc 3 quốc gia vừa xác định. Sau đó tính tổng doanh thu của 3 quốc gia đó theo loại sản phẩm.
- Dòng 17: Tạo thêm một cột phân cách hàng nghìn.
1. library(dplyr)
2. library(lubridate)
3. library(scales) # để dùng hàm comma() hoặc label_number()
4. sales_yearly <- Sales %>%
5. mutate(Year = year(Order.Date)) %>%
6. group_by(Year) %>%
7. summarise(total_revenue = sum(Total.Revenue, na.rm = TRUE)) %>%
8. mutate(total_revenue_label = label_number(
9. big.mark = ".", decimal.mark = ","
10. )(total_revenue))
11. head(sales_yearly)
1. ggplot(sales_yearly, aes(x = Year, y = total_revenue)) +
2. geom_line(color = "#4575b4", linewidth = 1.2) +
3. geom_point(size = 3, color = "#74add1") +
4. geom_smooth(method = "lm", se = FALSE, linetype = "dashed", color = "gray40") +
5. # Hiển thị số có dấu phân cách trên trục tung
6. scale_y_continuous(
7. labels = label_number(big.mark = ".", decimal.mark = ",")) +
8. labs(
9. title = "Xu hướng doanh thu theo năm",
10. x = "Năm",
11. y = "Doanh thu "
12. ) + theme_minimal(base_size = 13) +
13. theme(plot.title = element_text(face = "bold", hjust = 0.5))
>Nhận xét: Doanh thu giai đoạn 2010–2015 duy trì mức
ổn định quanh 17,5 tỷ đồng, phản ánh hoạt động kinh doanh tương đối bền
vững. Tuy nhiên, từ sau năm 2015, doanh thu giảm mạnh xuống còn khoảng
10 tỷ đồng vào năm 2017, cho thấy dấu hiệu suy giảm nghiêm trọng về hiệu
quả kinh doanh. Xu hướng tổng thể có chiều hướng giảm, cho thấy một số
quốc gia cần xem xét lại chiến lược thị trường và mô hình hoạt động để
phục hồi tăng trưởng.
Giải thích:
- Dòng 1: Khởi tạo vẽ biểu đồ.
- Dòng 2: geom_line() Vẽ đường nối các điểm, tô màu đường ,độ dày đường là 1.2
- Dòng 3: geom_point() Vẽ điểm tương ứng với mỗi năm, kích thước là 3 và tô màu cho điểm.
- Dòng 4: geom_smooth(): thêm đường hồi quy tuyến tính (linear model) thể hiện xu hướng chung, se = FALSE: không hiển thị dải tin cậy, và đường là đường nét đứt với màu xám đậm.
- Dòng 6: scale_y_continuous(): dùng để định dạng phân cách hàng nghìn, labs(): tạo tiêu đề và nhãn trục, theme_minimal(base_size = 13): Chọn chủ đề tối giản
1. top_items <- Sales %>%
2. group_by(Item.Type) %>%
3. summarise(Total_Revenue=sum(Total.Revenue)) %>%
4. arrange(desc(Total_Revenue)) %>%
5. slice_head(n=10)
6. # Tính phần trăm doanh thu
7. top_items <- top_items %>%
8. mutate(Share = Total_Revenue / sum(Total_Revenue))
9. head(top_items)
1. ggplot(top_items, aes(x = reorder(Item.Type, Total_Revenue), y = Total_Revenue)) +
2. geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = 0, ymax = Inf),
3. fill = "#f9fbfd", alpha = 0.4, inherit.aes = FALSE) +
4. geom_col(aes(fill = Total_Revenue), width = 0.6, alpha = 0.95, show.legend = FALSE) +
5. geom_hline(yintercept = mean(top_items$Total_Revenue),
6. linetype = "dashed", color = "#457b9d", alpha = 0.7) +
7. geom_text(aes(label = paste0(round(Share * 100, 1), "%")),
8. color = "white", fontface = "bold", size = 3.5,
9. hjust = 1.15, vjust = 0.5) +
10. scale_fill_gradient(low = "#a8dadc", high = "#f4a261") +
11. scale_y_continuous(
12. labels = scales::label_number(
13. big.mark = ".",
14. decimal.mark = ",",
15. accuracy = 1))+
16. coord_flip() +
17. labs( title = "Top 10 sản phẩm theo doanh thu",
18. x = "Loại sản phẩm", y = "Doanh thu") +
19. theme_minimal(base_size = 13) +
20. theme(
21. plot.title = element_text(face = "bold", hjust = 0.5, color = "#264653"),
22. axis.text = element_text(color = "#2d3436"),
23. panel.grid.major.y = element_line(color = "#edf2f4"),
24. panel.grid.minor = element_blank(),
25. plot.background = element_rect(fill = "#fdfefe", color = NA))
Nhận xét: Dẫn đầu ngành là loại sản phẩm Household với tổng doanh thu 21.1% so vơis toàn ngành, tương đương hơn 20 tỷ, theo sau là các ngành trên mức trung bình gồm: Office Supplies, Comestic và Meat. Các ngành còn lại thì có doanh thu thấp hơn. Điều này cho thấy thị trường đang tập trung vào 4 ngành này và coi nó như ngành trọng điểm.
Giải thích:
- Dòng 1: Khởi tạo biểu đồ
- Dòng 2: geom_rect() Vẽ một hình chữ nhật phủ toàn biểu đồ, tạo nền nhạt màu xanh trắng (#f9fbfd,), inherit.aes = FALSE giúp lớp geom_rect() hoạt động độc lập, chỉ để tô màu nền hoặc vùng nhấn mà không bị ràng buộc bởi dữ liệu chính, alpha = 0.4 làm mờ (trong suốt nhẹ) làm biểu đồ sáng, thoáng.
- Dòng 4: geom_col(): tạo cột có chiều cao là tổng doanh thu.
- Dòng 5: geom_hline(): Vẽ đường ngang nét đứt tại giá trị trung bình doanh thu
- Dòng 7: geom_text(): Share là tỷ trọng doanh thu mỗi sản phẩm trong tổng (Share = Total_Revenue / sum(Total_Revenue)). Nhãn hiển thị dạng “xx.x%”.
- Dòng 10: scale_fill_gradient(): Màu nhạt cho giá trị thấp, màu cam nóng hơn cho giá trị cao.
- Dòng 11: scale_y_continuous thêm dấu phân cách hàng nghìn cho trục Y.
- Dòng 16: coord_flip(): Đổi trục X và Y cho nhanh để thành biểu đồ ngang thanh bar
- labs(): đặt tên tiêu đề, nhãn trục X và Y. theme_minimal(base_size = 13) + theme(): Giúp giao diện sáng và đẹp,
1. Country <- aggregate(
2. x=Sales$Total.Profit,
3. by = list(Order_Priority =Sales$Order.Priority, Year=Sales$Year),
4. FUN= mean)
5. head(Country)
1. ggplot(Country, aes(x = Year, y = x, fill = Order_Priority)) +
2. geom_col(position = "dodge", alpha = 0.9) +
3. geom_point(size = 3, color = "black", position = position_dodge(0.5)) +
4. geom_hline(yintercept = mean(Country$MeanProfit),
5. linetype = "dashed", color = "red") +
6. facet_wrap(~Order_Priority) +
7. scale_y_continuous(labels = scales::label_comma(big.mark = ".", decimal.mark = ","))+
8. theme_minimal() +
9. labs(
10. title = "Lợi nhuận trung bình theo năm và mức độ ưu tiên đơn hàng",
11. x = "Năm",
12. y = "Lợi nhuận trung bình")
Nhận xét: - Biểu đồ cho thấy lợi nhuận trung bình của toàn ngành qua các năm nhìn chung ổn định, các đơn hàng ở mỗi loại mức độ giao hàng đều có lợi nhuận trung bình qua các năm giao động trên dưới 400.000, cho thấy được sự phân bố đồng đều qua các năm.
Giải thích:
- Dòng 1: Khởi tại biểu đồ.
- Dòng 2,3 và 4: Tạo biểu đồ cột, thêm điểm dữ liệu và tạo đường trường bình
- Dòng 6: facet_wrap(~Order.Priority): Tách riêng mỗi mức độ ưu tiên thành một ô biểu đồ nhỏ, trình bày cạnh nhau theo ngang. “facet” nghĩa là chia nhỏ ra thành từng ô biểu đồ riêng; “wrap” là áp dụng cho từng giá trị trong cột “Order.Priority”.
- theme_minimal() tạo giao diện sáng cho biểu đồ. labs(): Tạo tên tiêu đề và nhãn cho trục X, Y
1. #tổng doanh thu theo năm và loại sản phẩm
2. area_data <- Sales %>%
3. group_by(Year, `Item.Type`) %>%
4. summarise(TotalRevenue = sum(`Total.Revenue`, na.rm = TRUE), .groups = 'drop')
5. item_colors <- c(
6. "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728",
7. "#9467bd", "#8c564b", "#e377c2", "#7f7f7f",
8. "#bcbd22", "#17becf", "#aec7e8", "#ffbb78") #thêm màu
9. # Vẽ biểu đồ
10. ggplot(area_data, aes(x = Year, y = TotalRevenue, fill = `Item.Type`)) +
11.
12. geom_line(aes(color = `Item.Type`, group = `Item.Type`), size = 1) +
13. geom_point(aes(color = `Item.Type`), size = 2, alpha = 0.8) +
14. geom_smooth(aes(group = `Item.Type`), method = "loess", se = FALSE,
15. color = "black", linetype = "dashed", size = 0.3) +
16. scale_fill_manual(values = item_colors) +
17. scale_color_manual(values = item_colors) +
18. scale_y_continuous(labels = function(x) format(x, big.mark = "."))+
19. labs(title = "Doanh thu theo năm & loại sản phẩm",
20. x = "Năm",
21. y = "Doanh thu") +
22. theme_minimal(base_size = 12) +
23. theme(
24. legend.position = "bottom",
25. panel.grid.major = element_line(color = "gray80", size = 0.3),
26. panel.grid.minor = element_blank(),
27. plot.title = element_text(face = "bold", hjust = 0.5))
>Nhận xét: Doanh thu theo năm và loại sản phẩm cho
thấy mức độ phát triển của từng loại sản phẩm qua các năm thông qua
doanh thu. Có thể thấy từ năm 2010-2016 các loại sản phẩm có mức độ ổn
định, không có sự biến động lớn. Có hai ngành đặc biệt có sự biến động
khá lớn so với các ngành khác là Office Supplies và Household. Đây cũng
là hai sản phẩm có tổng doanh thu lớn nhất. Tại năm 2016-2017, nhìn
chung tất cả các loại sản phẩm đều có xu hướng doanh thu đi xuống. Có
thể là một sự kiện gây ảnh hưởng toàn thế giới, dẫn đến các nước có xu
hướng tiết kiệm, nên tổng doanh thu toàn ngành giảm
Giải thích:
- Dòng 1: Tính tổng doanh thu theo năm và loại sản phẩm để phục vụ cho việc vẽ hình.
- Dòng 5: Tạo một vector item_colors <- c(…): chứa 12 màu sắc riêng, đảm bảo không có sự trùng lặp về màu cho mỗi loại sản phẩm.
- Dòng 10: Khởi tạo biểu đồ.
- Dòng 12, 13: Vẽ đường riêng cho từng sản phẩm và thêm điểm dữ liệu tại từng năm
- Dòng 14: geom_smooth(aes(group = Item.Type), method = “loess”, se = FALSE, color = “black”, linetype = “dashed”, size = 0.3): Vẽ đường xu hướng mượt cho từng loại sản phẩm, se = FALSE là không hiển thị khoảng tin cậy, tô màu đen với đường đứt. Viêc này giúp quan sát xu hướng tăng giảm dài hạn của từng sản phẩm
- Dòng 16, 17: tô màu cho từng loại sản phẩm. Dòng 18: phân cách hàng nghìn cho trục Y. labs(): đặt tiêu đề và nhãn cho mỗi trục. theme_minimal(base_size = 12) + theme(…): giúp giao diện gọn và đẹp
1. library(ggplot2)
2. library(dplyr)
3. # Bảng màu cho từng nhóm phát triển
4. pie_colors <- c(
5. "Phát triển chậm" = "#ff9999",
6. "Phát triển trung bình" = "#ffd966",
7. "Phát triển tốt" = "#90ee90")
8. ggplot(freq_table, aes(x = "", y = Ty_le, fill = Nhom)) +
9. geom_col(width = 1, color = "gray93") +
10. geom_text(aes(label = paste0(Ty_le, "%")),
11. position = position_stack(vjust = 0.55),
12. size = 5, color = "black", fontface = "bold") +
13. scale_fill_manual(values = pie_colors) +
14. labs(
15. title = "Tỷ lệ các mức phát triển của thị trường",
16. fill = "Mức phát triển"
17. ) +
18. theme_void() +
19. theme(
20. plot.title = element_text(face = "bold", size = 13, hjust = 0.5),
21. legend.title = element_text(size = 14, face = "bold"),
22. legend.text = element_text(size = 13),
23. legend.position = "right") +
24. coord_polar(theta = "y")
>Nhận xét: Kết quả phân nhóm cho thấy phần lớn các
đơn hàng tại thị trường châu Á thuộc nhóm phát triển trung bình với tỷ
lệ 48,82, nghĩa là ở mức này sẽ có lợi nhuận từ 97 nghìn - 566 nghìn và
số lượng đơn hàng từ 2.518-7494, phản ánh sự ổn định và chiếm thị phần
chính của các sản phẩm này. Trong khi đó, nhóm phát triển tốt chiếm
36,67%, thể hiện có hơn một phần ba đơn hàng đạt hiệu quả kinh doanh
cao, đây là nhóm cần được ưu tiên đầu tư mở rộng để tối đa hóa lợi
nhuận. Ngược lại, chỉ 14,5% số đơn thuộc nhóm phát triển chậm, đa phần
là các sản phẩm có lượng bán và lợi nhuận thấp; doanh nghiệp nên rà
soát, điều chỉnh chính sách hoặc đổi mới sản phẩm đối với nhóm này để
cải thiện hiệu quả hoạt động kinh doanh.
Giải thích:
- Dòng 1: Khởi tạo biểu đồ pie chart trên bảng tần suất/tỷ lệ, trục x là chuỗi rỗng (để gom thành một vòng tròn), trục y chính là tỷ lệ phần trăm, fill là màu cho từng nhóm phát triển.
- Dòng 9, 10: Vẽ biểu đồ cột và them nhãn cho cột
- Dòng 13: scale_fill_manual() mỗi nhóm ứng với một nhóm sẽ mang màu riêng.
- Dòng 14: labs():Đặt tiêu đề và chú thích màu. Dòng 18: theme_void(base_family = “Arial”) + theme(…): Tạo giao diện cho biểu đồ
- Dòng 24: coord_polar(theta = “y”):Xoay trục y theo dạng tròn tạo hiệu ứng pie chart và mỗi cột tỷ trọng dồn vào thành một lát của hình tròn.
1. library(dplyr)
2. library(ggplot2)
3. speed_count <- Sales %>%
4. count(Sort_Date)
5. colnames(speed_count) <- c("Sort_Date", "n")
6. ggplot(speed_count, aes(x = n, y = Sort_Date, fill = Sort_Date)) +
7. geom_col(alpha = 0.8) +
8. geom_text(aes(label = format(n, big.mark = ".", scientific = FALSE)),
9. vjust = -0.5, hjust = 1.2, size = 4, fontface = "bold") +
10. geom_vline(xintercept = mean(speed_count$n),
11. linetype = "dashed", color = "red", linewidth = 1) +
12. scale_fill_brewer(palette = "Set2") +
13. scale_x_continuous(labels = label_number(big.mark = ".")) +
14. theme_light(base_size = 13) +
15. labs(
16. title = "Phân loại tốc độ giao hàng của đơn hàng",
17. x = "Số lượng đơn hàng",
18. y = "Nhóm tốc độ giao hàng"
19. ) +
20. theme(
21. plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
22. axis.text = element_text(size = 12),
23. legend.position = "none"
24. )
Nhận xét: -Biểu đồ thanh ngang thể hiện rõ ba nhóm: “Tốc độ chậm” là 25,709 đơn, “Tốc độ nhanh” là 23,553 đơn, “Tốc độ trung bình” là 50,738 đơn. Đường trung bình đỏ với khoảng 33,333 đơn giúp đối chiếu nhanh từng nhóm với chuẩn chung. Khoảng 50% đơn hàng (50.738 đơn) thuộc nhóm tốc độ trung bình với thời gian giao hàng khoảng từ 12–38 ngày. Đây là nhóm chủ đạo của quốc gia. Đơn “Tốc độ chậm” chiếm 25.7% vẫn được xem xét là chiếm ưu thế lớn, vì vậy các quốc gia cần xem xét và cải thiện hiệu suất giao hàng. Đối với đơn “Tốc độ nhanh” khoảng 23.6% quốc gia nên chú trọng và phát huy.
Giải thích:
- Dòng 3: tạo một bảng speed_count để đếm số lần xuất hiện của ba nhóm thuộc tốc độ giao hàng được tổng hợp theo khoảng tứ phân vị
- Dòng 6: khởi tạo biểu đồ
- Dòng 7, 8, 10: Vẽ biểu đồ cột, dán số lên cột và vẽ đường trung bình số đơn hang.
- Dòng 12: scale_fill_brewer()chọn bảng màu để dễ phân biệt cac nhóm.
- theme_light(base_size = 13), labs(), theme(…): Tạo giao diện, tiêu đề cho biểu đồ
- Dòng 13: scale_x_continuous(): Phân cách hàng nghìn
1. library(scales)
2. Cost_Item_Priority <- aggregate(Sales$Total.Cost,
3. by = list(Item = Sales$Item.Type, Priority = Sales$Order.Priority),
4. FUN = sum)
5. head(Cost_Item_Priority[order(Reve_Item_Priority$x),],5) #Doanh thu cao nhất
1. tail(Cost_Item_Priority[order(Reve_Item_Priority$x),],5) #Doanh thu thấp nhất
1. colnames(Cost_Item_Priority)[3] <- "Total_Cost"
1. Cost_Item_Priority <- Cost_Item_Priority %>%
2. mutate(Total_Cost_M = Total_Cost / 1e6)
3. Cost_Item_Priority
1. ggplot(Cost_Item_Priority, aes(x = Item, y = Total_Cost_M, fill = Priority)) +
2. geom_col(position = position_dodge(width = 0.8), width = 0.7, alpha = 0.9) +
3. geom_hline(yintercept = mean(Cost_Item_Priority$Total_Cost_M),
4. linetype = "dashed", color = "gray50", linewidth = 0.6)+
5. scale_y_continuous(
6. labels = label_number(big.mark = ".", decimal.mark = ",")
7. ) +
8. scale_fill_brewer(palette = "Set2") +
9. labs(title = "Tổng chi phí theo loại hàng và độ ưu tiên",
10. x = "Loại hàng", y = "Tổng doanh thu (đơn vị = 1.000.000)", fill = "Độ ưu tiên") +
11. theme_light(base_size = 15) +
12. theme(plot.title = element_text(face = "bold", hjust = 0.5),
13. axis.text.x = element_text(hjust = 0.75),
14. legend.position = "bottom") +
15. coord_flip(clip = "off")
Nhận xét: Biểu đồ thanh ngang nhóm này thể hiện tổng chi phí sản xuất của 12 loại hàng hóa theo bốn mức độ ưu tiên đơn hàng: Critical, High, Low, Medium. Các nhóm sản phẩm như Office Supplies, Meat, Household đều có chi phí sản xuất cao, ở mọi mức ưu tiên với từng thanh đạt xấp xỉ trên 4 tỷ đồng. Ngược lại, chi phí sản xuất của Fruit, Clothes, Beverages rất thấp, dao động từ khoảng dưới 1 tỷ đồng, bất kể nhóm ưu tiên nào. Nhóm hàng Office Supplies, Meat, Household thể hiện chi phí rất cao cho toàn bộ hệ thống, vượt trội hơn hẳn các nhóm còn lại, cho thấy đây là những mặt hàng tốn kém nhiều chi phí. Nhóm Critical, High và Medium ở các mặt hàng này mang về chi phí sản xuất lớn gần như ngang nhau, trong khi các mặt hàng như Beverages, Fruit, Clothes ít tốn kém, chỉ dao động từ 500 triệu đến hơn 2 tỷ đồng mỗi nhóm.
Giải thích:
- Tạo một bảng mới để phân tích doanh thu theo loại hang và mức độ ưu tiên
- Dòng 1: khởi tạo biểu đồ.
- Dòng 2: geom_col(): vẽ biểu đồ cột thể hiện doanh thu với position = position_dodge(width = 0.9): các thanh của cùng loại hàng nhưng khác độ ưu tiên sẽ xếp cạnh nhau và không đè lên nhau.
- Dòng 3: Vẽ thêm đường trung bình
- Dòng 5: phân cách hàng nghìn. Dòng 8: scale_fill_brewer(palette = “Set2”): Bảng màu cho các mức độ ưu tiên
- labs(…): Đặt tiêu đề và dán nhãn cho trục X và Y
- theme_light(base_size = 13) và theme(): Tạo giao diện của biểu đồ
- Dòng 15: coord_flip(clip = “off”):Đảo chiều biểu đồ sang ngang để tên loại hàng dài vẫn hiện rõ, nếu các thành phần nằm ngoài trục, vẫn hiện thị.
1. library(ggplot2)
2. library(dplyr)
3. # Tính tổng doanh thu theo quốc gia và sản phẩm
4. revenue_detail <- Sales %>%
5. group_by(Country, Item.Type) %>%
6. summarise(Revenue = sum(Total.Revenue, na.rm = TRUE), .groups = "drop")
7. # Lấy 10 quốc gia có doanh thu thấp nhất
8. top_countries_list <- Sales %>%
9. group_by(Country) %>%
10. summarise(Total.Revenue= sum(Total.Revenue, na.rm = TRUE)) %>%
11. arrange(Total.Revenue) %>%
12. slice(1:10) %>%
13. pull(Country)
14. print(top_countries_list)
## [1] "Angola" "Jamaica"
## [3] "Palau" "Vietnam"
## [5] "Switzerland" "United States of America"
## [7] "Solomon Islands" "Iceland"
## [9] "Germany" "Kazakhstan"
1. # Lọc dữ liệu chi tiết chỉ top 10 quốc gia
2. revenue_detail_top <- revenue_detail %>%
3. filter(Country %in% top_countries_list) %>%
4. mutate(Country = factor(Country, levels = top_countries_list))
5. country_sum <- tapply(revenue_detail_top$Revenue, revenue_detail_top$Country, sum)
6. mean_sum <- mean(country_sum)
7. ggplot(revenue_detail_top, aes(x = Country, y = Revenue, fill = Item.Type)) +
8. geom_col(position = "stack", width = 0.7) +
9. geom_text(
10. aes(label = ifelse(Revenue > quantile(Revenue, 0.85), comma_vn(round(Revenue, 0)), "")),
11. position = position_stack(vjust = 0.5), size = 2.5, color = "black", fontface = "bold"
12. ) +
13. stat_summary(
14. aes(group = Country),
15. fun = sum, geom = "text",
16. vjust = -0.5, size = 3.5, fontface = "bold",
17. label = comma_vn(country_sum)
18. ) +
19. coord_flip(clip = "off") +
20. scale_fill_brewer(palette = "Set3", name = "Loại sản phẩm") +
21. scale_y_continuous(labels = comma_vn, expand = expansion(mult = c(0, 0.12))) +
22. labs(
23. title = "Top 10 Quốc gia: Doanh thu thấp theo Loại sản phẩm",
24. subtitle = "Mỗi màu sắc = loại sản phẩm",
25. x = "Quốc gia", y = "Tổng Doanh thu",
26. caption = "Nguồn: Dữ liệu 100,000 Sales Records"
27. ) +
28. theme_minimal() +
29. theme(
30. legend.position = "right",
31. axis.text.y = element_text(size = 11, face = "bold"),
32. plot.title = element_text(face = "bold", size = 14)
33. )
Nhận xét: Top 10 quốc gia đều có tổng lợi nhuận trên 234 tỷ đồng, vượt khá xa mức trung bình nhóm (khoảng 237 tỷ). Một số thị trường như Sudan, Hungary, Micronesia và Malta ghi nhận mức lợi nhuận vượt trội, trong khi đó các quốc gia còn lại tiệm cận trung bình. Cơ cấu sản phẩm (mỗi màu) cho thấy nhóm sản phẩm nào là chủ lực ở từng nước, giúp doanh nghiệp xác định sản phẩm mũi nhọn cần tập trung hoặc các phân khúc tiềm năng có thể phát triển thêm.
Giải thích:
- Tạo một bảng top_countries_list để lấy top 10 doanh thu thấp nhất
- revenue_detail_top: để lọc dẽu liệu chi tiết top 10 quốc gia
- Dòng 7: Khởi tạo biểu đồ.
- Dòng 8, 9: Vẽ cột nằm chồng theo từng quốc gia. Mỗi cột sẽ gồm các phần nhỏ tương ứng từng loại sản phẩm và xhỉ hiển thị nhãn số doanh thu với các phần doanh thu lớn hơn phân vị 0.85 (top 15% giá trị cao nhất), các giá trị còn lại để trắng. Số nằm giữa cột, font đậm và rõ.
- Dòng 13: Hiển thị tổng doanh thu mỗi quốc gia ngay trên đầu cụm cột của từng nước, giúp đọc tổng dễ dàng. Dùng luôn hàm định dạng comma_vn nên số luôn tách nhóm nghìn bằng dấu chấm.
- Dòng 19: coord_flip(clip = “off”):Đảo chiều biểu đồ sang ngang để tên loại hàng dài vẫn hiện rõ, nếu các thành phần nằm ngoài trục, vẫn hiện thị.
- Còn lại là chỉnh màu cho cột, tên tiêu đề và giao diện cho biểu đồ
1. df_sum <- Sales %>%
2. group_by(Region, Year) %>%
3. summarise(
4. Revenue = sum(Total.Revenue, na.rm=TRUE),
5. Cost = sum(Total.Cost, na.rm=TRUE),
6. Profit = sum(Total.Profit, na.rm=TRUE),
7. .groups = "drop"
8. ) %>%
9. pivot_longer(cols = c("Revenue", "Cost", "Profit"), names_to = "Indicator", values_to = "Value")
Nhận xét: Việc tổng hợp doanh thu, chi phí, lợi nhuận theo từng khu vực và từng năm cho phép đánh giá chính xác hiệu quả hoạt động kinh doanh tại từng thị trường và so sánh các biến động theo thời gian.
Giải thích:
- Dòng 1: tạo bảng df_sum để tổng hợp các chỉ số theo khu vực và năm
- Dòng 9: pivot_longer(cols = …): Đưa bảng về dạng bảng dài, gộp ba cột chỉ số thành hai cột là Indicator: chứa tên chỉ số (“Revenue”, “Cost”, “Profit”) và Value: giá trị từng chỉ số tương ứng.
1. df_my <- df_sum %>%
2. filter(Region == "North America")
3. ggplot(df_my, aes(x = Year, y = Value, color = Indicator, group = Indicator)) +
4. geom_line(size = 1.4) +
5. geom_point(size = 2.5) +
6. geom_text(
7. aes(label = comma_vn(round(Value,0))),
8. vjust = -0.5, size = 3, fontface = "bold", color= "black") +
9. scale_color_manual(
10. values = c("Revenue" = "#1C7ED6", "Cost" = "#FFC300", "Profit" = "#21A179"),
11. labels = c("Doanh thu", "Chi phí", "Lợi nhuận"),
12. name = "Chỉ số tài chính") +
13. scale_y_continuous(labels = comma_vn, expand = expansion(mult = c(0, 0.12)))+
14. labs(
15. title = "Doanh thu, Chi phí, Lợi nhuận Châu Mỹ theo năm",
16. x = "Năm", y = "Giá trị", color = "Chỉ số tài chính" ) +
17. theme_minimal() +
18. theme(
19. plot.title = element_text(face = "bold", size = 13),
20. legend.position = "bottom")
Nhận xét: Dưới góc nhìn kinh tế, biểu đồ cho thấy khu vực Châu Mỹ trải qua một chu kỳ kinh doanh điển hình khi trả qua quá trình gần 7 năm. Từ năm 2010 đến 2013, doanh thu, chi phí và lợi nhuận đều tăng đồng bộ, phản ánh sự mở rộng kinh tế. Tuy nhiên, từ sau năm 2013, doanh thu và lợi nhuận giảm mạnh, trong khi chi phí vẫn duy trì ở mức cao, cho thấy hiệu quả sản xuất kinh doanh giảm sút. Diễn biến này có thể xuất phát từ suy giảm tăng trưởng kinh tế toàn cầu, biến động tỷ giá hoặc cạnh tranh gia tăng khiến biên lợi nhuận bị thu hẹp. Đến năm 2017, cả ba chỉ tiêu đều ở mức thấp nhất trong giai đoạn, đòi hỏi các phải tái cấu trúc và tối ưu chi phí để duy trì khả năng sinh lợi.
Giải thích:
- Dòng 1: Lọc dữ liệu tổng hợp chỉ giữ lại khu vực Bắc Mỹ
- Dòng 3: Khởi tạo biểu đồ.
- Dòng 4, 5, 6: Vẽ biểu đồ đường, them các điểm tròn và nhãn từng điểm trên đường
- Dòng 13: scale_y_continuous(labels = comma_vn, expand = expansion(mult = c(0, 0.12))): phân cách hàng nghìn. Khoảng mở rộng trục y phía trên 12% để nhãn tổng không bị cắt biên.
- labs(…): Đặt tiêu đề, chú thích và dán nhãn cho trục X và Y. theme_minimal() và theme(): Tạo giao diện của biểu đồ. scale_color_manual() Cài đặt màu cho từng chỉ tiêu.
1. # Xác định năm mới nhất có trong dữ liệu
2. latest_year <- Sales %>%
3. filter(Region == "North America") %>%
4. summarise(MaxYear = max(Year, na.rm = TRUE)) %>%
5. pull(MaxYear)
6. # Tính tổng doanh thu từng quốc gia Bắc Mỹ trong năm mới nhất
7. country_rev_na_latest <- Sales %>%
8. filter(Region == "North America", Year == latest_year) %>%
9. group_by(Country) %>%
10. summarise(TotalRevenue = sum(Total.Revenue, na.rm = TRUE), .groups = "drop")
Giải thích:
filter(Region == "North America"): lọc và chỉ chọn khu vực Bắc Mỹ.summarise(MaxYear = max(Year, na.rm = TRUE)): tính năm lớn nhất xuất hiện trong tập lọc này, loại bỏ NA.pull(MaxYear): lấy giá trị MaxYear vừa tính ra và gán vào biến latest_year.filter(Region == "North America", Year == latest_year)Lọc khu vực Bắc Mỹ và của những năm mới nhất.group_by(Country): Gom nhóm dữ liệu theo từng quốc giasummarise(...): Tổng hợp lại nhóm vừa tạo và thực hiện tính tổng doanh thu.groups = "drop": Sau khi tổng hợp, kết quả trả về là bảng phẳng, không còn nhóm nào.
1. ggplot(country_rev_na_latest, aes(x = "", y = TotalRevenue, fill = Country)) +
2. geom_col(width = 1, color = "gray90") +
3. coord_polar(theta = "y") +
4. geom_text(aes(label = comma_vn(round(TotalRevenue, 0))),
5. position = position_stack(vjust = 0.5),
6. size = 4, color = "black", fontface = "bold") +
7. scale_fill_brewer(palette = "Set3") +
8. labs(
9. title = paste("Doanh thu Bắc Mỹ từng quốc gia năm", latest_year),
10. fill = "Quốc gia") +
11. theme_void(base_family = "Arial") +
12. theme(
13. plot.title = element_text(face = "bold", size = 13, hjust = 0.5),
14. legend.title = element_text(size = 13, face = "bold"),
15. legend.text = element_text(size = 13),
16. legend.position = "right")
Nhận xét: Biểu đồ trên thể hiện doanh thu của các quốc gia thuộc khu vực Bắc Mỹ năm 2017, bao gồm Hoa Kỳ, Mexico, Canada và Greenland. Dưới góc nhìn kinh tế, có thể thấy Mexico dẫn đầu về doanh thu với hơn 81,8 triệu. Điều này phản ánh quy mô thị trường tiêu dùng nội địa lớn. Hoa Kỳ đứng thứ hai với khoảng 55,7 triệu, cho thấy dù là nền kinh tế lớn và phát triển bậc nhất khu vực, song mức doanh thu trong năm 2017 có xu hướng giảm so với các giai đoạn tăng trưởng trước đó, có thể do biến động nhu cầu tiêu dùng và cạnh tranh toàn cầu. Canada và Greenland lần lượt đạt 50,1 triệu và 47,5 triệu, phản ánh quy mô dân số nhỏ hơn và cơ cấu kinh tế thiên về tài nguyên và dịch vụ thay vì sản xuất hàng hóa tiêu dùng.
Giải thích:
- Dòng 1: Khởi tạo biểu đồ pie chart
- Dòng 2: geom_col(width = 1, color = “gray90”): Tạo từng lát tròn, lát đầy đủ, viền xám nhạt để phân biệt rõ các phần.
- Dòng 3: coord_polar(theta = “y”): Chuyển biểu đồ từ bar sang pie chart bằng cách xoay trục y thành vòng tròn.
- Dòng 4: Hiển thị nhãn số doanh thu, phân cách đúng dấu chấm nghìn trên từng lát.
- Dòng 7: Tô màu cho từng quốc gia giúp biểu đồ dễ phân biệt.
- labs(…): Đặt tiêu đề, chú thích và dán nhãn cho trục X và Y . theme() và theme_void(base_family = “Arial”) tạo giao diện của biểu đồ và chọn font chữ Arial
1. # Tính tổng lợi nhuận và chi phí từng quốc gia
2. europe_data <- Sales %>% filter(Region == "Europe") %>% group_by(Country) %>%
3. summarise(
4. TotalProfit = sum(Total.Profit, na.rm = TRUE),
5. TotalCost = sum(Total.Cost, na.rm = TRUE))
6. # Lấy top 10 quốc gia có giá trị Indicator cao nhất
7. top10_countries <- europe_data %>%
8. arrange(desc(TotalProfit)) %>%
9. slice_head(n = 10) %>%
10. pull(Country)
11. # Chuyển dữ liệu về dạng long
12. europe_long_top10 <- europe_data %>%
13. filter(Country %in% top10_countries) %>%
14. pivot_longer(
15. cols = c(TotalProfit, TotalCost),
16. names_to = "Indicator",
17. values_to = "Value")
Giải thích:
- Dòng 2: Lấy bảng dữ liệu gốc Sales và thực hiện chuỗi xử lý tổng hợp, kết quả cuối cùng gán vào biến europe_data .
filter(Region == "Europe") %>%: Lọc chỉ giữ lại các khu vực là Europe.group_by(): Gom nhóm dữ liệu để tính toán.summarise(): Tổng hợp lại nhóm vừa tạo và thực hiện tính tổng lợi nhuận và chi phí, loại trừ các giá trị NA nếu có. Kết quả là bảng có ba cột: Country, TotalProfit, TotalCost .- Dòng 7:
top10_countries: Sắp xếp bảng theo tổng lợi nhuận giảm dần. Giữ lại 10 quốc gia đứng đầu về tổng lợi nhuận. Rút ra tên quốc gia để dùng cho bước lọc tiếp theo .- Dòng 13: Chỉ giữ lại các quốc gia thuộc top 10 vừa lọc. Sử dụng pivot_longer chuyển dữ liệu từ dạng rộng sang dạng dài để dễ vẽ biểu đồ nhóm.
cols = c(TotalProfit, TotalCost): Chỉ chuyển hai cột này.names_to = "Indicator": Tạo cột mới chứa tên chỉ số của TotalProfit hoặc TotalCost.values_to = "Value": Tạo cột mới chứa giá trị tương ứng. Mỗi quốc gia sẽ có hai dòng: một dòng lợi nhuận, một dòng chi phí .
1. ggplot(europe_long_top10, aes(x = reorder(Country, Value), y = Value, fill = Indicator)) +
2. geom_col(position = position_dodge(width = 0.7), width = 0.7, alpha = 0.93) +
3. geom_text(aes(label = format(Value, big.mark = ".", scientific = FALSE)),
4. position = position_dodge(width = 0.7),
5. hjust = 1, vjust = 0.5, size = 3.2, family = "Arial", color = "black") +
6. scale_fill_manual(
7. values = c("TotalProfit" = "#21A179", "TotalCost" = "#FFC300"),
8. labels = c("Lợi nhuận", "Chi phí")) +
9. coord_flip() +
10. scale_y_continuous(labels = function(x) format(x, big.mark = ".", scientific = FALSE),
11. expand = expansion(mult = c(0, 0.12))) +
12. labs(
13. title = "Top 10 quốc gia Châu Âu theo tổng lợi nhuận và chi phí",
14. subtitle = "Quốc gia xếp theo tổng lợi nhuận cao nhất",
15. x = "Quốc gia",
16. y = "Tổng giá trị",
17. fill = "Chỉ số") +
18. theme_minimal(base_size = 13) +
19. theme(
20. legend.position = "bottom",
21. axis.text.y = element_text(family = "Arial", size = 13))
Nhận xét: Biểu đồ cho thấy top 10 quốc gia Châu Âu có tổng lợi nhuận và chi phí cao nhất, trong đó Hungary, Malta và Romania là ba quốc gia dẫn đầu với tổng chi phí lần lượt đạt 241,86 triệu, 234,37 triệu và 223,97 triệu và lợi nhuận tại các quốc gia này cũng ở mức rất cao, dao động từ khoảng 511 triệu đến gần 596 triệu, phản ánh quy mô hoạt động kinh tế lớn và mức đầu tư cao. Nhìn chung, nhóm quốc gia như Hungary, Romania, Bulgaria đang có xu hướng mở rộng quy mô sản xuất và thương mại, thể hiện qua mức chi tiêu và lợi nhuận cao, trong khi các quốc gia nhỏ hơn như Estonia, Macedonia hay Serbia vẫn duy trì hiệu quả ổn định nhưng ở quy mô nhỏ hơn. Xu hướng này phản ánh sự phân hóa về năng lực sản xuất và hiệu quả kinh tế giữa các nền kinh tế Châu Âu.
Giải thích:
- Dòng 1: Khởi tạo biểu đồ.
- Dòng 2:
geom_col(): Vẽ cột với hai chỉ số lợi nhuận và chi phí cùng quốc gia được đặt cạnh nhau; cột có độ rộng 0.7 và hơi trong suốt giúp nhìn rõ lưới nền.- Dòng 3:
geom_text(): Thêm nhãn giá trị lên từng cột, định dạng với dấu chấm ngăn cách hàng nghìn.- Dòng 6:
scale_fill_manual(): Đặt màu cho cột lợi nhuận màu xanh, chi phí màu vàng.- Dòng 9:
coord_flip(): Lật trục giúp quốc gia xếp dọc, nhãn dễ nhìn, phù hợp khi có nhiều quốc gia.- Dòng 10: Định dạng trục y với dấu chấm ngăn cách hàng nghìn.
expand = expansion(mult = c(0, 0.12)): Thêm khoảng trắng bên phải để không cắt mất nhãn lớn nhất.labs(...): Đặt tiêu đề, chú thích và dán nhãn cho trục X và Ytheme_minimal(base_size = 13)vàtheme(): Tạo giao diện của biểu đồ.
1. bubble_df <- Sales %>%
2. group_by(Item.Type, Year) %>%
3. summarise(
4. TotalProfit = sum(Total.Profit, na.rm=TRUE),
5. UnitsSold = sum(Units.Sold, na.rm=TRUE)
6. ) %>%
7. ungroup()
8. # Lấy top 8 sản phẩm lớn.
9. top_items <- bubble_df %>%
10. group_by(Item.Type) %>%
11. summarise(SumProfit = sum(TotalProfit)) %>%
12. arrange(desc(SumProfit)) %>%
13. slice(1:8) %>%
14. pull(Item.Type)
Giải thích:
group_by(Item.Type, Year): Gộp nhóm, mỗi nhóm là một tổ hợp sản phẩm và năm để thực hiện tổng hợp riêng biệt.summarise(...): tổng hợp và tính tổng lợi nhuận từng nhóm, cộng lợi nhuận và số lượng hàng bán từng loại sản phẩm mỗi năm, bỏ qua giá trị thiếu.ungroup(): Xóa trạng thái nhóm; kết quả là bảng tổng hợp, từng dòng là một sản phẩm-năm. Sau đó lọc và lấy top 8 sản phẩm lớn có lợi nhuận lớn nhất.
1. library(ggplot2)
2. library(scales)
3. # Hàm rút gọn số kiểu
4. format_short <- function(x) {
5. ifelse(abs(x) >= 1e6, paste0(round(x/1e6,1),"M"),
6. ifelse(abs(x) >= 1e3, paste0(round(x/1e3,1),"K"),
7. as.character(x)))}
8. ggplot(bubble_df %>% filter(Item.Type %in% top_items),
9. aes(x = Year, y = Item.Type, size = UnitsSold, fill = TotalProfit)) +
10. geom_point(alpha = 0.87, shape = 21, color = "#333333") +
11. scale_size_continuous(range = c(3.5, 17), name = "Số lượng bán") +
12. scale_fill_viridis_c(option = "plasma", name = "Tổng lợi nhuận") +
13. geom_text(aes(label = format_short(TotalProfit)),
14. size = 2.2, color = "black", vjust = 0.8, fontface = "bold")
r 1. labs(title = "Tổng lợi nhuận và quy mô bán sản phẩm", 2. subtitle = "Bong bóng càng to: càng nhiều bán; 3. màu nóng = lãi lớn, số trong bóng = lãi", 4. x = "Năm", y = "Sản phẩm") + 5. theme_light(base_size = 13) + 6. theme( 7. plot.title = element_text(face = "bold", size = 13), 8. axis.text.y = element_text(size = 10, face = "bold") 9. ) + 10. scale_x_discrete(expand = expansion(mult = c(0.04, 0.08)))
## NULL
Nhận xét: Các sản phẩm Household và Cosmetics là những mặt hàng nổi bật nhất với lợi nhuận mỗi năm từ 900 triệu, đồng thời có quy mô bán hàng rất lớn. Ngược lại, nhóm Vegetables và Meat có lợi nhuận thấp hơn rõ rệt, nhiều năm chỉ đạt khoảng 200–400 triệu. Đặc biệt, xu hướng chung là lợi nhuận và số lượng bán đều giảm nhẹ qua các năm: Household giảm từ 1,2 tỷ năm 2010 xuống dưới 500 triệu năm 2017, còn Vegetables chỉ còn khoảng 200 triệu năm cuối. Điều này cho thấy doanh nghiệp cần tập trung vào các nhóm hàng chủ lực, đồng thời cân nhắc các giải pháp để cải thiện sức bán và lợi nhuận cho các sản phẩm yếu hơn trong tương lai.
Giải thích:
- Dòng 4:
format_short <- function(x) { ... }: định nghĩa hàm với x giá trị số bạn muốn rút gọn,abs()là giá trị tuyệt đối của x, dùng để xử lý cả số âm. Sử dụng hàm ifelse lồng nhau để phân loại theo độ lớn của x, nếu lớn hơn 1 triệu, rút gọn về M, nếu lớn hơn 1 nghìn thì rút gọn về K, còn lại trả về dạng character.- Dòng 9: Khởi tạo biểu đồ.
- Dòng 11:
geom_point(alpha=0.87, shape=21, color="#333333"): Vẽ bong bóng với độ trong suốt 87%,shape=21: Hình tròn rỗng ở giữa, có thể tô màu nền và viền riêng.color="#333333": Viền ngoài bong bóng màu xám đậm.- Dòng 12:
scale_size_continuous(range=c(3.5, 17), name="Số lượng bán"): Chỉnh tỷ lệ kích thước bong bóng từ nhỏ tới lớn và đặt tên “Số lượng bán”.- Dòng 13:
scale_fill_viridis_c(option="plasma", name="Tổng lợi nhuận"): Dùng bảng màu liên tục viridis, giúp dễ nhìn sự khác biệt lợi nhuận vì màu càng nóng.- Dòng 14:
geom_text(): Thêm nhãn số vào giữa bong bóng, hiển thị phân cách hàng nghìn cho lợi nhuận.labs(): Đặt tiêu đề lớn, phụ đề giải thích và ghi chú trục cũng như chú giải màu cho biểu đồ.theme_light(base_size=11): Chọn nền sáng, chữ cơ bản cỡ 11.theme(): Tạo giao diện của biểu đồ.- Dòng 25:
scale_x_discrete(expand=expansion(mult=c(0.04,0.08))): Dãn trục x ở hai đầu, giúp các bong bóng ngoài cùng không bị sát lề biểu đồ.
1. library(dplyr)
2. # Xác định top 3 quốc gia doanh thu cao nhất
3. country_total <- Sales %>%
4. group_by(Country) %>%
5. summarise(TotalRevenue = sum(Total.Revenue, na.rm = TRUE), .groups = "drop")
6. # Lấy tên 3 nước dẫn đầu
7. top3_countries <- country_total %>%
8. arrange(desc(TotalRevenue)) %>%
9. slice_head(n = 3) %>%
10. pull(Country)
11. # Bảng heatmap doanh thu từng sản phẩm trong 3 nước này
12. sales_heatmap <- Sales %>%
13. filter(Country %in% top3_countries) %>%
14. group_by(Item.Type, Country) %>%
15. summarise(TotalRevenue = sum(Total.Revenue, na.rm = TRUE), .groups = "drop")
16. head(sales_heatmap)
1. library(ggplot2)
2. ggplot(sales_heatmap, aes(x = Country, y = Item.Type, fill = TotalRevenue)) +
3. geom_tile(color = "white", linewidth = 0.6) +
4. geom_text(aes(label = format(TotalRevenue, big.mark = ".",scientific = FALSE )),
5. color = "black", size = 3) +
6. scale_fill_gradient(low = "#FDEBD0", high = "#922B21", name = "Tổng doanh thu")+
7. labs(title = "Heatmap doanh thu sản phẩm tại top 3 quốc gia",
8. x = "Quốc gia (doanh thu cao nhất)",
9. y = "Loại sản phẩm") +
10. theme_minimal(base_size = 11) +
11. theme(axis.text.x = element_text(angle = 20, hjust = 1, size = 9),
12. axis.text.y = element_text(size = 9))
Nhận xét: Quan sát màu sắc thể hiện cường độ doanh thu, có thể thấy Office Supplies (văn phòng phẩm) là nhóm sản phẩm tạo doanh thu cao nhất ở cả ba quốc gia, đặc biệt tại Bahrain (232,3 triệu VND), cho thấy nhu cầu lớn về hàng hóa phục vụ văn phòng và hoạt động hành chính, phản ánh nền kinh tế dịch vụ hoặc hành chính phát triển mạnh. Tiếp theo là các nhóm sản phẩm Household (đồ gia dụng) và Meat (thịt) cũng đạt mức doanh thu cao và tương đối đồng đều giữa các quốc gia, cho thấy đây là những mặt hàng thiết yếu, có nhu cầu tiêu dùng ổn định. Ngược lại, các nhóm như Fruits (trái cây), Beverages (đồ uống) và Personal Care (chăm sóc cá nhân) có doanh thu thấp hơn rõ rệt, thể hiện nhu cầu tiêu dùng chưa lớn ở các quốc gia này.
Giải thích:
- Dòng 2: Khởi tạo biểu đồ heatmap từ bảng sales_heatmap,
- Dòng 3:
geom_tile(color = "white", linewidth = 0.6): Vẽ từng ô vuông của heatmap. Mỗi ô đại diện cho một cặp sản phẩm – quốc gia, đổ màu tuỳ theo giá trị doanh thu. Viền ô màu trắng, độ dày đường viền là 0.6 giúp các ô tách biệt rõ khi đọc dữ liệu.- Dòng 4:
geom_text(): Thêm nhãn số doanh thu trên từng ô; số được định dạng với dấu chấm ngăn cách hàng nghìn.- Dòng 6:
scale_fill_gradient(): Bảng màu chuyển từ màu sáng (doanh thu nhỏ) đến màu đậm (doanh thu lớn) giúp trực quan hóa sự khác biệt doanh thu.labs():Đặt tiêu đề, nhãn trục x và trục y,theme_minimal(base_size = 11):Thiết lập phong cách đồ họa tối giản,theme():Tạo giao diện cho biểu đồ
1. library(ggplot2)
2. library(dplyr)
3. # Có các cột: Region, Country, Item.Type, Total.Revenue
4. sales_asia <- Sales %>% filter(Region == "Asia")
5. # Tính doanh thu theo sản phẩm và quốc gia (chi tiết)
6. sum_by_product <- sales_asia %>% group_by(Country, Item.Type) %>%
7. summarise(TotalRevenue = sum(Total.Revenue), .groups = 'drop')
8. # Top 5 sản phẩm doanh thu lớn nhất toàn châu Á
9. top5_tbl <- sum_by_product %>% group_by(Item.Type) %>%
10. summarise(TotalRevenue = sum(TotalRevenue), .groups='drop') %>%
11. arrange(desc(TotalRevenue)) %>% slice_head(n = 5)
12. top5_items <- top5_tbl$Item.Type
13. # Gom các sản phẩm còn lại thành "Các sản phẩm khác"
14. plot_data <- sum_by_product %>%
15. mutate(Item.Type = ifelse(Item.Type %in% top5_items, Item.Type,
16. "Các sản phẩm khác"))%>%
17. group_by(Item.Type)%>%summarise(TotalRevenue = sum(TotalRevenue),.groups='drop')
18. total_revenue_sum <- sum(plot_data$TotalRevenue)
19. plot_data <- plot_data %>% arrange(desc(TotalRevenue))
Giải thích:
- Dòng 4: Lọc dữ liệu chỉ lấy các dòng khu vực Châu Á để tập trung phân tích doanh thu cho thị trường này.
- Dòng 6:
sum_by_product: Tạo data frame mới để tính tổng doanh thu cho từng loại sản phẩm tại từng quốc gia thuộc Châu Á.- Dòng 9: Gom tổng doanh thu của từng loại sản phẩm qua các quốc gia Châu Á, sắp xếp giảm dần và chọn 5 sản phẩm bán chạy nhất.
- Dòng 14: Các sản phẩm không thuộc top 5 sẽ được gộp tên thành “Các sản phẩm khác”. Sau đó tiếp tục cộng tổng doanh thu cho từng nhóm này.
- Dòng 21: Sắp xếp nhóm sản phẩm theo doanh thu giảm dần để trình bày đẹp trên biểu đồ. Tính tổng doanh thu tất cả nhóm để sử dụng ở chú thích trung tâm.
1. pastel_colors<-c("#FFB3BA", "#BAE1FF", "#BFFCC6", "#FFFACD", "#D5BAFF", "#FFDAC1")
2. ggplot(plot_data, aes(x = 2, y = TotalRevenue, fill = Item.Type)) +
3. geom_bar(stat = "identity", width = 1.5, color = "black") +
4. scale_fill_manual(values = pastel_colors) +
5. coord_polar(theta = "y") +
6. xlim(0.5, 3) +
7. geom_text(aes(label = scales::comma(TotalRevenue, big.mark = ".")),
8. position = position_stack(vjust = 0.5), size = 3, color = "black") +
9. annotate("text",x = 0.5, y = 0,
10. label = paste0("Tổng: ", scales::comma(total_revenue_sum, big.mark = ".")),
11. size = 4,fontface = "bold",color = "black") +
12. labs(title = "Doanh thu top 5 sản phẩm tại Châu Á") +
13. theme_void() +
14. theme(text = element_text(family = "Arial"),
15. plot.title = element_text(size = 13, face = "bold", hjust = 0.5))
Nhận xét: Trong đó, sản phẩm “Các sản phẩm khác” có doanh thu 4,713 tỷ, thể hiện sự đa dạng hóa danh mục sản phẩm và đóng góp đáng kể từ nhiều mặt hàng nhỏ lẻ ngoài nhóm chính. Tiếp theo là Office Supplies (4,029 tỷ) và Household (3,829 tỷ) — hai nhóm sản phẩm thiết yếu trong đời sống và kinh doanh, cho thấy nhu cầu tiêu dùng ổn định và quy mô thị trường lớn. Các nhóm còn lại như Cosmetics (2,615 tỷ), Meat (2,550 tỷ) và Baby Food (1.557 tỷ) đóng góp phần nhỏ hơn nhưng vẫn giữ vai trò quan trọng trong cơ cấu chung. Tổng doanh thu của khu vực đạt khoảng 19.293 tỷ, phản ánh mức tiêu thụ hàng hóa khá cao tại Châu Á, đặc biệt ở các mặt hàng thiết yếu và sản phẩm phục vụ sinh hoạt.
Giải thích:
- Dòng 1:
pastel_colors: Tạo bảng màu pastel cho từng lát biểu đồ.- Dòng 2: Khởi tạo biểu đồ.
- Dòng 4:
scale_fill_manual(): Gán màu pastel vào từng lát sản phẩm trên donut, giúp phân biệt từng loại rõ ràng.- Dòng 5:
coord_polar(theta = "y") + xlim(0.5, 3): Chuyển biểu đồ dạng cột thành tròn nhờ hệ tọa độ polar, kết hợp xlim để tạo hiệu ứng donut, có lỗ lớn ở giữa cho nhãn.- Dòng 7:
geom_text(): Hiển thị doanh thu từng lát cắt, chuyển dạng số theo phân cách hàng nghìn dấu chấm.- Dòng 9:
annotate("text"): Đặt chú thích tổng doanh thu của toàn bộ vòng tròn ngay giữa tâm.labs(title = "Doanh thu top 5 sản phẩm tại các quốc gia Châu Á") + theme_void() + theme(...): Đặt tiêu đề, bỏ trục/tick labels, tùy chỉnh font và kích thước cho biểu đồ thật gọn, dễ nhìn và hiện đại.
1. # Lọc chỉ lấy Châu Á và Châu Âu
2. cost_year_region <- Sales %>%
3. filter(Region %in% c("Asia", "Europe")) %>%
4. group_by(Year, Region) %>%
5. summarise(TotalCost = sum(Total.Cost), .groups = 'drop') %>%
6. arrange(Year, Region)
7.
8. ggplot(cost_year_region, aes(x = as.factor(Year), y = TotalCost, fill = Region))+
9. geom_col(position = "dodge", color = "black", width = 0.7) +
10. geom_text(
11. aes(label = scales::comma(TotalCost, big.mark = ".")),
12. position = position_dodge(width = 0.7), vjust = 0.5,
13. hjust = 1,size = 4, color = "black", angle = 90) +
14. scale_y_continuous(labels = scales::comma_format(big.mark = ".")) +
15. scale_fill_manual(values = c("Asia" = "#8fd3f4", "Europe" = "#dab6fc")) +
16. labs(title = "Tổng Total Cost theo năm (Châu Á vs Châu Âu)",
17. x = "Năm", y = "Tổng chi phí", fill = "Khu vực") +
18. theme_minimal(base_size = 13) +
19. theme(plot.title = element_text(face = "bold", hjust = 0.5))
>Nhận xét” Biểu đồ trên thể hiện tổng chi phí (Total
Cost) của hai khu vực Châu Á và Châu Âu trong giai đoạn 2010–2017. Nhìn
chung, tổng chi phí của Châu Âu luôn cao hơn đáng kể so với Châu Á trong
toàn bộ giai đoạn, dao động trong khoảng từ 3,1 đến 3,3 tỷ đồng, phản
ánh quy mô hoạt động sản xuất – kinh doanh lớn hơn cũng như chi phí vận
hành và nhân công cao hơn. Trong khi đó, tổng chi phí của Châu Á duy trì
ở mức thấp hơn, trung bình khoảng 1,7 – 1,9 tỷ đồng, cho thấy khu vực
này có lợi thế về chi phí nhờ nguồn nhân công rẻ, điều kiện sản xuất
thuận lợi và chính sách ưu đãi thuế. Xét về xu hướng, từ năm 2010 đến
2013, tổng chi phí của cả hai khu vực đều có xu hướng tăng, thể hiện sự
mở rộng quy mô hoạt động. Giai đoạn 2014–2016, chi phí tại cả hai khu
vực có sự ổn định tương đối hoặc tăng nhẹ, có thể do tác động từ giá
nguyên liệu và chi phí logistics tăng. Đến năm 2017, tổng chi phí của cả
hai khu vực đều giảm mạnh, đặc biệt là tại Châu Á, cho thấy khả năng các
doanh nghiệp đã tái cấu trúc hoạt động, cắt giảm chi phí và tối ưu hóa
nguồn lực.
Giải thích:
- Dòng 2:
cost_year_regiontạo dataframe mới để tính tổng chi phí theo năm và khu vực..- Dòng 8: Khởi tạo biểu đồ.
- Dòng 9:
geom_col(): Vẽ biểu đồ cột nhóm.- Dòng 10:
geom_text()Chèn nhãn số tổng chi phí lên mỗi cột theo chiều dọc (angle = 90).- Dòng 14: Phân cách hàng nghìn ở số.
- Dòng 15: Tô màu cho cột.
labs(): Đặt tiêu đề cho biểu đồ, nhãn cho trục x và y.theme_minimal(base_size = 14) + theme():Tạo giao diện cho biểu đồ
1. # Có các cột: Region, Country, Item.Type, Total.Revenue
2. sales_europe <- Sales %>% filter(Region == "Europe")
3. # Tính doanh thu theo sản phẩm và quốc gia
4. sum_by_product <- sales_europe %>% group_by(Country, Item.Type) %>%
5. summarise(TotalRevenue = sum(Total.Revenue), .groups = 'drop')
6. # Top 5 sản phẩm doanh thu lớn nhất toàn châu Âu
7. top5_tbl <- sum_by_product %>% group_by(Item.Type) %>%
8. summarise(TotalRevenue = sum(TotalRevenue), .groups='drop') %>%
9. arrange(desc(TotalRevenue)) %>% slice_head(n = 5)
10. top5_items <- top5_tbl$Item.Type
11. # Gom các sản phẩm còn lại thành "Các sản phẩm khác"
12. plot_data <- sum_by_product %>%
13. mutate(Item.Type = ifelse(Item.Type %in% top5_items,
14. Item.Type, "Các sản phẩm khác")) %>%
15. group_by(Item.Type)%>%summarise(TotalRevenue=sum(TotalRevenue), .groups='drop')
16. total_revenue_sum <- sum(plot_data$TotalRevenue)
17. plot_data <- plot_data %>% arrange(desc(TotalRevenue))
Giải thích:
- Dòng 2: Lọc dữ liệu chỉ lấy khu vực Châu Âu để phân tích doanh thu sản phẩm.
- Dòng 5: Tính tổng doanh thu từng sản phẩm tại từng quốc gia châu Âu.
- Dòng 9: Cộng doanh thu của từng sản phẩm trên toàn châu Âu và lấy top 5 sản phẩm doanh thu cao nhất.
- Dòng 16:
mutate(Item.Type = ifelse(...)): Đổi tên các sản phẩm ngoài top 5 thành “Các sản phẩm khác”. Cộng tổng doanh thu từng nhóm, và sử dụng hàm ifelse để phân loại nhóm sản phẩm khác- Dòng 21:
arrange(desc(TotalRevenue)): Sắp xếp lại theo doanh thu để trình bày đẹp trên biểu đồ. Tính tổng doanh thu tất cả nhóm để làm nhãn chính giữa donut.
1. library(ggplot2)
2. bar_colors <- c("#FFB3BA", "#BAE1FF", "#BFFCC6", "#FFFACD", "#D5BAFF", "#FFDAC1")
3. ggplot(plot_data, aes(x = reorder(Item.Type, -TotalRevenue),
4. y = TotalRevenue, fill = Item.Type)) +
5. geom_col(color = "black", width = 0.7) +
6. scale_fill_manual(values = bar_colors) +
7. # Nhãn số dọc, hiện giữa cột
8. geom_text(
9. aes(label = scales::comma(TotalRevenue, big.mark = ".")),
10. angle = 90, vjust = 0.5, hjust = 1.1, size = 4, color = "black",
11. fontface = "bold") +
12. labs(title = "Doanh thu top 5 sản phẩm ởcác quốc gia Châu Âu",
13. x = NULL,
14. y = "Tổng doanh thu") +
15. scale_y_continuous(labels = scales::comma_format(big.mark = ".")) +
16. theme_minimal(base_size = 13) +
17. theme(
18. axis.text.x = element_blank(),
19. axis.ticks.x = element_blank(),
20. plot.title = element_text(face = "bold", hjust = 0.5))
>Nhận xét: Trước hết, nhóm “Các sản phẩm khác” dẫn
đầu với hơn 8,2 tỷ doanh thu, cho thấy sự đa dạng hóa trong nhu cầu tiêu
dùng của người dân châu Âu. Điều này phản ánh nền kinh tế phát triển với
mức sống cao, nơi người tiêu dùng có xu hướng chi tiêu cho nhiều loại
hàng hóa phục vụ tiện ích và phong cách sống. Các nhóm Household (7,17
tỷ) và Office Supplies (7,10 tỷ) cũng đạt doanh thu cao, cho thấy cơ cấu
kinh tế châu Âu thiên về khu vực dịch vụ và văn phòng. Ngược lại, Meat
(4,53 tỷ) và Cosmetics (4,52 tỷ) có doanh thu trung bình, phản ánh sự ổn
định trong các ngành hàng tiêu dùng truyền thống, nhưng không còn tốc độ
tăng trưởng cao do thị trường đã bão hòa. Baby Food (2,70 tỷ) có doanh
thu thấp nhất, có thể lý giải bằng yếu tố tỷ lệ sinh thấp tại Châu Âu,
dẫn đến nhu cầu cho sản phẩm trẻ em giảm dần.
Giải thích:
- Dòng 1: Đặt một bảng màu pastel cố định cho từng nhóm sản phẩm trong biểu đồ.
- Dòng 3: Khởi tạo biểu đồ . Dòng 5: Vẽ các cột đứng có viền màu đen rõ nét, mỗi cột thể hiện tổng doanh thu một nhóm,
- Dòng 6: scale_fill_manual(): Gán màu pastel cho từng cột dựa
- Dòng 8: geom_text(): Đặt nhãn số doanh thu in dọc theo cột (angle = 90) và căn giữa các số được phân cách hang nghìn.
- labs(): Thiết lập tiêu đề chính, phụ, loại bỏ tiêu đề trục x và trục y.
- theme_minimal(base_size = 16) và theme(): Tạo giao diện cho biểu đồ
1. ggplot(Sales, aes(x = `Total.Profit`)) +
2. geom_histogram(bins = 30, fill = "#56B4E9", color = "white", alpha = 0.8) +
3. geom_vline(aes(xintercept = mean(`Total.Profit`, na.rm = TRUE)),
4. color = "red", linewidth = 1) +
5. geom_text(aes(x = mean(`Total.Profit`, na.rm = TRUE), y = 50,
6. label = paste0("Trung bình = ",
7. label_number(big.mark = ".", accuracy = 1)(mean(`Total.Profit`, na.rm = TRUE)))),
8. color = "red", hjust = -0.1,vjust = -25, size = 3.8) +
9. scale_x_continuous(labels = label_number(big.mark = ".", accuracy = 1)) +
10. scale_y_continuous(labels = label_number(big.mark = ".", accuracy = 1))+
11. labs(title = "Phân bổ tổng lợi nhuận",
12. x = "Lợi nhuận",
13. y = "Tần suất") +
14. theme_minimal(base_size = 13) +
15. theme(panel.grid.minor = element_blank())
Nhận xét: Biểu đồ thể hiện tổng doanh thu trong bộ dữ liệu Sales xuất hiện bao nhiêu lần. Ta dễ thấy với lợi nhuận từ 0 đến trên mức trung bình là 394.091 thì tần suất xuất hiện trên 5.000 cho thấy mức độ tập trung lợi nhuận của toàn thế giới ở mức đó. Càng về sau, đặc biệt là khoảng lợi nhuận 1.500.000 thì mức phân bố rất ít, hầu như chỉ có những quốc gia tiềm lực thì sẽ mang lại mức lợi nhuận lớnlớn
Giải thích:
- Dòng 1: khởi tạo biểu đồ
- Dòng 2: vẽ cột histogram của mức phân bổ lợi nhuận.
- Dòng 3: vẽ đường thẳng đứng trên đồ thị cho thấy giá trị trung bình
- Dòng 5: Thêm nhãn trung bình trên đồ thị.
- Dòng 9 và dòng 10: Định dạng số có phân cách hàng nghìn.
labs(): Đặt tiêu đề và nhãn trên biểu đồ,theme_minimal()vàtheme(): Tạo giao diện cho biểu đồ.
1. region_channel <- Sales %>%
2. group_by(Region, Sales.Channel) %>%
3. summarise(rev = sum(Total.Profit), .groups = "drop")
4. region_channel <- head(region_channel[order(-region_channel$rev),],6)
5. ggplot(region_channel, aes(x = Region, y = rev, fill = Sales.Channel)) +
6. geom_col(position = "stack", color = "black", linewidth = 0.15) +
7. geom_hline(yintercept = 0, color = "gray40", linetype = "dashed") +
8. geom_text(aes(label = scales::comma(rev, big.mark = ".", decimal.mark = ",")),
9. position = position_stack(vjust = 0.5), size = 3, color = "white") +
10. scale_fill_brewer(palette = "Set2") +
11.
12. labs(
13. title = "Top Lợi nhuận theo vùng và kênh bán hàng mạnh nhất",
14. y = "Tổng doanh thu",
15. x = "Khu vực",
16. fill = "Kênh Bán Hàng"
17. ) +
18. scale_y_continuous(labels = label_number(big.mark = ".")) +
19. theme_minimal(base_size = 12)
Nhận xét: Số liệu cho thấy khu vực có doanh thu cao nhất là Europe và Sub-Saharan Africa, mỗi khu vực đạt xấp xỉ trên 34 tỷ, trong đó doanh thu kênh Offline luôn chiếm tỷ trọng lớn hơn Online. Ở khu vực Asia, tổng doanh thu đạt khoảng 19 tỷ, thấp hơn một nửa hai khu vực đứng đầu, doanh thu kênh Online và Offline chênh lệch không nhiều, nhưng Offline vẫn cao hơn so với Online. Đây là dấu hiệu việc tiêu thụ qua kênh truyền thống vẫn là động lực chính cho tăng trưởng ở mọi khu vực lớn.
Giải thích: •
- Dòng 1: Tạo bảng region_channel để tính tổng lợi nhuận theo vùng
- Dòng 5: Khởi tạo biểu đồ. Dòng 6, 7, 8: Vẽ biểu đồ cột chồng, them nhãn trên biểu đồ
- Dòng 17: Phân cách hang nghìn
- Labs() + theme_minimal(): Tạo nhãn và giao diện cho biểu đồ
1. donut_df <- Sales %>%
2. group_by(Region) %>%
3. summarise(Revenue = sum(`Total.Revenue`, na.rm = TRUE)) %>%
4. arrange(desc(Revenue)) %>%
5. mutate(
6. fraction = Revenue / sum(Revenue),
7. ymax = cumsum(Revenue),
8. ymin = lag(ymax, default = 0),
9. label_pos = (ymin + ymax) / 2,
10. percent_label = paste0(round(fraction * 100, 1), "%"))
11. total_revenue <- sum(donut_df$Revenue)
12. # Vẽ biểu đồ Donut
13. ggplot(donut_df) +
14. geom_rect(aes(ymin = ymin, ymax = ymax, xmin = 1, xmax = 2, fill = Region),
15. color = "white", linewidth = 0.8, alpha = 0.95) +
16. geom_rect(aes(ymin = ymin, ymax = ymax, xmin = 2.0, xmax = 2.05, fill = Region),
17. alpha = 0.3, color = NA) +
18. annotate("rect", xmin = 0.5, xmax = 1.5,
19. ymin = 0, ymax = sum(donut_df$Revenue),
20. fill = "white", color = NA) +
21. annotate("text",
22. x = 1,
23. y = sum(donut_df$Revenue) / 2,
24. label = paste0("Tổng: ", comma(sum(donut_df$Revenue), accuracy = 1)),
25. size = 4.5,
26. fontface = "bold",
27. color = "#379683",
28. hjust = 0.5, vjust = -3) +
29. geom_text(aes(x = 2.1, y = label_pos, label = percent_label), size = 4,
30. fontface = "bold", color = "black", hjust = 0.6, lineheight = 1.1)+
31. scale_fill_viridis_d(option = "C", begin = 0.1, end = 0.9, direction = 1) +
32. coord_polar(theta = "y") + # thiết lập hệ tọa độ tròn (donut)
33. labs(
34. title = "Thị phần doanh thu theo khu vực",
35. fill = "Khu vực",
36. caption = "Nguồn: Bộ dữ liệu Sales") +
37. theme_void() +
38. theme(
39. plot.title = element_text(size = 16, face = "bold", hjust = 0.5),
40. plot.subtitle = element_text(size = 11, hjust = 0.5, color = "gray40"),
41. plot.caption = element_text(size = 9, color = "gray50", hjust = 1),
42. legend.position = "right", # 🎯 Đưa chú thích ra ngoài
43. legend.title = element_text(size = 10, face = "bold"),
44. legend.text = element_text(size = 9),
45. panel.background = element_rect(fill = "white", color = NA))
Nhận xét: Biểu đồ donut thể hiện rõ thị phần doanh thu theo từng khu vực, trên tổng doanh thu toàn cầu là 133,606,673,066. Dẫn đầu là khu vực Sub-Saharan Africa với doanh thu hơn 34.9 tỷ, chiếm 26.2% tổng doanh thu. Europe đứng kế tiếp, doanh thu hơn 34.2 tỷ, chiếm 25.6%. Asia đạt gần 19.3 tỷ doanh thu với tỷ lệ 14.4%. Nhìn vào thị phần, hai khu vực Sub-Saharan Africa và Europe chiếm tổng cộng hơn 51% thị trường doanh thu toàn cầu, cho thấy độ tập trung rất cao tại hai khu vực này. Trong khi đó, các khu vực khác đều dưới 15% thị phần, Bắc Mỹ là khu vực nhỏ nhất với tỷ trọng chỉ 2.2%. Kết quả này cho thấy doanh nghiệp muốn tối ưu hóa nguồn lực hoặc lựa chọn thị trường trọng điểm nên ưu tiên đầu tư vào Sub-Saharan Africa và Europe.
Giải thích:
- Dòng 1:
donut_df: Tính tổng doanh thu theo khu vực,mutate(): tạo thêm cột mới gồm min, max, tỷ lệ phần trăm.label_pos: vị trí trung tâm mỗi lát donut, dùng để đặt nhãn phần trăm.percent_label: định dạng phần trăm thành chuỗi- Dòng 14: khởi tạo biểu đồ
- Dòng 15 và dòng 17:
geom_rect()vẽ hình chữ nhật, nhưng sử dụngcoord_polar(theta="y")nó trở thành lát tròn và tạo hiệu ứng ánh sáng và viền ngoài cho hònh tròn.- Dòng 19:
annotate("rect"...): Vẽ một hình chữ nhật màu trắng ở giữa để tạo lỗ rỗng, biến hình tròn bình thường thành donut.- Dòng 20:
annotate("text"): ghi tổtổng doanh thu ở giữa- Dòng 30:
geom_text()ghi phần trăm trên biểu đồ.- Dòng 31:
scale_fill_viridis_d(): Tô màu cho biểu đồ.- Dòng 32:
coord_polar(theta = "y"): Chuyển hệ tọa độ từ chữ nhật thành hình tròn.labs(),theme_voidvàtheme(): Tạo tiêu đề, nhãn và giao diện cho biểu đồ
1. sales_2015_online <- Sales[Sales$Sales.Channel == "Online" & Sales$Year == "2015", ]
2. top10_countries <- sales_2015_online %>%
3. group_by(Country) %>%
4. summarise(TotalRevenue = sum(Total.Revenue)) %>%
5. arrange(desc(TotalRevenue)) %>%
6. slice_head(n = 10)
7. top10_countries <- top10_countries %>%
8. mutate(Top3 = ifelse(row_number() <= 3, "Top 3", "Others"))
Nhận xét: Tạo một bảng dữ liệu mới với điều kiện là Kênh bán hàng Online và chỉ có năm 2015, sau đó lọc top 10 đất nước có tổng doanh thu lớn nhất và dùng arrange(desc()) để sắp xếp theo thứ tự giảm dần và dùng slice_head() để cắp bộ dữ liệu chỉ bao gồm top 10 đất nước. Sau đó thêm 1 cột và dùng hàm ifelse với 3 đất nước đầu thì trả về “Top 3”, còn lại thì “Others”, việc này giúp phân định rõ ràng khi vẽ biểu đồ, giúp biểu đồ bắt mắt hơn.
1. ggplot(top10_countries, aes(x = reorder(Country, TotalRevenue), y = TotalRevenue)) +
2. geom_bar(aes(y = max(TotalRevenue)), stat = "identity", fill = "gray90") +
3. geom_bar(stat = "identity", aes(fill = TotalRevenue)) +
4. scale_fill_gradient(low = "lightblue", high = "steelblue") +
5. geom_bar(
6. stat = "identity",
7. data = subset(top10_countries, Top3=="Top 3"),
8. aes(fill = TotalRevenue),
9. color = "gold",
10. linewidth = 1.2 ) +
11. geom_text(aes(label = label_number(big.mark = ".", accuracy = 1)(TotalRevenue))
12. , hjust = 1, size = 3.5) +
13. geom_hline(yintercept = mean(top10_countries$TotalRevenue),
14. linetype = "dashed", color = "red", linewidth = 0.8) +
15. scale_y_continuous(labels = label_number(big.mark = ".")) +
16. coord_flip() +
17. labs(
18. title = "Top 10 Quốc gia bán hàng Online năm 2015 ",
19. x = "Quốc gia",
20. y = "Tổng doanh thu",
21. fill = "Total Revenue") +
22. theme_minimal() +
23. theme(
24. legend.position = "right",
25. plot.title = element_text(face = "bold", size = 17))
Nhận xét: Biểu đồ này cho thấy trong năm 2015, top 10 quốc gia có tổng doanh thu bán hàng online cao nhất có sự chênh lệch rõ rệt giữa các vị trí đầu bảng và các quốc gia còn lại. Senegal dẫn đầu với doanh thu lớn nhất là khoảng 95 triệu, tiếp đến là Portugal và Slovakia, cả hai quốc gia này đều có tổng doanh thu vượt ngưỡng 75 triệu như thể hiện bởi cột vượt qua vạch đỏ trên biểu đồ. Từ vị trí thứ tư trở đi, doanh thu bắt đầu giảm dần, với các quốc gia như Iceland, Australia, Kosovo, Burundi, Maldives, Bulgaria và Malta lần lượt chiếm các vị trí còn lại trong top 10. Điều này cho thấy ngoài nhóm dẫn đầu thì phần lớn các quốc gia đều có doanh thu online xấp xỉ hoặc thấp hơn mức trung bình của nhóm top, phản ánh mức độ tập trung doanh thu khá cao vào một số ít thị trường chủ lực.
Giải thích:
- Dòng 1: Khởi tạo ggplot
- Dòng 2: geom_bar(): thể hiện tổng doanh thu tối đa, làm tham chiếu so sánh, sử dụng gradient màu từ nhạt đến đậm để trực quan hóa mức độ doanh thu.
- Dòng 3: hiển thị tổng doanh thu dạng số, hỗ trợ đọc trực quan mà không cần nhìn trục Y.
- Dòng 13: geom_hline(): Vẽ đường trung bình doanh thucủa top 10,
- Sử dụng scale_fill_gradient() cho gradient màu liên tục, scales::comma() để định dạng số, theme_minimal() làm biểu đồ gọn gàng.
1. library(readxl)
2. file = ("D:/hsg.xlsx")
3. HSG <- read_excel(path = file)
4. colnames(HSG) <- c("nam","Phai tra nguoi ban ngan han","chi phi phai tra ngan han",
5. "vay va no thue tai chinh","von co phan", "LNSTCPP","tien",
6. "Cac khoan tuong duong tien", "cac khoan phai thu ngan han",
7. "TSCD","cac khoan phai thu dai han", "luu chuyen tien thuan",
8. " tien thu di vay","doanh thu ban hang", "gia von",
9. "loi nhuan gop","chi phi ban hang",
10. "chi phi qly doanh nghiệp", "loi nhuan thuan")
1. names(HSG)
## [1] "nam" "Phai tra nguoi ban ngan han"
## [3] "chi phi phai tra ngan han" "vay va no thue tai chinh"
## [5] "von co phan" "LNSTCPP"
## [7] "tien" "Cac khoan tuong duong tien"
## [9] "cac khoan phai thu ngan han" "TSCD"
## [11] "cac khoan phai thu dai han" "luu chuyen tien thuan"
## [13] " tien thu di vay" "doanh thu ban hang"
## [15] "gia von" "loi nhuan gop"
## [17] "chi phi ban hang" "chi phi qly doanh nghiệp"
## [19] "loi nhuan thuan"
Giải thích: Lệnh
names()dùng hiện tên của các biến.
1. str(HSG)
## tibble [10 × 19] (S3: tbl_df/tbl/data.frame)
## $ nam : num [1:10] 2015 2016 2017 2018 2019 ...
## $ Phai tra nguoi ban ngan han: num [1:10] 555161842884 1501886154837 3415707867150 1111659624255 1370637850790 ...
## $ chi phi phai tra ngan han : num [1:10] 81556360439 187888512542 62825939966 117856182101 92362758133 ...
## $ vay va no thue tai chinh : num [1:10] 4400210324546 4102697779164 7402317620460 9010977033379 5706275512506 ...
## $ von co phan : num [1:10] 1007907900000 1965398290000 3499966830000 3849903280000 4234694890000 ...
## $ LNSTCPP : num [1:10] 1531127724105 1753131906267 1618854251238 1323418124868 1539503023643 ...
## $ tien : num [1:10] 276553474303 292227797476 576477183208 171516367114 222120606665 ...
## $ Cac khoan tuong duong tien : num [1:10] 140000000 143521875 143521875 143521875 143521875 ...
## $ cac khoan phai thu ngan han: num [1:10] 755197646602 1827514998306 1097734614933 7860565817787 5167377333616 ...
## $ TSCD : num [1:10] 3403033912877 6396829534741 4010721553262 1591695704971 1441875639868 ...
## $ cac khoan phai thu dai han : num [1:10] 25000000000 1458000000 28470549901 268984943607 292077985517 ...
## $ luu chuyen tien thuan : num [1:10] 1280225410487 1641219255869 -2173431969202 499984886725 5181076080821 ...
## $ tien thu di vay : num [1:10] 13314828925538 12715960175942 27410327886870 33719297189430 20572520273479 ...
## $ doanh thu ban hang : num [1:10] 17469894530725 18006498541322 26336984183123 34570344557164 28081303783088 ...
## $ gia von : num [1:10] -14869355353248 -13717393786963 -21730791206018 -30464290088385 24836155036672 ...
## $ loi nhuan gop : num [1:10] 2577516224574 4176321693990 4418253629261 3977139259876 3198620082003 ...
## $ chi phi ban hang : num [1:10] -864210788876 -1139602275640 -1512517323076 -1816042397184 1748882841240 ...
## $ chi phi qly doanh nghiệp : num [1:10] -511797744891 -900715660782 -801479758048 -895579880506 470700688884 ...
## $ loi nhuan thuan : num [1:10] 808446738155 1918748102484 1568992697472 474797169857 239566040636 ...
Nhận xét: bộ dữ liệu gồm 10 quan sát và 19 biến, cả 19 biến đều hiển thị dưới dạng số là numeric
Giải thích:
str(Sales): hiện thông tin chi tiết, gồm số dòng, số cột, tên từng trường, kiểu dữ liệu, một vài mẫu giá trị.
- Kết quả giúp xác định biến số, biến chữ, biến ngày tháng để chọn thao tác phù hợp cho phân tích về sau.
1. dim(HSG)
## [1] 10 19
Nhận xét: Kết quả cho thấy bộ dữ liệu gồm 10 dòng và 19 biến.
Giải thích:
dim(Sales): hiển thị dạng (số dòng, số cột). Ví dụ (100.000, 14).
- Sử dụng thông tin này để hình dung quy mô dataset, kiểm tra thiếu/gỡ lỗi khi nhập file.
Giải thích:
summary(HSG[[" "]]): Tạo ra bảng tóm tắt thống kê cho biến chứa các giá trị như: Min (giá trị nhỏ nhất), 1st Qu. (phân vị thứ nhất – tứ phân vị thứ nhất), Median (Trung vị), Mean (Giá trị trung bình), 3rd Qu. (tứ phân vị thứ ba), Max (giá trị lớn nhất).format(..., big.mark = ".", decimal.mark = ","): Định dạng lại các kết quả thống kê vừa tính, sử dụng dấu chấm “.” để phân cách hàng nghìn và dấu phẩy “,” cho phần thập phân, phù hợp với quy chuẩn số ở Việt Nam.
1. format(summary(HSG[["tien"]]), big.mark = ".", decimal.mark = ",")
## Min. 1st Qu. Median Mean
## "171.516.367.114" "250.687.476.019" "348.747.468.446" "376.374.876.074"
## 3rd Qu. Max.
## "495.339.485.898" "597.436.771.510"
Nhận xét: Dòng tiền của Hoa Sen group đi chủ yếu là từ khoảng 250 tỷ đến 495 tỷ hơn, cho thấy khối lượng tiền trong doanh nghiệp đủ lớn.Nhìn chung, tiền mặt có xu hướng tăng theo thời gian, tuy nhiên vẫn tồn tại một số năm thấp hơn, cần chú ý đến quản lý dòng tiền và rủi ro thanh khoản.
1. format(summary(HSG[["vay va no thue tai chinh"]]), big.mark = ".", decimal.mark = ",")
## Min. 1st Qu. Median Mean
## "2.936.344.523.958" "4.177.075.915.510" "4.918.998.936.304" "5.230.646.227.048"
## 3rd Qu. Max.
## "5.620.727.747.666" "9.010.977.033.379"
Nhận xét: Mức vay và nợ thấp nhất là khoảng 2,94 nghìn tỷ, trong khi mức cao nhất lên tới 9 nghìn tỷ, cho thấy biến động rất lớn trong 10 năm qua. Giá trị trung bình khoảng 5,23 nghìn tỷ, cao hơn giá trị trung vị 4,92 nghìn tỷ, chứng tỏ dữ liệu lệch phải, tức một số năm nợ tăng đột biến kéo trung bình lên. Khoảng giữa 1st Qu. (4,18 nghìn tỷ) và 3rd Qu. (5,62 nghìn tỷ) cũng khá rộng, cho thấy sự phân tán đáng kể trong các năm, nghĩa là mức nợ không đồng đều và có sự biến động theo từng kỳ.
1. format(summary(HSG[["von co phan"]]), big.mark = ".", decimal.mark = ",")
## Min. 1st Qu. Median Mean
## "1.007.907.900.000" "3.587.450.942.500" "4.340.473.510.000" "4.223.913.832.000"
## 3rd Qu. Max.
## "5.719.117.135.000" "6.159.823.090.000"
Nhận xét: Vốn cổ phần thấp nhất khoảng 1.008 tỷ, trong khi cao nhất là 6.160 tỷ, cho thấy quy mô vốn cổ phần tăng đáng kể trong 10 năm qua. Giá trị trung bình khoảng 4.224 tỷ, gần bằng giá trị trung vị 4.340 tỷ, chứng tỏ dữ liệu khá cân đối và không có sự lệch quá lớn.cho thấy doanh nghiệp đã huy động thêm vốn từ cổ đông hoặc tăng vốn điều lệ, góp phần tăng cường khả năng tài chính
1. format(summary(HSG[["TSCD"]]), big.mark = ".", decimal.mark = ",")
## Min. 1st Qu. Median Mean
## " 848.743.235.444" "1.047.747.456.742" "1.516.785.672.420" "2.470.562.104.148"
## 3rd Qu. Max.
## "3.786.692.305.506" "6.396.829.534.741"
Nhận xét: Mức thấp nhất là khoảng 849 tỷ, trong khi mức cao nhất lên tới 6.397 tỷ, cho thấy biến động rất lớn trong giá trị tài sản cố định qua các năm. Giá trị trung bình khoảng 2.471 tỷ, cao hơn giá trị trung vị 1.517 tỷ, chứng tỏ dữ liệu lệch phải, nghĩa là có một số năm HSG đầu tư mạnh vào tài sản cố định, kéo trung bình lên cao. Tài sản cố định hữu hình có xu hướng tăng theo thời gian, phản ánh doanh nghiệp mở rộng năng lực sản xuất, đầu tư máy móc, nhà xưởng
1. format(summary(HSG[["doanh thu ban hang"]]), big.mark = ".", decimal.mark = ",")
## Min. 1st Qu. Median
## "17.469.894.530.725" "26.694.027.043.919" "30.082.800.738.072"
## Mean 3rd Qu. Max.
## "32.327.475.286.297" "38.554.689.827.340" "50.090.135.318.501"
Nhận xét: Mức thấp nhất là khoảng 17.470 tỷ, trong khi mức cao nhất đạt tới 50.090 tỷ, cho thấy doanh thu biến động đáng kể trong 10 năm qua. Giá trị trung bình khoảng 32.327 tỷ, cao hơn giá trị trung vị 30.083 tỷ, chứng tỏ doanh thu lệch phải, tức có một vài năm doanh thu tăng đột biến kéo trung bình lên.Nhìn chung, doanh thu có xu hướng tăng theo thời gian, phản ánh HSG đang mở rộng hoạt động kinh doanh, tăng thị phần hoặc nâng cao hiệu quả bán hàng
1. format(summary(HSG[["gia von"]]), big.mark = ".", decimal.mark = ",")
## Min. 1st Qu. Median
## "-35.008.227.341.981" "-26.875.211.951.759" "-14.293.374.570.106"
## Mean 3rd Qu. Max.
## " -1.201.537.059.904" " 24.352.986.818.860" " 44.771.944.789.711"
Nhận xét: Mức thấp nhất là khoảng -35.008 tỷ, trong khi mức cao nhất lên tới 44.772 tỷ, cho thấy biến động cực kỳ lớn trong giá vốn qua các năm. Giá trị trung bình khoảng -1.202 tỷ, thấp hơn giá trị trung vị -14.293 tỷ, chứng tỏ dữ liệu lệch phải rất mạnh. hoảng giữa 1st Qu. (-26.875 tỷ) và 3rd Qu. (24.353 tỷ) cực kỳ rộng, thể hiện sự phân tán phi thường, có năm chi phí vượt trội hoặc được điều chỉnh kế toán. Bên cạnh đó cũng cho thấy cho thấy có những năm chi phí thực tế cao, nhưng cũng có những năm điều chỉnh kế toán lớn, ảnh hưởng tới biên lợi nhuận gộp.
1. format(summary(HSG[["loi nhuan thuan"]]), big.mark = ".", decimal.mark = ",")
## Min. 1st Qu. Median Mean
## " 96.130.196.549" " 366.015.397.238" " 659.530.295.552" "1.224.336.041.006"
## 3rd Qu. Max.
## "1.521.476.626.436" "4.917.382.392.261"
Nhận xét: Trong 10 năm qua, lợi nhuận thuần dao động từ khoảng 96 tỷ đến 4.917 tỷ, cho thấy biến động rất lớn giữa các năm. Giá trị trung bình khoảng 1.224 tỷ, cao hơn giá trị trung vị 660 tỷ, chứng tỏ dữ liệu lệch phải, tức có một vài năm lợi nhuận rất cao kéo trung bình lên. Khoảng giữa 1st Qu. (366 tỷ) và 3rd Qu. (1.521 tỷ) khá rộng, phản ánh sự phân tán đáng kể trong lợi nhuận qua các năm. Nhìn chung, HSG có khả năng tạo lợi nhuận thuần dương từ hoạt động kinh doanh, đồng thời có những năm lợi nhuận tăng mạnh, phản ánh hiệu quả kinh doanh tốt nhờ doanh thu tăng, chi phí được kiểm soát và quản lý dòng tiền hợp lý.
1. sapply(HSG,function(HSG) sum(is.na(HSG)))
## nam Phai tra nguoi ban ngan han
## 0 0
## chi phi phai tra ngan han vay va no thue tai chinh
## 0 0
## von co phan LNSTCPP
## 0 0
## tien Cac khoan tuong duong tien
## 0 0
## cac khoan phai thu ngan han TSCD
## 0 0
## cac khoan phai thu dai han luu chuyen tien thuan
## 0 0
## tien thu di vay doanh thu ban hang
## 0 0
## gia von loi nhuan gop
## 0 0
## chi phi ban hang chi phi qly doanh nghiệp
## 0 0
## loi nhuan thuan
## 0
Nhận xét: Kết quả kiểm tra trả về toàn bộ giá trị bằng 0, nghĩa là không có bất kỳ giá trị thiếu nào trong 19 cột dữ liệu .Đây là một kết quả tốt vì dữ liệu đầy đủ, không bị NA .Điều này có nghĩa là không cần áp dụng thêm bất kỳ phương pháp xử lý bổ sung khác. Nhờ đó, các phân tích tiếp theo như tính tổng doanh thu, lợi nhuận hay vẽ biểu đồ đều đảm bảo chính xác và đáng tin cậy, không bị ảnh hưởng bởi lỗi thiếu dữ liệu.
Giải thích:
sapply(...): áp dụng kiểm tra cho từng cột trong bảng HSG , trả về một số cho mỗi cột.sum(is.na(HSG)): đếm tổng số giá trị bị thiếu trong mỗi cột, các giá trị thiếu được hàm is.na trả về TRUE (TRUE được tính là 1, FALSE là 0).
1. HSG[duplicated(HSG),]
Nhận xét:Kết quả hiển thị là một bảng rỗng (# A tibble: 0 x 19), nghĩa là không có dòng dữ liệu nào bị trùng lặp. Kết quả này rất tốt vì đảm bảo các phép tính tổng hợp như doanh thu hoặc lợi nhuận không bị sai lệch do dữ liệu trùng. Dữ liệu có độ tin cậy cao và phản ánh đúng thực tế
Giải thích:
duplicated(HSG): kiểm tra từng dòng của bảng, trả về TRUE nếu dòng này trùng hoàn toàn với dòng phía trước.HSG[duplicated(HSG),]: gọi ra các dòng trùng, nếu bảng kết quả rỗng thì dữ liệu không bị lặp lại, tuyệt đối duy nhất.
1. scale <- function(x){
2. if (!is.numeric(x)) {
3. message("Cot khong phai dang so. Khong the chuan hoa.")
4. return(NULL)}
5.
6. # Neu tat ca gia tri giong nhau
7. if (max(x) == min(x)) {
8. message("Tat ca gia tri giong nhau. Tra ve toan 0.")
9. return(rep(0, length(x)))}
10.
11. # Chuan hoa ve khoang [0, 1]
12. scaled <- (x - min(x)) / (max(x) - min(x))
13. return(scaled)}
Nhận xét: Tạo một function mới, nếu kết quả đầu vô không phải là số, thì sẽ đưa ra một thông điệp để cảnh báo. Nếu là số thì sẽ áp dụng công thức để chuẩn hóa. Việc chuẩn hóa giúp đưa các biến về cùng thang đo [0,1], thuận tiện khi so sánh hoặc vẽ biểu đồ. Đây là bước cần thiết trong các phân tích thống kê hoặc mô hình hóa vì nó giúp loại bỏ sự khác biệt về đơn vị đo lường giữa các biến.
Giải thích:
scale <- function(x){ ... }: Định nghĩa một hàm tên là scale, nhận đối số là biến x (có thể là một vector).if (!is.numeric(x)) { ... }: Kiểm tra nếu x không phải là kiểu số (numeric), thì: message(“Cot khong phai dang so. Khong the chuan hoa.”): Thông báo trên màn hình rằng cột không phải dạng số.return(NULL): Trả về giá trị rỗng, kết thúc hàm (không báo lỗi).if (max(x) == min(x)) { ... }: Kiểm tra nếu tất cả giá trị trong x đều giống nhau (giá trị lớn nhất bằng giá trị nhỏ nhất):message("Tat ca gia tri giong nhau. Tra ve toan 0."): Thông báo trên màn hình.return(rep(0, length(x))): Trả về một vector toàn giá trị 0, độ dài bằng độ dài của x.scaled <- (x - min(x)) / (max(x) - min(x)): Đây là công thức chuẩn hóa min-max, đưa mọi giá trị về khoảng từ 0 đến 1. Từng phần tử sẽ lấy giá trị trừ giá trị nhỏ nhất rồi chia cho hiệu số lớn nhất - nhỏ nhấtreturn(scaled): Trả về vector đã chuẩn hóa.
1. Tien <- as.data.frame(scale(HSG[["tien"]]))
2. colnames(Tien) <- c("scale.Tien")
3. print(head(Tien))
## scale.Tien
## 1 0.2466121
## 2 0.2834131
## 3 0.9507899
## 4 0.0000000
## 5 0.1188115
## 6 0.7229768
Giải thích:
ggplot(HSG, aes(y = HSG[[" ab "]])): Tạo đối tượng ggplot, lấy dữ liệu từ bảng HSG, trục tung là giá trị “ab”
geom_boxplot(fill = "lightblue"): Vẽ boxplot với màu nền xanh nhạt cho hộp.
scale_y_continuous(labels = scales::comma_format(big.mark = ".", decimal.mark = ",")): Thiết lập cách hiển thị nhãn trục y, dùng hàm comma_format của package scales, quy định dấu phân cách hàng nghìn là “.” và dấu thập phân là “,”.
labs(title = "Boxplot ab", y = "Tiền (VNĐ)": Ghi tiêu đề cho biểu đồ và đặt tên trục y.
theme_minimal(): Áp dụng theme tối giản cho biểu đồ, tránh rối mắt.
1. library(ggplot2)
2. library(scales)
3. ggplot(HSG, aes(y = HSG[["tien"]])) +
4. geom_boxplot(fill = "lightblue") +
5. scale_y_continuous(labels = scales::comma_format(big.mark = ".", decimal.mark = ",")) +
6. labs(title = "Boxplot Tiền", y = "VNĐ") +
7. theme_minimal()
Nhận xét: Biểu đồ boxplot được vẽ bằng ggplot() đã tùy chỉnh định dạng số liệu với dấu thập phân phân cách rõ ràng, không xuất hiện điểm bất thường (outlier), cho thấy các giá tiền nằm trong phạm vi hợp lý và không có số liệu nào quá xa trung bình. Khoảng giữa tứ phân vị thứ nhất và tứ phân vị thứ ba khá rộng, dao động từ khoảng 250 tỷ đến gần 500 tỷ đồng, phản ánh mức biến động tiền mặt thay đổi giữa các năm. Nhìn chung, HSG duy trì được nguồn tiền ổn định, hợp lý, cho thấy quản lý tài chính an toàn và hiệu quả.
1. ggplot(HSG, aes(y = HSG[["vay va no thue tai chinh"]])) +
2. geom_boxplot(fill = "lightblue") +
3. scale_y_continuous(labels = scales::comma_format(big.mark = ".", decimal.mark = ",")) +
4. labs(title = "Boxplot Vay và nợ thuê tài chính ngắn hạn", y = "VNĐ") +
5. theme_minimal()
>Nhận xét: Biểu đồ boxplot vay và nợ thuê tài chính
ngắn hạn được vẽ bằng ggplot() với định dạng số liệu có dấu thập phân rõ
ràng. Dữ liệu có mức ổn định và tính tập trung khá tốt, tuy nhiên xuất
hiện một điểm ngoại lai (outlier) phía trên, cho thấy có một kỳ phát
sinh khoản vay hoặc nợ thuê tài chính cao bất thường so với các năm còn
lại. Khoảng giữa tứ phân vị thứ nhất và tứ phân vị thứ ba tương đối
rộng, dao động từ khoảng 4.000 tỷ đến hơn 6.000 tỷ, phản ánh sự biến
động nhất định nhưng vẫn kiểm soát được.
1. ggplot(HSG, aes(y = HSG[["von co phan"]])) +
2. geom_boxplot(fill = "lightblue") +
3. scale_y_continuous(labels = scales::comma_format(big.mark = ".", decimal.mark = ",")) +
4. labs(title = "Boxplot vốn cổ phần", y = "VNĐ") +
5. theme_minimal()
Nhận xét: Biểu đồ boxplot vốn cổ phần được vẽ bằng ggplot() với phân cách dấu thập phân rõ ràng. Các giá trị chủ yếu tập trung trong khoảng giữa tứ phân vị thứ nhất và thứ ba , từ khoảng 3.500 tỷ đến gần 6.000 tỷ đồng, cho thấy mức vốn cổ phần ổn định qua các thời kỳ. Không xuất hiện điểm ngoại lai, phản ánh HSG duy trì nguồn vốn cổ phần ổn định, vững chắc và không có biến động đột biến về mặt vốn góp.
1. ggplot(HSG, aes(y = HSG[["TSCD"]])) +
2. geom_boxplot(fill = "lightblue") +
3. scale_y_continuous(labels = scales::comma_format(big.mark = ".")) +
4. labs(title = "Boxplot tài sản cố định hữu hình", y = "Tiền (VNĐ)") +
5. theme_minimal()
Nhận xét:Biểu đồ boxplot tài sản cố định hữu hình được vẽ bởi ggplot() và sử dụng phân cách dấu thập phân. Dữ liệu phân bố khá rộng, với khoảng giữa tứ phân vị thứ nhất và tứ phân vị thứ ba dao động từ khoảng 1.000 tỷ đến gần 4.000 tỷ đồng, phản ánh sự biến động nhất định về tài sản cố định qua các năm. Không xuất hiện điểm ngoại lai, cho thấy các giá trị đều nằm trong phạm vi hợp lý và không có sự đột biến bất thường về mặt đầu tư tài sản cố định.
1. ggplot(HSG, aes(y = HSG[["luu chuyen tien thuan"]])) +
2. geom_boxplot(fill = "lightblue") +
3. scale_y_continuous(labels = scales::comma_format(big.mark = ".", decimal.mark = ",")) +
4. labs(title = "Boxplot lưu chuyển tiền thuần từ HĐKD", y = "VNĐ") +
5. theme_minimal()
Nhận xét:Biểu đồ boxplot Lưu chuyển tiền thuần từ hoạt động kinh doanh sử dụng ggplot() với dấu thập phân hiển thị. Dữ liệu phân bố tập trung, tuy nhiên tồn tại một số điểm ngoại lai ở cả phía trên và phía dưới, phản ánh có những năm doanh nghiệp ghi nhận dòng tiền kinh doanh tăng vọt hoặc âm bất thường. Khoảng giữa tứ phân vị thứ nhất và tứ phân vị thứ ba khá hẹp, chủ yếu dao động quanh mốc gần 1.000 tỷ đồng đến 2.000 tỷ đồng, cho thấy dòng tiền thuần từ kinh doanh chủ yếu ổn định qua các năm.
1. ggplot(HSG, aes(y = HSG[["doanh thu ban hang"]])) +
2. geom_boxplot(fill = "lightblue") +
3. scale_y_continuous(labels = scales::comma_format(big.mark = ".", decimal.mark = ",")) +
4. labs(title = "Boxplot Doanh thu bán hàng và cung cấp dịch vụ", y = "VNĐ") +
5. theme_minimal()
Nhận xét: Biểu đồ boxplot ddoanh thu bán hàng và cung cấp dịch vụ sử dụng ggplot() với định dạng dấu phân cách rõ ràng. Dữ liệu phân bố khá rộng, với khoảng giữa tứ phân vị thứ nhất và tứ phân vị thứ ba dao động từ 25.000 tỷ đến gần 40.000 tỷ đồng, phản ánh sự dao động doanh thu lớn giữa các kỳ kinh doanh. Không xuất hiện điểm ngoại lai, thể hiện các mốc doanh thu nằm trong phạm vi hợp lý và không có sự đột biến bất thường. Nhìn chung, doanh nghiệp duy trì được quy mô doanh thu ổn định với biên độ dao động vừa phải, thể hiện năng lực bán hàng, cung cấp dịch vụ bền vững và triển vọng tăng trưởng tích cực.
1. ggplot(HSG, aes(y = HSG[["gia von"]])) +
2. geom_boxplot(fill = "lightblue") +
3. scale_y_continuous(labels = scales::comma_format(big.mark = ".")) +
4. labs(title = "Boxplot giá vốn hàng bán và cung cấp dịch vụ", y = "VNĐ") +
5. theme_minimal()
Nhận xét: Biểu đồ boxplot giá vốn hàng bán và cung cấp dịch vụ với dấu phân cách rõ ràng giúp người xem dễ theo dõi giá trị tuyệt đối. Dữ liệu có sự phân tán rộng, khoảng giữa tứ phân vị thứ nhất và tứ phân vị thứ ba trải dài từ -15.000 tỷ đến hơn 25.000 tỷ đồng, thể hiện biến động lớn về giá vốn giữa các kỳ kinh doanh. Không xuất hiện điểm ngoại lai, cho thấy các giá trị giá vốn đều nằm trong phạm vi hợp lý, không có năm nào ghi nhận chi phí bất thường quá cao hoặc quá thấp so với mặt bằng chung. Nhìn chung, doanh nghiệp duy trì quản lý chi phí giá vốn ổn định, dù còn biến động mạnh phù hợp với quy mô doanh thu từng kỳ.
1. ggplot(HSG, aes(x = "", y = HSG[["loi nhuan thuan"]])) +
2. geom_boxplot(fill = "lightblue") +
3. scale_y_continuous(labels = scales::comma_format(big.mark = ".", decimal.mark = ",")) +
4. labs(title = "Boxplot Lợi nhuận thuần từ hoạt động kinh doanh", y = "Tiền (VNĐ)") +
5. theme_minimal()
Nhận xét: Biểu đồ boxplot lợi nhuận thuần từ hoạt động kinh doanh được vẽ với dấu cách thập phân. Dữ liệu tập trung chủ yếu ở mức dưới 2.000 tỷ đồng, với khoảng giữa tứ phân vị thứ nhất và tứ phân vị thứ ba không quá rộng, cho thấy mức lợi nhuận kinh doanh nhìn chung ổn định qua các năm. Tuy nhiên có xuất hiện một điểm ngoại lai phía trên, cho thấy một kỳ doanh nghiệp ghi nhận lợi nhuận đột biến tăng cao so với mặt bằng chung. Nhìn tổng thể, biên lợi nhuận được duy trì tốt, được kiểm soát ổn định, ngoại trừ năm đặc biệt có lợi nhuận vọt lên mạnh mẽ phản ánh sự thuận lợi bất thường hoặc phát sinh ngoại lệ kinh doanh tích cực.
1. HSG %>%
2. summarise(
3. min_cash = comma_vn(min(tien, na.rm = TRUE)),
4. max_cash = comma_vn(max(tien, na.rm = TRUE)),
5. mean_cash = comma_vn(round(mean(tien, na.rm = TRUE), 0)), #
6. sd_cash = comma_vn(round(sd(tien, na.rm = TRUE), 0)))
Nhận xét: Tiền mặt thấp nhất là 171 tỷ, cao nhất là 597 tỷ, chênh lệch giữa min và max khá lớn khoảng gấp 3 lần, chứng tỏ tiền mặt giữa các quan sát có độ biến động lớn. Trung bình tiền mặt khoảng 376 tỷ, nằm giữa min và max, gần sát giá trị trung bình của khoảng tiền mặt, hợp lý với dữ liệu. Độ lệch chuẩn khoảng 155 tỷ, khá lớn so với trung bình. Điều này xác nhận biến động tiền mặt cao, một số công ty có lượng tiền mặt rất lớn, trong khi một số công ty khác thấp hơn nhiều.
Giải thích: Sử dụng toán tử pipe cho bộ dữ liệu HSG thực hiện các bước tiếp theo.
summarise(): tính các thống kê cơ bản như min, max, trung bình và độ lệch chuẩn.comma_vn(): giúp bộ dữ liệu có phân cách hàng nghìn.
1. HSG %>%
2. filter(`von co phan` > mean(`von co phan`, na.rm = TRUE)) %>%
3. mutate(`von co phan` = comma_vn(`von co phan`)) %>%
4. select(`nam`, `von co phan`)
Nhận xét: Vốn cổ phần là số tiền mà cổ đông đã góp để sở hữu công ty. Khi vốn cổ phần lớn hơn mức trung bình lịch sử, điều này cho thấy công ty tăng vốn, có thể thông qua phát hành cổ phiếu mới hoặc tăng vốn từ cổ đông hiện hữu. Đây là tín hiệu rằng quy mô vốn chủ sở hữu tăng so với quá khứ.
Giải thích:
filter(): lọc các hàng có doanh thu lớn hơn trung bình,mmutate(): chỉnh sửa cột vốn cổ phần thành số có phân cách hàng nghìn,select(): chỉ giữ cột doanh thu ban hang trong kết quả.na.rm = TRUE: bỏ qua các giá trị NA khi tính trung bình.
1. comma_vn(summary(HSG$`doanh thu ban hang`))
## Min. 1st Qu. Median
## "17.469.894.530.725" "26.694.027.043.919" "30.082.800.738.072"
## Mean 3rd Qu. Max.
## "32.327.475.286.297" "38.554.689.827.340" "50.090.135.318.501"
1. HSG$`phan loai doanh thu` <- ifelse(
2. HSG$`doanh thu ban hang` < 26694027043919, "Doanh thu yếu",
3. ifelse(
4. HSG$`doanh thu ban hang` < 38554689827340, "Doanh thu ổn",
5. "Doanh thu tốt"))
6. HSG$`phan loai doanh thu`<- factor( HSG$`phan loai doanh thu`,
7. levels = c("Doanh thu tốt","Doanh thu ổn", "Doanh thu yếu"))
8. table(HSG$`phan loai doanh thu`)
##
## Doanh thu tốt Doanh thu ổn Doanh thu yếu
## 3 4 3
Nhận xét: Dựa vào khoản tứ phân vị, sẽ phân loại doanh thu, nếu nhỏ hơn khoảng tứ phân vị thứ nhất, sẽ là doanh thu yếu, nếu trong khoảng từ tứ phân vị thứ 1 đến thứ 3 thì thì sẽ là doanh thu ổn, còn lại là doanh thu tốt. Việc phân chi như vậy để phân loại được năm nào có doanh thu yếu và có mục tiêu đúng đắn ở các năm tiếp theo. Trong 10 năm thì có 3 năm có mức doanh thu yếu, còn lại thì trên mức trung bình, điều này cho một cái nhìn khách quan lẫn nhà đầu tư và cổ đông.
Giải thích: Sử dụng hàm ifelse để phân loại doanh thu. Dùng hàm factor() để gắn mức độ cho 3 loại doanh thu, doanh thu tốt thì là level 1, tương tự doanh thu ổn là level 2 và doanh thu yếu là level 3. Việc phân chia sẽ giúp thuận tiện trong các thao tác vẽ biểu đồ
1. HSG$`Bien loi nhuan` <- ifelse(
2. HSG$`doanh thu ban hang` != 0,
3. HSG$`loi nhuan thuan` / HSG$`doanh thu ban hang`, 0 )
4. # Tạo cột "Bậc lợi nhuận" dựa trên cột "Biên lợi nhuận"
5. HSG$`bac loi nhuan` <- ifelse(
6. HSG$`Bien loi nhuan` < 0, "Lỗ",
7. ifelse(
8. HSG$`Bien loi nhuan` < 0.03, "Mỏng",
9. ifelse(
10. HSG$`Bien loi nhuan` < 0.08, "Trung bình",
11. ifelse(
12. HSG$`Bien loi nhuan` < 0.15, "Khỏe", "Tuyệt hảo"))))
13. HSG %>%
14. select(`loi nhuan thuan`, `doanh thu ban hang`, `Bien loi nhuan`, `bac loi nhuan`) %>%
15. mutate(across(where(is.numeric), # chỉ áp dụng với cột dạng số
16. ~ comma(., big.mark = ".", decimal.mark = ",")))
Nhận xét: Biên lợi nhuận là để tính bao nhiêu đồng doanh thu bán hàng thì tạo ra 1 đồng lợi nhuận. Tại mức đầu tiên tương ứng với năm 2015, doanh thu bán hàng khoảng 17.5 nghìn tỷ đồng và lợi nhuận thuần khoảng 808 tỷ đồng tức là cứ 1 đồng lợi nhuận sẽ được tạo bởi 4,6% doanh thu. Còn bậc lợi nhuận chủ yếu để phân loại biên lợi nhuận ra làm ba phần, tương ứng với năm 2015 thì có bậc lợi nhuận trên 3% thì sẽ rơi vào mức trung bình.
Giải thích: Đầu tiên dùng hàm
ifelse(), nếu doanh thu khác không thì lấy lợi nhuận thuần chi cho doanh thu, còn nếu là 0 thì gán nó là 0. Tiếp theo vẫn dùng hàmifelse()để tạo thêm cột “bậc lợi nhuận”. Nếu biên lợi nhuận bé hơn 0 thì lỗ, nhỏ hơn 0.3 thì mỏng,nhỏ hơn 0.8 thì trung bình, nhỏ hơn 0.15 thì khỏe, còn lại là tuyệt hảo. Và cuối cùng dùng toán tử pipe từ data frame HSG đểselect()4 ô .muốn hiện thị, câu lệnhcomma()để phân cách hàng nghìn và chữ số thập phân.
1. agg1 <- HSG %>%
2. group_by(nam, `bac loi nhuan`) %>%
3. summarise(von_co_phan= sum(`von co phan`, na.rm = TRUE), .groups = "drop")
4. agg1 %>% mutate(von_co_phan_fmt = comma_vn(von_co_phan)) %>%
5. print()
## # A tibble: 10 × 4
## nam `bac loi nhuan` von_co_phan von_co_phan_fmt
## <dbl> <chr> <dbl> <chr>
## 1 2015 Trung bình 1007907900000 1.007.907.900.000
## 2 2016 Khỏe 1965398290000 1.965.398.290.000
## 3 2017 Trung bình 3499966830000 3.499.966.830.000
## 4 2018 Mỏng 3849903280000 3.849.903.280.000
## 5 2019 Mỏng 4234694890000 4.234.694.890.000
## 6 2020 Trung bình 4446252130000 4.446.252.130.000
## 7 2021 Khỏe 4934818960000 4.934.818.960.000
## 8 2022 Mỏng 5980549860000 5.980.549.860.000
## 9 2023 Mỏng 6159823090000 6.159.823.090.000
## 10 2024 Mỏng 6159823090000 6.159.823.090.000
Nhận xét: Tại năm 2015, vốn cổ phần còn chưa lớn, chỉ đạt khoảng hơn 1.000 tỷ đồng, thuộc bậc lợi nhuận trung bình, lợi nhuận ở mức trung bình cho thấy doanh nghiệp vẫn đang ổn định tài chính, chưa mở rộng quy mô mạnh, và hiệu quả đầu tư ở mức vừa phải. Ở những năm tiếp theo, vốn cổ phần tăng liên tục từ 2.000 tỷ đồng lên 6.000 tỷ đồng, cho thấy donh nghiệp đang dần mở rộng quy mô.
Giải thích: Sử dụng toán tử pipe cho bộ dữ liệu HSG.
group_by()là nhóm bộ dữ liệu lại và tính tổng giá cốn theo các biến đã nhóm, nếu có giá trị NA thì sẽ bỏ qua.comma()là để chỉnh format cho có phân cách hàng nghìn
1. HSG_growth <- HSG %>%
2. arrange(nam) %>%
3. mutate(across(where(is.numeric),
4. ~ (.x / lag(.x) - 1) * 100, .names = "growth_{.col}"))
5. HSG_growth %>%
6. select(nam, `growth_gia von`, `growth_doanh thu ban hang`,
7. `growth_Bien loi nhuan`, `growth_loi nhuan thuan`,
8. `growth_cac khoan phai thu dai han`) %>%
9. mutate(across(where(is.numeric),
10. ~ comma(., big.mark = ".", decimal.mark = ",")))
Nhận xét: tính tốc độ phát triển của năm này so với năm trước, tại năm 2015 không có năm trước nên trả về NA. Tại năm 2016, tốc dộ phát triển giá vốn là -7,747 tức là giảm 7% so với năm trước đó. Tương tự là doanh thu là 3.07, tức là tăng 3.07% so với năm trước đó. Việc này đánh giá được tỷ trọng tăng giảm của từng danh mục để HSG sẽ có những điều chỉnh phù hợp.
Giải thích:
- Dòng 1: Tạo một bảng HSG_growth là phần tram tăng trưởng của mỗi cột
- Dòng 5: Lựa chọn các biến, và phân cách hang nghìn.
1. tuong_quan <- HSG %>%
2. select(where(is.numeric)) %>%
3. cor(use = "pairwise.complete.obs") %>%
4. round(3)
5. tuong_quan <- as.data.frame(tuong_quan)
6. tail(tuong_quan)
Nhận xét: Bảng hệ số tương quan giữa các biến cho thấy được mức độ ảnh hưởng của biến này tới biến kia và ngược lại. Ví dụ: hệ số tương quan của hai biến chi phí bán hàng và tiền là -0.35351 là khi chi phí bán hàng tăng, tiền mặt có xu hướng giảm. Hoặc là lợi nhuận thuần và phải trả người bán ngắn hạn có hệ số tương quan là 0.636, mối quan hệ này khá mạnh, kkhi lợi nhuận thuần tăng, phải trả người bán ngắn hạn cũng có xu hướng tăng.Cho thấy khi doanh nghiệp kiếm nhiều lợi nhuận hơn, thường cũng phải trả nhiều khoản phải trả ngắn hạn.
Giải thích:
- Dòng 1:
tuong_quan<- HSG %>%Bắt đầu tạo đối tượng tuong quan từ dữ liệu HSG.- Dòng 2:
select()Chọn tất cả các cột có kiểu dữ liệu số để tính tương quan.- Dòng 3:
cor(use = "pairwise.complete.obs")Tính ma trận hệ số tương quan giữa các biến số, bỏ qua giá trị bị thiếu theo cặp quan sát hợp lệ.- Dòng 5:
tuong_quan <- as.data.frame(tuong_quan)Chuyển ma trận tương quan thành data frame
1. zscore <- HSG %>%
2. mutate(
3. revenue_z = (`doanh thu ban hang` - mean(`doanh thu ban hang`, na.rm = TRUE)) / sd(`doanh thu ban hang`, na.rm = TRUE),
4. profit_z = (`loi nhuan thuan` - mean(`loi nhuan thuan`, na.rm = TRUE)) / sd(`loi nhuan thuan`, na.rm = TRUE)
5. ) %>%
6. select(nam, revenue_z, profit_z)
7. zscore
Nhận xét: Z-score của doanh thu hay lơi nhuận là đo mức độ lệch của so với tất cả các năm. Tại năm 2015, cả hai chỉ số đều âm, cho thấy doanh thu thấp hơn trung bình, lợi nhuận cũng thấp. Tại năm 2016-2017, doanh thu vẫn thấp nhưng lợi nhuận cao hơn trung bình cho thấy khả năng sinh lời tốt. Tốt nhất là năm 2021, doanh thu và lợi nhuận đều vượt trung bình nhiều lần (Z > 1), hiệu quả kinh doanh cao. Năm 2022, có doanh thu cực cao nhưng lợi nhuận âm so với trung bình (Z-score lợi nhuận -0.62), nghĩa là công ty bán được nhiều nhưng biên lợi nhuận thấp, chi phí lớn.
Giải thích: Sử dụng toán tử pipe để truyền bộ dữ liệu HSG và để sang bước tiếp theo,
mutate()là để tạo cột thêm hai cột mới là revenue_z và profit_z. Trong đó, kết quả revenue_z và profit_z được tính bằng công thức Z-Score,(doanh thu ban hang - mean(...)) / sd(...). cho biết mỗi doanh thu hoặc lợi nhuận cao hay thấp so với trung bình, tính theo số độ lệch chuẩn.select()dùng để chọn các cột cần giữ lại trong kết quả cuối cùng, ở đây chỉ giữlại 3 cột nam, revenue_z, profit_z.
1. library(dplyr)
2. library(tidyr)
3. avg_data <- HSG %>% group_by(nam) %>% summarise(
4. avg_cphinganhan = mean(`chi phi phai tra ngan han`, na.rm = TRUE),
5. avg_tien = mean(`tien`, na.rm = TRUE)) %>%
6. pivot_longer(cols = c(avg_cphinganhan, avg_tien),
7. names_to = "Chỉ_tiêu",
8. values_to = "Giá_trị")%>%
9. mutate(
10. Gia_tri_hienthi = comma(Giá_trị, big.mark = ".", decimal.mark = ","))
11. head(avg_data)
Nhận xét: Tại năm 2015, mục chỉ tiêu trung bình của tiền là 276 tỷ đồng, còn trung bình chi phí phải trả ngắn hạn là 81 tỷ đồng, điều này thể hiện công ty dư thừa vốn lưu động, không bị phụ thuộc vào các khoản vay nợ ngắn hạn. Thể hiện được chiến lược tài chính an toàn. Tỷ lệ tiền/ chi phí ngắn hạn cao (276/81 = 3.4) cho thấy công ty sẽ rất ít rủi ro về thanh khoản năm 2015.
Giải thích:
- Dòng 3: Gom nhóm dữ liệu theo năm, tính trung bình từng năm cho 2 biến: “chi phí phải trả ngắn hạn” và “tiền”.
- Dòng 6:
pivot_longer(cols = c(avg_cphinganhan, avg_tien)...): Chuyển 2 cột trung bình này thành 1 cột “Giá_trị” để dữ liệu ở dạng dài để dễ vẽ biểu đồ hoặc so sánh.- Dòng 9:
mutate(): Tạo thêm một cột mới định dạng dấu chấm phân cách hàng nghìn.
1. TienMat_stats <- HSG %>%
2. group_by(`phan loai doanh thu`) %>%
3. summarise(
4. N = n(),
5. Mean = mean(tien, na.rm = TRUE),
6. SD = sd(tien, na.rm = TRUE),
7. Var = var(tien, na.rm = TRUE),
8. Min = min(tien, na.rm = TRUE),
9. Q1 = quantile(tien, 0.25, na.rm = TRUE),
10. Median = median(tien, na.rm = TRUE),
11. Q3 = quantile(tien, 0.75, na.rm = TRUE),
12. Max = max(tien, na.rm = TRUE) ) %>%
13. arrange(`phan loai doanh thu`)%>%
14. mutate(across(
15. where(is.numeric),
16. ~ comma(., big.mark = ".", decimal.mark = ",")))
17.
18. head(TienMat_stats)
Nhận xét: Tính các phép toán thống kê cơ bản của danh mục Tiền theo phân loại doanh thu. Tại mức doanh thu tốt, trung bình tiền mặt nắm giữ là khoản 400 tỷ hơn, với độ lệch chuẩn là 177 tỷ đồng, độ lệch chuẩn tương đối lớn so với trung bình 44%. Điều này cho thấy rằng mức tiền mặt biến động khá mạnh giữa các quan sát, có năm tiền mặt thấp hơn nhiều hoặc có năm cao hơn nhiều. Có thể là do biến động doanh thu, chi phí, hoặc các khoản đầu tư, thanh toán nợ.
Giải thích:Bắt đầu chuỗi thao tác với HSG bằng pipe %>% .
group_by(phan loai doanh thu):Nhóm dữ liệu theo cột phan loai doanh thu. Mỗi nhóm sẽ tính thống kê riêng.summarise(...): thực hiện các thống kê cho từng nhóm .arrange(phan loai doanh thu): Sắp xếp kết quả theo thứ tự chữ cái của nhóm doanh thu.mutate(across(...)):Chọn tất cả cột numeric và định dạng số theo dấu thập phân và ngăn cách hàng nghìn
1. HSG_summary <- HSG %>% group_by(nam) %>% summarise(
2. total_profit_mix = sum(`loi nhuan gop`, na.rm = TRUE),
3. total_profit = sum(`loi nhuan thuan`, na.rm = TRUE),) %>%
4. mutate(ratio_total = total_profit_mix / total_profit ) %>%
5. mutate(across(c(total_profit_mix, total_profit),
6. ~ comma(., big.mark = ".", decimal.mark = ","))) %>% arrange(nam)
7. HSG_summary
Nhận xét: Ở năm 2015, lợi nhuận gộp khoảng 2.577 tỷ và lợi nhuận thuần khoảng 808 tỷ, gấp 3.1 lần so với lợi nhuận thuần cho thấy chi phí hoạt động và chi phí khác khá cao, làm giảm đáng kể lợi nhuận thuần cuối cùng. Công ty có khả năng bán hàng tốt (biên lợi nhuận gộp ổn định), nhưng chi phí vận hành hoặc chi phí tài chính lớn, nên lợi nhuận thuần còn lại không nhiều. Đây là tín hiệu cần xem xét hiệu quả quản lý chi phí, khả năng tối ưu hóa hoạt động hoặc tài chính.
Giải thích: HSG %>% để dùng pipe để truyền dữ liệu HSG vào các bước tiếp theo.
group_by(nam):ngom dữ liệu theo cột nam (theo từng năm).summarise(...):tính tổng các chỉ tiêu trong từng nhóm gồm lợi nhuận gộp và lợi nhuận thuần.arrange(nam): sắp xếp các hàng theo thứ tự năm tăng dần.mutate(across(...)): Tạo cột mới với tỷ lệ lấy lợi nhuận gộp / lợi nhuận thuần.comma(): định dạng số để phân cách ra số ở hàng nghìn và số thập phân.
1. VCSH_data <- HSG %>%
2. select(nam,`von co phan`,`LNSTCPP`) %>%
3. pivot_longer(cols = -nam, names_to = "VCSH",values_to = "gia_tri") %>%
4. group_by(nam) %>% mutate( tong_thu = sum(gia_tri, na.rm = TRUE),
5. tile = gia_tri / tong_thu * 100,
6. tile_lab = paste0(round(tile, 1), "%") ,
7. gia_tri_lab = scales::label_number(
8. big.mark = ".",
9. decimal.mark = ",", accuracy = 1)(gia_tri) )
10. head(VCSH_data)
Nhận xét: Bộ dữ liệu chứa hai biến thuộc danh mục Vốn chủ sở hữu, vì vậy, để xem cơ cấu vốn chủ sở hữu,(giả định chỉ bao gồm 2 biến này) ta cộng hai thành phần lại để ra được tổng thu và tính phần trăm từng loại. Tại năm 2015, vốn cổ phần sẽ chiến 39.7%, còn Lợi nhuận sau thuế chưa phân phối chiếm 60.3%, điều này thể hiện tỷ trọng lợi nhuận giữu lại lớn hơn vốn gốc, điều này thể hiện công ty tự tái đầu tư lợi nhuận để phát triển, không phụ thuộc quá nhiều vào vốn bên ngoài.
Giải thích:
- Dòng 3:
pivot_longer()": biến sang dạng dài, tuy nhiên cột “nam” vẫn giữ nguyên.group_by(nam): Nhóm dữ liệu theo năm, để tính tổng vốn của mỗi năm vàmutate(): tính tổng vốn của các loại VCSH nằm đó, bỏ qua giá trị NA nếu có. Sau đó tính tỷ lệ “%” từng loại danh mục trên tổng vốn. Và cuối cùng là tạo nhãn hiện thị phần trăm trên biểu đồ và là tròn 1 chữ số thập phân.- Dòng 7: tạo thêm một cột phân cách hàng nghìn, tên là
gia_tri_lab
1. HSG %>%
2. mutate(total_assets = `tien` +`Cac khoan tuong duong tien`+ `TSCD`+
3. `cac khoan phai thu dai han` + `cac khoan phai thu ngan han`) %>%
4. group_by(nam) %>%
5. summarise(
6. pct_tien = sum(`tien`, na.rm=TRUE) / sum(total_assets, na.rm=TRUE) * 100,
7. pct_tuong_duong_tien = sum(`Cac khoan tuong duong tien`, na.rm=TRUE) / sum(total_assets, na.rm=TRUE) * 100,
8. pct_phai_thu_dai_han = sum(`cac khoan phai thu dai han`, na.rm=TRUE) / sum(total_assets, na.rm=TRUE) * 100,
9. pct_phai_thu_ngan_han= sum(`cac khoan phai thu ngan han`, na.rm=TRUE) / sum(total_assets, na.rm=TRUE) * 100,
10. pct_TSCD = sum(`TSCD`, na.rm=TRUE) / sum(total_assets, na.rm=TRUE) * 100)
Nhận xét: Tài sản cố định hữu hình chiếm tới 76% tổng tài sản, trong khi tiền mặt và các khoản tương đương tiền chỉ chiếm 6,2%, còn phải thu ngắn hạn chiếm 16%. Cấu trúc này phản ánh công ty đang duy trì một tỷ trọng vốn cố định cao, tập trung vào hoạt động sản xuất và đầu tư vào cơ sở vật chất, thiết bị. Tuy nhiên, tỷ lệ tiền mặt thấp cho thấy khả năng thanh khoản ngắn hạn hạn chế, tiềm ẩn rủi ro trong việc đáp ứng các nghĩa vụ tài chính đột xuất hoặc chi phí hoạt động ngắn hạn. Tuy nhiên ở năm 2021,Tài sản cố định hữu hình (TSCĐ) giảm mạnh còn khoảng 7%, trong khi phải thu ngắn hạn chiếm tới 88% và tiền mặt chỉ còn 3% tổng tài sản. Sự thay đổi này phản ánh công ty giảm đầu tư dài hạn và chuyển phần lớn tài sản sang các khoản ngắn hạn. Cấu trúc tài sản này và những năm sau đó cho thấy công ty đã chuyển từ mô hình tài sản cố định nặng sang mô hình tài sản luân chuyển nhanh, nhấn mạnh tầm quan trọng của quản lý dòng tiền và rủi ro tín dụng khách hàng để duy trì ổn định tài chính.
Giải thích:
- Dòng 2:
mutate(total_assets = ...)tạo cột mới total_assets cho mỗi hàng bằng tổng các thành phần tài sản có trong bộ dữ liệu- Dòng 4: nhóm bản ghi theo năm. Dòng 5:
summaries(): thực hiện các phép thống tính cho mỗi biến.
1. vaytaichinh_stats <- HSG %>%
2. group_by(`bac loi nhuan`) %>%
3. summarise(
4. N = n(), # số quan sát
5. Mean = mean(`vay va no thue tai chinh`, na.rm = TRUE),
6. SD = sd(`vay va no thue tai chinh`, na.rm = TRUE),
7. Var = var(`vay va no thue tai chinh`, na.rm = TRUE),
8. Min = min(`vay va no thue tai chinh`, na.rm = TRUE),
9. Q1 = quantile(`vay va no thue tai chinh`, 0.25, na.rm = TRUE),
10. Median = median(`vay va no thue tai chinh`, na.rm = TRUE),
11. Q3 = quantile(`vay va no thue tai chinh`, 0.75, na.rm = TRUE),
12. Max = max(`vay va no thue tai chinh`, na.rm = TRUE)) %>%
13. mutate(across(where(is.numeric),
14. ~ comma(., big.mark = ".", decimal.mark = ",")))
15. head(vaytaichinh_stats)
Nhận xét: Tại bậc lợi nhuận khỏe, với biên lợi nhuận lớn hơn 8% thì trung bình nợ tài chính mà doanh nghiệp mượn khoảng 4.428 tỷ đồng, tuy nợ cao nhưng doanh nghiệp vẫn có lợi nhuận cao có thể dùng nợ tài chính để đầu tư thêm, tận dụng đòn bẩy tài chính với độ lệch chuẩn/trung bình khoảng 10, so với tổng mức nợ, dao động này không quá lớn, doanh nghiệp có quản lý nợ khá ổn định.Tuy nhiên ở bậc lợi nhuận mỏng, thì sai số chuẩn/trung bình khoảng gần 45%, độ biến động lớn, cho thấy vay lúc này lớn, cần điều tiết dòng tiền để tránh gây ra rủi ro hay khủng hoảng.
Giải thích:
- Dòng 1:
vaytaichinh_statsthực hiện các thống kê cơ bản của vay và nợ thuê tài chính theo bậc lợi nhuận.- Dòng 13:
mutate(): Phân cách hàng nghìn
1. df_group <- HSG %>%
2. select(nam, TSCD, `von co phan`) %>%
3. pivot_longer(-nam, names_to = "Chitieu", values_to = "giatri") %>%
4. mutate(
5. Chitieu = recode(Chitieu, TSCD = 'TSCĐ', `von co phan` = 'Vốn cổ phần')) %>%
6. group_by(nam) %>%
7. mutate(la_max = giatri == max(giatri),
8. giatri_hienthi = comma_vn(giatri)) %>% ungroup()
9. head(df_group, 10)
Nhận xét: Kết quả dùng để so sánh 2 chỉ tiêu là TSCĐ và vốn cổ phần, nếu một trong hai, cái nào lớn hơn thì sẽ trả về TRUE. Mục đích chính là đánh giá mức độ đầu tư tài sản dài hạn so với nguồn vốn chủ sở hữu .Tại năm 2018-2019, kKhi TSCĐ nhỏ hơn vốn cổ phần, điều đó cho thấy doanh nghiệp có khả năng tự tài trợ cho tài sản dài hạn bằng vốn của cổ đông, phản ánh tình hình tài chính an toàn và bền vững. Ngược lại,từ khoảng năm 2015-2017, TSCĐ lớn hơn vốn cổ phần, doanh nghiệp có thể đang sử dụng thêm nợ vay để đầu tư, làm tăng rủi ro tài chính và thể hiện mức độ phụ thuộc vào nguồn vốn bên ngoài
Giải thích:
- Dòng 2:
select(): Chỉ lấy các biến cần phân tích..- Dòng 3:
pivot_longer(-nam, ...): Chuyển từ dạng bảng ngang, mỗi năm một dòng, hai chỉ tiêu là hai cột TSCD/tien thành bảng dọc.- Dòng 4:
mutate(Chitieu = recode(...)): Đổi tên,la_max = giatri == max(giatri): Đánh dấu trong từng năm dòng nào là lớn nhất (TRUE). Thao tác này sau khigroup_bynăm sẽ cho đúng logic: duy nhất bar giá trị lớn nhất mỗi năm mới TRUE. Dùng để tạo hiệu ứng nhãn số nổi bật.ungroup()có tác dụng bỏ phân nhóm
1. df2 <- HSG %>%
2. select(nam, `vay va no thue tai chinh`, ` tien thu di vay`) %>%
3. pivot_longer(-nam, names_to = "KhoanMuc", values_to = "giatri") %>%
4. mutate(nam = as.factor(nam), KhoanMuc = recode(KhoanMuc,
5. "vay va no thue tai chinh" = "Vay nợ thuê tài chính",
6. "tien thu di vay" = "Tiền thu đi vay"),
7. giatri_hienthi = comma_vn(giatri))
8. label_points <- df2 %>% group_by(KhoanMuc) %>%
9. filter(giatri == max(giatri) | giatri == min(giatri)) %>% ungroup()
10. head(df2,)
Nhận xét: Tại năm 2015, doanh nghiệp đã huy động một lượng vốn vay lớn hơn 13 nghìn tỷ đồng, nhưng dư nợ cuối kỳ chỉ còn hơn 4 nghìn tỷ đồng. Điều này phản ánh khả năng quản lý nợ hiệu quả, dòng tiền vay được sử dụng linh hoạt, và có thể doanh nghiệp đã thanh toán phần lớn nợ ngắn hạn trước cuối năm.Hay yếu tố thể hiện các khoản vay mà doanh nghiệp cần để huy động vốn và cũng thể hiện cách mà doanh nghiệp sử dụng vốn như thế nào.
Giải thích:
- Dòng 2:
select(): Lấy ra 3 cột cần thiết là ‘nam’, ‘vay va no thue tai chinh’, ‘tien thu di vay’.- Dòng 3:
pivot_longer(-nam, ...): Chuyển dữ liệu sang dạng dài, gom hai biến về một cột “KhoanMuc”, giá trị về cột “giatri” để dễ biểu diễn dạng nhóm.- Dòng 4:
mutate(): Chuyển ‘nam’ thành factor giúp nhóm theo trục x tốt hơn khi là barplot. Đổi tiếng Việt có dấu cho các tên khoản mục- Dòng 10:
filter(...max... | ...min...): Lấy ra dòng có giá trị lớn nhất và nhỏ nhất của từng nhóm,ungroup():có tác dụng bỏ phân nhóm
1. nam_moi <- max(HSG$nam)
2. df3 <- HSG %>%
3. filter(nam == nam_moi) %>%
4. select(`cac khoan phai thu dai han`, tien, TSCD) %>%
5. pivot_longer(everything(), names_to = "KhoanMuc", values_to = "giatri") %>%
6. mutate(
7. KhoanMuc = recode(KhoanMuc,
8. "cac khoan phai thu dai han" = "Phải thu dài hạn",
9. "tien" = "Tiền mặt",
10. "TSCD" = "Tài sản cố định"),
11. tyle = giatri / sum(giatri))
12. head(df3)
Nhận xết: Lấy ra những năm có giá trị 3 danh mục là lớn nhất trong mục tài sản. Ta dễ thấy, cơ cấu tài sản của doanh nghiệp cho thấy tài sản cố định chiếm tỷ trọng áp đảo (hơn 82%), trong khi tiền mặt chỉ chiếm khoảng 12,6% và các khoản phải thu dài hạn chiếm tỷ trọng nhỏ (khoảng 4,5%). Điều này phản ánh phù hợp khi doanh nghiệp hoạt động trong lĩnh vực thép, có cường độ đầu tư lớn vào tài sản cố định — chẳng hạn như sản xuất công nghiệp, xây dựng hoặc cơ khí. Phần lớn nguồn vốn được sử dụng cho máy móc, nhà xưởng và thiết bị sản xuất, thay vì giữ dưới dạng tiền mặt hoặc cho vay dài hạn.
Giải thích:
- Dòng 1: lấy ra năm lớn nhất trong dữ liệu.
- Dòng 3:
filter(nam == nam_moi): Chỉ giữ lại dữ liệu của năm mới nhất.- Dòng 4:
select(...): Chọn đúng ba loại tài sản cần phân tích tỉ trọng.- Dòng 5:
pivot_longer(...): Chuyển dữ liệu sang dạng dài.- Dòng 6:
mutate( ): Đổi tên từng loại tài sản. Tính tỉ trọng từng loại tài sản trên tổng tài sản.
1. top5_profit_revenue <- HSG %>%
2. mutate(
3. rank_profit = min_rank(desc(`loi nhuan thuan`)),
4. rank_revenue = min_rank(desc(`doanh thu ban hang`)),
5. combined_rank = rank_profit + rank_revenue) %>%
6. arrange(combined_rank) %>% slice_head(n = 5) %>%
7. mutate(
8. `doanh thu ban hang` = comma_vn(`doanh thu ban hang`),
9. `loi nhuan thuan` = comma_vn(`loi nhuan thuan`),
10. `Bien loi nhuan` = paste0(
11. format(round(`Bien loi nhuan`, 4), decimal.mark = ",", nsmall = 4))) %>%
12. select(nam, `phan loai doanh thu`, `bac loi nhuan`, `doanh thu ban hang`,
13. `loi nhuan thuan`, `Bien loi nhuan`)
14. top5_profit_revenue
Nhận xét: Thông qua bảng thống kê, cho ta thấy doanh thu và lợi nhuận trong năm như thế nào. Năm 2021 là một năm nổi bật đối với công ty, khi doanh thu và lợi nhuận đạt top cao nhất trong giai đoạn quan sát. Bậc lợi nhuận cũng phản ánh kết quả tích cực, cho thấy công ty hoạt động hiệu quả và quản lý chi phí tốt. Biên lợi nhuận cho thấy cứ 10 đồng doanh thu tạo ra khoảng 1 đồng lợi nhuận thuần, phản ánh công ty duy trì khả năng sinh lời ổn định và kiểm soát chi phí hợp lý, đồng thời khẳng định năng lực tạo giá trị từ doanh thu trong năm này. Trong năm 2022, mặc dù doanh thu cao hơn năm 2021, nhưng khả năng sinh lời của công ty lại giảm đáng kể. Nhìn vào biên lợi nhuận, chúng ta thấy cứ 60 đồng doanh thu mới tạo ra 1 đồng lợi nhuận, cho thấy hiệu quả sử dụng doanh thu kém hơn nhiều so với năm trước. Do đó, bậc lợi nhuận phản hồi là thấp, nhấn mạnh rằng dù tổng doanh thu tăng, công ty vẫn cần tối ưu hóa chi phí và nâng cao hiệu quả kinh doanh để cải thiện khả năng sinh lời.
Giải thích:
- Dòng 1:
top5_profit_revenue: tạo một bảng mới về top 5 doanh thu và lợi nhuận- Dòng 2:
mutate(rank_profit = min_rank(desc(loi nhuan thuan))): Tạo cột mới rank_profit là thứ hạng giảm dần của lợi nhuận thuần,desc(): sắp xếp giảm dần, tức giá trị cao hơn tương ứng với hạng tốt hơn (1 là cao nhất).min_rank(): tính hạng theo giá trị, hạng bằng nhau sẽ nhận cùng giá trị.- Dòng 5:
combined_rank = rank_profit + rank_revenue: Tạo cột mới tổng hợp 2 hạng để đánh giá cả lợi nhuận lẫn doanh thu. Giá trị nhỏ làtốt hơn cả hai chỉ tiêu.- Dòng 6:
arrange(combined_rank):Sắp xếp toàn bộ bảng theo combined_rank tăng dần, tức là top 5 đầu tiên sẽ là các quan sát có cả lợi nhuận và doanh thu cao,slice_head(n = 5):Lấy 5 quan sát đầu tiên sau khi sắp xếp, tức top 5 “tốt nhất” theo chỉ số kết hợp.- Dòng 7:
mutate(): Chuyển định dạng số sang dấu phân cách hàng nghìn.- Dòng 12:
select():Chọn các cột quan trọng để hiển thị.
1. VCSH_data <- HSG %>%
2. select(nam,`von co phan`,`LNSTCPP`) %>%
3. pivot_longer(cols = -nam,names_to = "VCSH",values_to = "gia_tri") %>%
4. group_by(nam) %>%
5. mutate(
6. tong_thu = sum(gia_tri, na.rm = TRUE),
7. tile = gia_tri / tong_thu * 100,
8. tile_lab = paste0(round(tile, 1), "%"))
9. # Vẽ biểu đồ bar chart ngang
10. ggplot(VCSH_data, aes(x = factor(nam), y = gia_tri, fill = VCSH)) +
11. geom_col(position = "stack", width = 0.7, alpha = 0.95) +
12. geom_text(aes(label = tile_lab),
13. position = position_stack(vjust = 0.5),
14. size = 3.6, color ="black", family = "sans") +
15. coord_flip() +
16. scale_fill_brewer(palette = "Set2") +
17. scale_y_continuous(labels = label_number(scale_cut = cut_short_scale())) +
18. labs(
19. title = "Cơ cấu VCSH của HSG theo giá trị thực tế",
20. x = "Năm",
21. y = "Giá trị (1T = 1 nghìn tỷ VND)",
22. fill = "VCSH") +
23. theme_minimal(base_size = 13) +
24. theme(
25. plot.title = element_text(face = "bold", size = 16),
26. plot.subtitle = element_text(color = "gray30"),
27. legend.position = "bottom",
28. panel.grid.major.y = element_blank(),
29. panel.grid.minor = element_blank())
>Nhận xét: Nhìn vào biểu đồ, ta dễ thấy cơ cấu VCSH
của HSG từ năm 2015-2024 tăng gần như là liên tục. Ban đầu vốn chỉ dưới
3 nghìn tỷ, và lợi nhuận giữ lại để đem đi đầu tư là 60.3%, nhưng những
năm từ khi vốn trên 3 nghìn tỷ, thì lợi nhuận sau thuế chưa phân phối
lại nhỏ hơn vốn cổ phần, điều này thể hiện việc công ty huy động vốn từ
bên ngoài, có thể để mở rộng hoạt động hoặc công ty quan tâm đến cổ đông
nên chi trả cổ tức lớn hơn, dẫn đến tỷ trọng lợi nhuận giữ lại giảm.
Nhìn chung đây là dấu hiệu cho thấy Hoa Sen group tăng trưởng chủ động
để mở rộng quy mô.
Giải thích:
- Dòng 1: VCSH_data <- HSG %>% tạo dữ liệu mới VCSH_data từ bảng HSG,
- Dòng 10: Khởi tạo biểu đồ
- Dòng 11, 12: Về biểu đồ cột chồng và them nhãn để dán tỷ lệ % của từng loại vốn
- Dòng 15: coord_flip() Xoay trục x trở thành trục dọc, trục y trở thành trục ngang.
- Dòng 16: chọn bảng màu, “Set2” là bảng màu pastel. Dòng 17: rút gọn số lớn, thay vì 1 nghìn tỷ thì sẽ trở thành 1T. labs(): kà để ghi các tiêu đè chính, giải thích, gắn nhãn cho từng biến. theme_minimal(base_size = 13) + theme(…) Tạo giao diện cho biểu đồ
1. library(dplyr)
2. library(tidyr)
3. avg_data <- HSG %>%
4. group_by(nam) %>% summarise(
5. avg_cphinganhan = mean(`chi phi phai tra ngan han`, na.rm = TRUE),
6. avg_tien = mean(`tien`, na.rm = TRUE)) %>%
7. pivot_longer(cols = c(avg_cphinganhan, avg_tien),
8. names_to = "Chi_tieu", values_to = "Gia_tri")
Tính trung bình chi phí phải trả ngắn hạn và tiền của doanh nghiệp HSG theo năm. Sau đó sử dụng pivot_longer() để chuyển đổi từ cột thành hàng nhằm mục tiêu vẽ đồ thị.
1. library(ggplot2)
2. library(scales)
3. library(ggrepel)
4. ggplot(avg_data, aes(x = nam, y = `Gia_tri`, color = `Chi_tieu`)) +
5. geom_line(aes(group = Chi_tieu), size = 1.0) +
6. geom_point(size = 2) +
7. geom_smooth(method = "loess", se = FALSE, linetype = "dashed") +
8. geom_area(aes(fill = `Chi_tieu`), alpha = 0.1, position = "identity") +
9. scale_y_continuous(labels = label_number(big.mark = ".", decimal.mark = ",")) +
10. labs(
11. title = "Chi phí phải trả ngắn hạn & Tiền theo năm",
12. x = "Năm",
13. y = "Giá trị trung bình (VNĐ)",
14. color = "Chỉ tiêu",
15. fill = "Chỉ tiêu") +
16. theme_minimal(base_size = 13) +
17. theme(
18. legend.position = "bottom",
19. plot.title = element_text(face = "bold", size = 14))+
20. scale_x_continuous(
21. breaks = HSG$nam,
22. labels = HSG$nam)
>Nhận xét: Dựa vào đường xu hướng của hai trung bình
chi phí phải trả ngắn hạn và tiền, ta thấy chúng có mối quan hệ đồng
biến với nhau . Điều này cho thấy những khoản chi phí mà doanh nghiệp đã
chi trả trước để được sử dụng các dịch vụ hoặc hàng hóa tăng, doanh
nghiệp cũng có xu hướng nắm giữ lượng tiền lớn để đảm bảo khả năng chi
trả kịp thời, duy trì uy tín tín dụng, và giảm rủi ro thanh khoản. Ở năm
2020, khi trung bình chi phí phải trả ngắn hạn khoảng 300 tỷ thì doanh
nghiệp sẽ nắm giữ gần 500 tỷ Tiền mặt để dự trữ.
Giải thích:
- Dòng 4: Khởi tạo biểu đồ
- Dòng 5, 6, 7: Vẽ đường nối, them điểm dữ liệu tại từng năm và vẽ đường xu hướng mượt (loess smoothing), dạng nét đứt.
- Dòng 8: geom_area() thêm vùng màu mờ nhẹ dưới đường
- Dòng 9: Phân cách hàng nghìn.
- Dòng 10–15: labs(…): gán tiêu đề, tên trục và chủ giải rõ rang
- theme_minimal(base_size = 13)+ theme(…): Tạo giao diện cho biểu đồ
1. library(ggrepel)
2. tscol <- "luu chuyen tien thuan"
3. ggplot(HSG, aes(x = nam, y = .data[[tscol]])) +
4. geom_line(size = 1) +
5. geom_point(size = 2) +
6. geom_smooth(method = "loess", se = TRUE, alpha = 0.2) +
7. geom_smooth(method = "lm", se = FALSE, linetype = "dashed", size = 0.7) +
8. geom_ribbon(aes(ymin = .data[[tscol]] - sd(.data[[tscol]], na.rm=TRUE),
9. ymax = .data[[tscol]] + sd(.data[[tscol]], na.rm=TRUE)), alpha = 0.08) +
10. geom_text_repel(
11. data = HSG %>% filter(
12. .data[[tscol]] == max(.data[[tscol]], na.rm=TRUE) |
13. .data[[tscol]] == min(.data[[tscol]], na.rm=TRUE)),
14. aes(label = paste0(nam, ": ", comma(.data[[tscol]], big.mark = "."))) ) +
15. labs(title = paste("Thời gian:", tscol),
16. x = "Năm", y = tscol) + theme_minimal() +
17. scale_y_continuous(labels = scales::comma_format(big.mark = ".")) +
18. scale_x_continuous(
19. breaks = HSG$nam,
20. labels = HSG$nam)
>Nhận xét: Dao động lớn giữa các năm: dữ liệu cho
thấy Lưu chuyển tiền thuần từ HĐKD biến thiên mạnh, có năm âm sâu, ví dụ
2017: khoảng hơn âm 2.000 tỷ, có nghĩa doanh nghiệp đã chi rất nhiều
tiền, nó phản ánh áp lực dòng tiền mạnh. Năm 2019 đạt đỉnh rất cao
khoảng 5.100 tỷ. Biến động này báo hiệu rằng hoạt động kinh doanh không
ổn định theo năm, có thể do chu kỳ ngành, biến động nhu cầu
Giải thích:
- Dòng 3: Khởi tạo plot với dữ liệu HSG.
- Dòng 4,5 và 6: Vẽ đường nối các giá trị theo thứ tự năm và đánh dấu các điểm dữ liệu thực tế tại mỗi năm và đường xu hướng mượt
- Dòng 7: geom_smooth(method = “lm”, se = FALSE, linetype = “dashed”, size = 0.7). Vẽ đường hồi quy tuyến tính , so sánh xu hướng thẳng với xu hướng loess.
- Dòng 8: Geom_ribbon():Vẽ băng (ribbon) biểu diễn ±1 độ lệch chuẩn quanh mỗi giá trị hiện thời như được viết.
- Dòng 10: Geom_text_repel(): Gắn nhãn giá trị tại năm cao nhất và thấp nhất
- Lab()+ theme_minimal(): Đặt tiêu đề và tạo giao diện tối giản
- Dòng 17, 18: Phân cách hàng nghìn
1. hsg2 <- HSG %>%
2. mutate(Revenue = `doanh thu ban hang`, COGS = `gia von`,Cash = `tien`)
Tạo một bảng mới có tên là hsg2, bảng mới này được lấy từ bộ dữ liệu HSG, dùng lệnh mutate() để tạo thêm 2 cột mới trong hsg2, để thuận tiện cho việc vẽ biểu đồ.
1. ggplot(hsg2, aes(x = factor(nam))) +
2. geom_col(aes(y = Revenue, fill = "Revenue"), width = 0.6) +
3. geom_col(aes(y = -COGS, fill = "COGS"), width = 0.4, alpha = 0.85) +
4. geom_label(
5. data = filter(hsg2, Revenue == max(Revenue, na.rm = TRUE)),
6. aes(y = Revenue, label = "Doanh thu cao nhất"),
7. nudge_y = max(hsg2$Revenue, na.rm = TRUE) * 0.05, angle = 90, hjust = 1.15,
8. colour = "red", size = 3) +
9. geom_hline(yintercept = 0, colour = "grey40") +
10. geom_col(aes(y = Revenue), width = -0.8, fill = "#B3E5FC", alpha = 0.2) +
11. geom_hline(yintercept = mean(hsg2$Revenue, na.rm = TRUE),
12. color = "blue", linetype = "dashed", linewidth = 0.6) +
13.
14. scale_y_continuous(labels = scales::comma_format(big.mark = ".")) +
15. labs(
16. title = "Doanh thu và giá vốn",
17. x = "Năm", y = "Giá trị (VND)", fill = "") +
18. theme_minimal() +
19. theme(legend.position = "bottom")
>Nhận xét: Biểu đồ cho thấy so sánh ngay tỷ trọng
giá vốn so với doanh thu theo năm. Ta thấy từ khoảng năm 2015 đến 2018
doanh thu dương và chi phí dương, điều này phản ánh hoạt động kinh doanh
thông thường: doanh nghiệp bán hàng và phải bỏ ra các khoản chi phí liên
quan như giá vốn, chi phí bán hàng hay quản lý. Tuy nhiên vào khoảng năm
2019 đến 2022, doanh thu dương nhưng chi phí lại âm mạnh, tạo ra sự bất
thường trong báo cáo tài chính. Nguyên nhân chủ yếu đến từ việc hoàn
nhập dự phòng các khoản đã ghi nhận ở các kỳ trước, các khoản được bồi
thường hay giảm trừ được hạch toán làm giảm chi phí. Vì vậy, chi phí âm
không đồng nghĩa với việc doanh nghiệp kinh doanh mà không tốn chi phí,
mà là do phần giảm trừ lớn hơn phần chi phí thực tế phát sinh trong
kỳ.
Giải thích:
- Dòng 1: Khởi tạo biểu đồ. Dòng 2, 3: Vẽ cột doanh thu. Dòng 4: Thêm nhãn đặc biệt cho cột doanh thu cao nhất
- Dòng 9: geom_hline(yintercept = 0, colour = “grey40”) : Vẽ trục ngang 0 để phân biệt doanh thu và giá vốn âm.
- Dòng 10: Vẽ cột nền doanh thu mờ phía sau để tạo hiệu ứng trực quan (highlight).
- Dòng 11: Thêm đường trung bình doanh thu nét đứt . Dòng 14: Phân cách hàng nghìn
1. hsg3 <- hsg2 %>% mutate(Cash_norm = as.numeric(scale(tien)))
Tạo thêm một bảng hsg3 nhằm chuẩn hóa dòng tiền (cash) về khoảng [0,1] rồi nhân với max(Revenue) — mục đích là đưa đường tiền về cùng thang đo với doanh thu để vẽ chung mà vẫn giữ được hình dạng biến động thực của dòng tiền.
1. ggplot(hsg3, aes(x = factor(nam))) +
2. geom_col(aes(y = Revenue, fill = "Revenue"), alpha = 0.75) +
3. geom_line(aes(y = Cash_norm * max(Revenue, na.rm = TRUE),
4. color = "Tiền (chuẩn hóa)"), size = 1.2, group = 1) +
5. geom_point(aes(y = Cash_norm * max(Revenue, na.rm = TRUE),
6. color = "Tiền (chuẩn hóa)"), size = 3) +
7. geom_hline(yintercept = 0, colour = "grey40") +
8. scale_y_continuous(
9. labels = comma_format(big.mark = "."),
10. sec.axis = sec_axis(
11. trans = ~ (. - 0) / max(hsg3$Cash_norm, na.rm = TRUE) *
12. (max(hsg3$Cash_norm, na.rm = TRUE) - min(hsg3$Cash_norm, na.rm = TRUE)) +
13. min(hsg3$Cash_norm, na.rm = TRUE),
14. name = "Tiền (VNĐ)",
15. labels = comma_format(big.mark = "."))) +
16.
17. scale_fill_manual(values = c("Revenue" = "#56B4E9")) +
18. scale_color_manual(values = c("Line = Cash" = "#e31a1c")) +
19. labs(
20. title = "Doanh thu và Tiền",
21. x = "Năm",y = "Doanh thu (VNĐ)", fill = "", color = "" ) +
22. theme_minimal() +
23. theme(
24. legend.position = "top",
25. legend.title = element_blank() )
Nhận xét: Cột doanh thu ta thấy xu hướng tổng thể tăng qua các năm. Đường “Tiền - Cash” thì lại biến động mạnh. Ở những năm 2015-2017, doanh thu tăng từ khoảng 15.000 tỷ đến 48.000 tỷ, tiền mặt cũng tăng mạng, thể hiện khả năng chuyển đổi doanh thu thành dòng tiền thực tốt. Nhưng ở những năm 2018-2020, doanh thu giảm mạnh, có thể do nguyên nhân từ dịch Covid, dòng tiền lúc này cũng biến động mạnh, có thể phải trả chi phí đầu tư lớn, hoặc thị trường đang giảm cầu. Và những năm tiếp theo thì doanh thu tăng bật, dòng tiềng cũng song hành, chứng tỏ dòng tiền hoạt động quay lại dương mạnh. Doanh nghiệp có thể đã tái cấu trúc, giảm chi phí, mở rộng sản xuất, hoặc hưởng lợi từ phục hồi kinh tế chung.
Giải thích:
- Dòng 1: Khởi tạo biểu đồ
- Dòng 2: geom_col(): Vẽ cột doanh thu . Dòng 3: geom_line(): Vẽ đường tiền đã chuẩn hóa để so sánh trực quan với doanh thu, nhân với max(Revenue) để đưa về cùng tỉ lệ.
- Dòng 5: Thêm điểm dữ liệu trên đường tiền chuẩn hóa, kích thước 3.
- Dòng 7: geom_hline(): Vẽ trục ngang 0 để phân biệt các giá trị.
- Dòng 8: Định dạng trục Y chính có dấu chấm ngăn nghìn, Thêm trục phụ bên phải (sec.axis) để hiển thị giá trị tiền gốc, dùng công thức chuyển đổi từ trục đã chuẩn hóa sang giá trị thực.
- Dòng 17,18: Tô màu cho cột doanh thu và đường tiền. labs() : Thêm tiêu đề, nhãn trục x và y. theme_minimal() + theme() tạo giao diện cho biểu đồ
1. ggplot(HSG, aes(x=`doanh thu ban hang`/1e12, y=`loi nhuan thuan`/1e12)) +
2. geom_point(aes(color=`phan loai doanh thu`), size=3, alpha=0.6) +
3. geom_smooth(method="lm", se=FALSE, color="black") +
4. geom_text(aes(label=round(`loi nhuan thuan`/1e12,1)), check_overlap=TRUE, vjust=-1, size=3) +
5. geom_density2d(color="blue") +
6. geom_rug(alpha=0.3) +
7. geom_hline(yintercept=mean(HSG$`loi nhuan thuan`/1e12), linetype="dashed") +
8. labs(title="Doanh thu vs Lợi nhuận theo phân loại doanh thu",
9. x="Doanh thu bán hàng (nghìn tỷ)", y="Lợi nhuận (nghìn tỷ)") +
10. theme_minimal()
>Nhận xét: khu vực tập trung nhiều điểm phân loại
doanh thu thì khu vực đó sẽ có mật độ cao, nghĩa là sự phân loại mức
doanh thu sẽ tập trung ở đó nhiều. Khu vực mật độ thấp(góc trên bên
phải) nghĩa là điểm phân loại doanh thu không phân bổ ở đó nhiêu, HSG
khó đạt được. Vùng mật độ doanh số ở vòng số 2 từ trong đếm ra chứa 4
điểm doanh thu ổn định với mức lợi nhuận/doanh thu bán hàng khoảng 0.1
đến 1.4. Nghĩa làkhoảng 10 đồng doanh thu sẽ tạo ra 1 đồng lợi
nhuận.
Giải thích:
- Dòng 1: Khởi tạo biểu đò
- Dòng 2: geom_point() vẽ các điểm dữ liệu thực tế. Dòng 3: geom_smooth() thêm đường hồi quy tuyến tính
- Dòng 4:Ghi nhãn lợi nhuận trên từng điểm (chia 1e12 để hiển thị nghìn tỷ),
- Dòng 5: geom_density2d(color=“blue”):Vẽ đường đồng mức mật độ 2D của các điểm, Mỗi đường contour thể hiện vùng tập trung của điểm dữ liệu, Màu blue để phân biệt với đường xu hướng. Dòng 6: geom_rug(alpha=0.3): Thêm chi tiết nhỏ dọc trục X và Y để hiển thị phân bố các giá trị riêng lẻ.
- labs(title=…, x=…, y=…): Đặt tiêu đề và nhãn trục cho biểu đồ. theme_minimal(): Tạo giao diện cho biểu đồ
1. library(RColorBrewer)
2. HSG_char<- HSG %>%
3. group_by(`phan loai doanh thu`) %>%
4. summarise(total_daihan= sum(`cac khoan phai thu dai han`), .groups="drop") %>%
5. mutate(
6. percentage = (total_daihan / sum(total_daihan)) * 100,
7. label = paste0(`phan loai doanh thu`, "\n", round(percentage,1), "%"))
8. my_colors <- brewer.pal(n = nrow(HSG_char), name = "Paired")#
9. ggplot(HSG_char, aes(x = 1, y = total_daihan, fill = `phan loai doanh thu`)) +
10. geom_bar(stat = "identity", width = 0.9, color = "white", size = 0.5, alpha = 0.9)+
11. coord_polar(theta = "y") +
12. geom_text(aes(label = label),
13. position = position_stack(vjust = 0.5),
14. color = "black", size = 3, fontface = "bold") +
15. scale_fill_manual(values = my_colors) +
16. labs(title = "Các khoản phải thu dài hạn theo loại doanh thu") +
17. theme_void() +
18. theme(legend.position = "right",
19. plot.title = element_text(hjust=0.8, size=16, face="bold")) +
20. geom_bar(stat = "identity", width = 0.7, alpha = 0.5) #Hiệu ứng nhẹ bằng shadow
> Nhận xét: Sau khi tính tổng các khoản phải thu dài
hạn theo phân loại doanh thu và tính tỷ trọng từng loại. Vẽ được biểu đồ
hình tròn thể hiện rằng, tại mức doanh thu tốt, các khoản nợ của doanh
nghiệp ở mức 35.5%, có thể là doanh nghiệp cho phép các khách hàng lớn
được ưu đãi về kỳ hạn thanh toán. Ở mức doanh thu ổn chiếm 61.4% các
khoản thu dài hạn, cho thấy doanh nghiệp duy trì chính sách tín dụng dài
hạn.
Giải thích:
- Dòng 2–4: Tạo bảng tổng hợp tổng khoản phải thu dài hạn theo từng loại doanh thu, bỏ grouping sau khi tóm tắt (.groups=“drop”).
- Dòng 8: Chọn bảng màu Paired với số màu bằng số loại doanh thu.
- Dòng 9: Khởi tạo biểu đồ
- Dòng 10: geom_bar(): Vẽ cột giá trị thực
- Dòng 11: coord_polar(theta = “y”): Chuyển cột thành pie chart dựa theo trục Y.
- Dòng 12: geom_text(): dán nhãn lên từng miếng bánh, xong đặt label xếp chồng lên.
- Dòng 15: scale_fill_manual(values = my_colors) tô màu các loại doanh thu, labs() để tạo tiêu đề biểu đồ và theme_void(): Bỏ hết trục, grid, nền, cho pie chart tối giản. theme(): Chỉnh màu và kích thước tiêu đề
- Dòng 20: geom_bar(stat = “identity”, width = 0.7, alpha = 0.5): lặp lại thêm một lần để vẽ đè lên layer trước với kích thước nhỏ hơn để tạo shadow.
1. library(RColorBrewer)
2. HSG$`Bien loi nhuan` <- ifelse(
3. HSG$`doanh thu ban hang` != 0,
4. HSG$`loi nhuan thuan` / HSG$`doanh thu ban hang` ,
5. 0 )
6. # Tạo cột "Bậc lợi nhuận" dựa trên cột "Biên lợi nhuận"
7. HSG$`bac loi nhuan` <- ifelse(HSG$`Bien loi nhuan` < 0, "Lỗ",
8. ifelse( HSG$`Bien loi nhuan` < 0.03, "Mỏng",
9. ifelse(HSG$`Bien loi nhuan` < 0.08, "Trung bình",
10. ifelse(HSG$`Bien loi nhuan` < 0.15, "Khỏe",
11. "Tuyệt hảo"))))
12. # Mã hóa bậc lợi nhuận thành số thứ tự
13. HSG <- HSG %>%
14. mutate(
15. bac_num = case_when(
16. `bac loi nhuan` == "Lỗ" ~ 1,
17. `bac loi nhuan` == "Mỏng" ~ 2,
18. `bac loi nhuan` == "Trung bình" ~ 3,
19. `bac loi nhuan` == "Khỏe" ~ 4,
20. `bac loi nhuan` == "Tuyệt hảo" ~ 5,
21. TRUE ~ NA_real_ ))
22. # Tính trung binh bac lợi nhuận đã được chuyển đổi, chi phí bán hàng theo năm
23. bacloinhuan_nam <- HSG %>%
24. group_by(nam) %>%
25. summarise(
26. bac_tb = mean(bac_num, na.rm = TRUE),
27. bac_text = first(`bac loi nhuan`),
28. trb_cpbh = mean(`chi phi ban hang`, na.rm = TRUE))
1. ggplot(bacloinhuan_nam, aes(x = factor(nam))) +
2. geom_col(aes(y = bac_tb, fill = bac_text), width = 0.6, alpha = 0.9) +
3. geom_line(
4. aes(y = (trb_cpbh / max(trb_cpbh, na.rm = TRUE)) * 5, group = 1),
5. color = "black", size = 1.2) +
6. geom_point(
7. aes(y = (trb_cpbh / max(trb_cpbh, na.rm = TRUE)) * 5),
8. color = "black", size = 2) +
9. scale_y_continuous(
10. breaks = 1:5,
11. labels = c("Lỗ", "Mỏng", "Trung bình", "Khỏe", "Tuyệt hảo"),
12. sec.axis = sec_axis(
13. ~ . / 5 * max(bacloinhuan_nam$trb_cpbh, na.rm = TRUE),
14. name = "Chi phí bán hàng", labels = label_number(big.mark = ".", accuracy = 1))) +
15. scale_fill_brewer(palette = "Set2") +
16. labs(
17. title = "Bậc lợi nhuận theo năm", x = "Năm", y = "Bậc lợi nhuận",
18. fill = "Bậc lợi nhuận") +
19. theme_minimal(base_size = 11) +
20. theme( plot.title = element_text(hjust = 0.5, face = "bold"),
21. legend.position = "right")
> Nhận xét: Biểu đồ bậc lợi nhuận theo năm gồm thêm
yếu tố chi phí bán hàng, để thấy được hiệu quả hoạt động kinh doanh của
doanh nghiệp qua các năm từ 2015 đến 2024. Có thể thấy chi phí bán hàng
từ 2015-2018 giảm liên tục, có thể là doanh nghiệp đang ghi nhận hàng
trước khi nhập kho hoặc các chi phí điều chỉnh,tuy nhiên cột biên lợi
nhuận cũng ở mức trung bình và khỏe, cho thấy doanh nghiệp quản trị dòng
tiền đủ tốt. Ở năm 2022, chi phí đạt cao nhất là 4.000 tỷ đồng kéo theo
doanh bậc lợi nhuận cũng chỉ ở mức mỏng, vì khi bỏ quá nhiều chi phí thì
doanh thu tạo ra ít.
Giải thích:
- Dòng 1: Khởi tạo biểu đồ
- Dòng 2: Vẽ biểu đồ cột thể hiện bậc lợi nhuận trung bình và gán màu theo nhóm; width = 0.6 — bề ngang cột; alpha = 0.9 — độ trong suốt.
- Dòng 3 và 6: Vẽ đường chi phí bán hàng màu đen và thêm điểm dữ liệu
- Dòng 9: scale_y_continuous(): breaks = 1:5 — hiển thị tick tại các giá trị 1,2,3,4,5. sec.axis = sec_axis(…): quy đổi lại giá trị chuẩn hóa thành giá trị gốc và them phân cách hàng nghìn
- Dòng 15: Thêm màu cho cột. labs() đặt tiêu đề và tên trục x, y, nhãn. theme_minimal() + theme(…) Tạo giao diện cho biểu đồ
1. ggplot(HSG, aes(x = `phan loai doanh thu`, y = `Bien loi nhuan`,
2. fill = `phan loai doanh thu`)) +
3. geom_boxplot(alpha = 0.6, width = 0.6, color = "black") +
4. geom_jitter(width = 0.15, alpha = 0.5, size = 1.5) +
5. geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
6. labs(
7. title = "Biên lợi nhuận theo phân loại doanh thu",
8. x = "Phân loại doanh thu",
9. y = "Biên lợi nhuận (%)") +
10. scale_fill_brewer(palette = "Set2") +
11. theme_minimal(base_size = 13) +
12. theme(
13. plot.title = element_text(face = "bold", hjust = 0.5),
14. axis.text.x = element_text(angle = 20, vjust = 0.9, hjust = 0.6),
15. legend.position = "none")
> Nhận xét: Thông qua biểu đồ ta thấy, tại mức doanh
thu tốt so với mức doanh thu yếu, thì có thể biên lợi nhuận của doanh
thu yếu nhỉnh hơn, điều này thể hiện được rằng, một số năm tuy doanh thu
chưa cao nhưng biết sử dụng doanh thu để tạo ra nhiều đồng lợi nhuận.
Còn tại mức doanh thu ổn, chủ yếu biên lợi nhuận rơi khoảng 0.01-0.02 và
có thêm giá trị ngoại lai tại mức 0.05.
Giải thích
- Dòng 1: Khởi tạo biểu đồ
- Dòng 3: Vẽ hộp biểu thị tứ phân vị của biên lợi nhuận theo từng nhóm
- Dòng 4: geom_jitter(): vẽ từng điểm dữ liệu rải rác xung quanh trục x để tránh chồng chéo với độ rộng 0.15, nhỏ hơn bề rộng của box plot
- Dòng 5: geom_hline() vẽ đường ngang tại y = 0, dễ nhìn để xác định các biên lợi nhuận âm
- labs(): để ghi tiêu đề, scale_fill_brewer(palette = “Set2”): dùng bảng màu pastel Set2. them_minimal() và them() tạo giao diện cho hình,
1. agg10 <- HSG %>%
2. group_by(nam, `phan loai doanh thu`) %>%
3. summarise(LNSTCPP= sum(`LNSTCPP`, na.rm = TRUE), .groups = "drop")
4. ggplot(agg10, aes(x =nam, y = LNSTCPP, fill = `phan loai doanh thu`)) +
5. geom_area(alpha = 0.12, position = "identity") +
6. geom_line(aes(color = `phan loai doanh thu`), linewidth = 0.8) +
7. geom_point(size = 1.8) +
8. geom_smooth(method = "loess", se = TRUE, linetype = "dashed") +
9. geom_ribbon(aes(ymin = pmax(0, LNSTCPP - LNSTCPP*0.08),
10. ymax = LNSTCPP + LNSTCPP*0.08),alpha = 0.05) +
11. facet_wrap(~ `phan loai doanh thu`, scales = "free_y") +
12. labs(
13. title = "Xu hướng LNSTCPP theo phân loại thị trường",
14. subtitle = "1T = 1 nghìn tỷ",
15. x = "Năm",
16. y = "Lợi nhuận sau thuế chưa phân phối") +
17. scale_x_continuous(breaks = scales::breaks_pretty(n = 3))+
18. scale_x_continuous(breaks = scales::breaks_pretty(n = 3)) +
19. scale_y_continuous(
20. labels = function(x) paste0(round(x / 1e12, 2), " T"),
21. expand = expansion(mult = c(0, 0.1))) +
22. theme_minimal(base_size = 11) +
23. theme(legend.position = "none",
24. plot.title = element_text(face = "bold", hjust = 0.5),
25. plot.subtitle = element_text(hjust = 0.5))
>Nhận xét: Biểu đồ thể hiện đường xu hướng sự thay
đổi của lợi nhuận sau thuế chưa phân phối qua các năm trong từng nhóm
doanh thu để phản ánh khả năng tích lũy lợi nhuận và hiệu quả kinh doanh
theo nhóm doanh thu. Trong nhóm doanh thu tốt, lợi nhuận chạy từ mức
4.500 tỷ đến 6.000 tỷ, cho thấy doanh thu tốt nên kéo theo lợi nhuận
tốt. Trong nhóm doanh thu ổn, lợi nhuận khoảng từ hơn 1.000 tỷ đến gần
4.000 tỷ, cần duy trì vì nhiều năm tập trung trong mức doanh thu an toàn
này. Và tại loại doanh thu yếu, với lợi nhuận sau thuế khoảng 1.500 tỷ,
doanh nghiệp cần tối ưu chi phí hoặc thay đổi sản phẩm.
Giải thích:
Dòng 1: Tạo bảng agg10 mới để tổng hợp LNSTCPP theo năm và phân loại doanh thu- Dòng 4: khởi tạo biểu đồ
- Dòng 5:geom_area(): vẽ vùng diện tích (area chart) biểu diễn xu hướng, độ trong suốt 12%. Dòng 6: Vẽ đường nối biểu diễn xu hướng lợi nhuận theo từng nhóm
- Dòng 7: geom_point(): Vẽ các điểm dữ liệu thực tế theo từng năm.
- Dòng 8: geom_smooth(): làm mượt đường xu hướng, hiển thị vùng tin cậy xung quanh đường mượt, và vẽ kiểu nét đứt để phân biệt với đường dữ liệu thật
- Dòng 9: geom_ribbon(aes(ymin = pmax(0, TotalCost - TotalCost0.08),ymax = TotalCost + TotalCost0.08), alpha = 0.05): Tạo vùng mờ cộng trừ 8% quanh đường chính, là đường dao động nhỏ
- Dòng 11: facet_wrap(~ phan loai doanh thu, scales = “free_y”): Chia biểu đồ thành nhiều khung nhỏ, mỗi khung ứng với một nhóm doanh thu, scales = “free_y”: mỗi khung có trục Y riêng.
1. ggplot(HSG, aes(x = nam)) +
2. geom_ribbon(aes(ymin = 0, ymax = `luu chuyen tien thuan`),
3. fill = "#00BFC4", alpha = 0.4) +
4. geom_ribbon(aes(ymin = 0, ymax = ` tien thu di vay`), fill = "#F8766D", alpha = 0.3) +
5. geom_line(aes(y = `luu chuyen tien thuan`), color = "#00BFC4", linewidth = 1.2) +
6. geom_line(aes(y = ` tien thu di vay`), color = "#F8766D", linewidth = 1.2) +
7. geom_point(aes(y = ` tien thu di vay`), color = "#F8766D", size = 3) +
8. geom_text(aes(y = ` tien thu di vay`,
9. label = label_number(
10. scale_cut = cut_short_scale(),
11. accuracy = 0.1,
12. big.mark = ".",
13. decimal.mark = ",")(` tien thu di vay`)),
14. vjust = 3, color = "#F8766D", size = 3.5)+
15. scale_x_continuous(
16. breaks = unique(HSG$nam),
17. labels = unique(HSG$nam)) +
18. scale_y_continuous(
19. labels = scales::label_number(big.mark = ".", decimal.mark = ",")) +
20. scale_y_continuous(
21. labels = scales::label_number(scale_cut = scales::cut_short_scale()))+
22. theme_minimal(base_size = 11.5) +
23. labs(title = "Dòng tiền và Khoản vay theo năm",
24. subtitle = "1T = 1 nghìn tỷ, đường đỏ: Khoản vay | đường xanh: dòng tiền",
25. x = "Năm", y = "Giá trị") +
26. theme(legend.position = "none")
>Nhận xét: Nhìn ở năm 2017, 2018 và 2021 các khoản
vay tăng mạnh, cho thấy doanh nghiệp phụ thuộc vào vốn vay trong những
năm này. Còn ở năm 2019 và 2023 thì có thể lúc này đang thắt chặt tài
chính nên khoản vay giảm. Đến 2024, khoản vay tăng lại, thể hiện dấu
hiệu doanh nghiệp quay lại tăng trưởng, nhưng cần theo dõi áp lực lãi
vay. Còn màu xanh là dòng tiền có xu hướng thấp, thập chí âm nhẹ ở vài
năm, chứng tỏ lợi nhuận tiền mặt chưa cao. Có thể do đầu tư tài sản, mở
rộng sản xuất, nên tiền bị “chôn” tạm thời. Giai đoạn 2019–2021 dòng
tiền dương hơn, tương ứng doanh nghiệp vận hành hiệu quả hơn, có khả
năng tự tài trợ.
Giải thích:
- Dòng 1: khởi tạo biểu đồ
- Dòng 2: geom_ribbon(aes(ymin = 0, ymax =luu chuyen tien thuan), fill = “#00BFC4”, alpha = 0.4): Tạo vùng bóng mờ (ribbon) biểu diễn dòng tiền thuần từ 0 đến giá trị thực. Dòng 4: geom_ribbon(aes(ymin = 0, ymax = tien thu di vay), fill = “#F8766D”, alpha = 0.3): tương tự lưu chuyển tiền tệ, là biến tiền thu đi vay
- Dòng 5,6: geom_line(): Vẽ đường màu trùng với vùng phía dưới
- Dòng 7: geom_point(aes(y = tien thu di vay), color = “#F8766D”, size = 3): Đặt chấm tròn đỏ tại vị trí các điểm dòng tiền vay theo năm. Giúp biểu đồ sinh động và dễ nhìn mốc dữ liệu cụ thể.
- Dòng 8: geom_text() Gắn nhãn giá trị cho từng điểm khoản vay, dùng label_number() để rút gọn đơn vị (T), có dấu phẩy và dấu chấm ngăn cách rõ ràng.
- theme_minimal(): và tùy chỉnh bố cục. labs() : thêm tiêu đề, phụ đề, và nhãn trục.
1. library(ggrepel)
2. step_data_2 <- HSG %>%
3. mutate(
4. thudai_trieu = `cac khoan phai thu dai han` / 1e12,
5. thungan_Trieu = `cac khoan phai thu ngan han` / 1e12)
6. ggplot(step_data_2, aes(x=nam, y = thungan_Trieu)) +
7. geom_step(color = "#0072B2", linewidth = 1.3) +
8. geom_ribbon(aes(ymin = 0, ymax = thungan_Trieu), fill = "#0072B2", alpha = 0.2) +
9. geom_step(aes(y = thudai_trieu), color = "#E69F00", linewidth = 1, linetype = "dashed") +
10. geom_point(color = "red", size = 3, shape = 21, fill = "white") +
11. geom_text_repel(aes(label = paste0(comma(thungan_Trieu,
12. big.mark = ".", decimal.mark = ".")," tỷ")),
13. nudge_y = 0.05 * max(step_data_2$thungan_Trieu, na.rm = TRUE),
14. size = 3, color = "black", box.padding = 0.4, max.overlaps = Inf) +
15. scale_x_continuous(
16. breaks = unique(step_data_2$nam), # chỉ hiển thị đúng các năm có dữ liệu
17. labels = as.character(unique(step_data_2$nam)))+
18. scale_y_continuous(labels = label_number(big.mark = ".", decimal.mark = ",")) +
19. theme_minimal(base_size = 13) +
20. labs(
21. title = "Biểu đồ BẬC THANG – Các khoản phải thu ngắn - dài hạn",
22. subtitle = "Đường xanh: Dài hạn | Đường cam: Ngắn hạn",
23. x = "Năm", y = "Giá trị (tỷ đồng)")+
24. theme(
25. plot.title = element_text(face = "bold", size = 15),
26. plot.subtitle = element_text(size = 12, color = "gray30"),
27. legend.position = "none")
> Nhận xét: các khoản thu ngắn hạn (đường cam), gần
như ổn định và thấp, dao động tầm 0.5-0.8 tỷ đồng, điều này cho thấy
rằng công ty kiểm soát tốt các khoản thu ngắn hạng, không tồn động nợ
xấu. Tuy nhiên các khoản thu dài hạn thì biến động mạnh, từ 1.828 tỷ
(2015) lên đỉnh 11.898 tỷ (2021). Đặc biệt tăng mạnh ở những năm
2017–2021: công ty có thể đã mở rộng tín dụng dài hạn, cho khách hàng
vay dài hơn, hoặc ký các hợp đồng lớn, đầu tư dài hạn vào khách hàng.
Khoản phải thu ngắn hạn thấp nên thanh khoản ngắn hạn an toàn.Khoản phải
thu dài hạn cao có thể do rủi ro nếu khách hàng không trả đúng hạn.
Giải thích:
- Dòng 2: Tạo biến mới để rút ngắn số
- Dòng 6: khởi tạo biểu đồ
- Dòng 7: geom_step(): Vẽ đường bậc thang.
- Dòng 8: geom_ribbon(): Tô nền dưới đường ngắn hạn bằng màu xanh nhạt
- Dòng 9: geom_step(): hêm đường bậc thang màu cam, nét đứt biểu diễn phải thu dài hạn. Hai đường giúp so sánh cấu trúc giữa ngắn hạn và dài hạn.
- Dòng 10: Thêm điểm dữ liệu tại các năm, nổi bật bằng màu đỏ và viền trắng.
- Dòng 14: geom_text_repel(): ghi giá trị từng năm trên biểu đồ để tránh trùng lặp nhãn, comma(): để format số với dấu ngăn cách hàng nghìn, hiện thị đơn vị triệu đồng.
- theme_minimal(): và tùy chỉnh bố cục. labs() : thêm tiêu đề, phụ đề, và nhãn trục
1. # 1. Chuẩn hóa data dạng long
2. HSG_profit <- HSG %>%
3. select(nam, LNSTCPP = `LNSTCPP`, DoanhThu = `doanh thu ban hang`)
4. df_long <- HSG_profit %>%
5. pivot_longer(cols = c(LNSTCPP, DoanhThu),
6. names_to = "ChiTieu", values_to = "giatri")
7. # 2. Tạo hàm đặt kiểu linetype và tên nhãn
8. ChiTieu_linetype <- c("LNSTCPP" = "dotted", "doanh thu ban hang" = "solid")
9. ChiTieu_label <- c("LNSTCPP" = "LNSTCPP (nét đứt)", "doanh thu ban hang" = "Doanh thu (nét liền)")
10. ChiTieu_color <- c("LNSTCPP" = "#6d6875", "doanh thu ban hang" = "#b5838d")
11. ChiTieu_fill <- c("LNSTCPP" = "#f8bbd0", "doanh thu ban hang" = "#cebbf7")
1. library(ggplot2)
2. library(ggrepel)
3. # Lấy dòng LNSTCPP lớn nhất để làm label
4. label_LNSTCPP <- HSG_profit %>% filter(LNSTCPP == max(LNSTCPP, na.rm = TRUE)) %>% mutate(LabelType = "Đỉnh lợi nhuận")
5. # Tương tự với DoanhThu
6. label_DoanhThu <- HSG_profit %>% filter(DoanhThu == max(DoanhThu, na.rm = TRUE)) %>% mutate(LabelType = "Đỉnh doanh thu")
7. ggplot(HSG_profit, aes(x = nam)) +
8. geom_ribbon(
9. aes(ymin = pmin(LNSTCPP, DoanhThu), ymax = pmax(LNSTCPP, DoanhThu)),
10. fill = "#d1e7dd", alpha = 0.38) +
11. geom_line(aes(y = LNSTCPP, color = "LNSTCPP", linetype = "LNSTCPP"), size = 2.3) +
12. geom_line(aes(y = DoanhThu, color = "DoanhThu", linetype = "DoanhThu"), size = 2.3) +
13. geom_point(aes(y = LNSTCPP, fill = "LNSTCPP"), size = 4.2, shape = 21, color = "#495057") +
14. geom_point(aes(y = DoanhThu, fill = "DoanhThu"), size = 4.2, shape = 21, color = "#495057") +
15. ggrepel::geom_label_repel(
16. data = label_LNSTCPP,
17. aes(x = nam, y = LNSTCPP, label = paste0(comma(LNSTCPP, big.mark = ".", decimal.mark = ","), "\n", LabelType)),
18. family = "Arial", fontface = "bold", fill = "#f8bbd0", color = "#6d6875", size = 4.3,
19. box.padding = 0.33, point.padding = 0.6, min.segment.length = 0.2, max.overlaps = 8,
20. inherit.aes = FALSE) +
21. ggrepel::geom_label_repel(
22. data = label_DoanhThu,
23. aes(x = nam, y = DoanhThu, label = paste0(comma(DoanhThu, big.mark = ".", decimal.mark = ","), "\n", LabelType)),
24. family = "Arial", fontface = "bold", fill = "#cebbf7", color = "#b5838d", size = 4.3,
25. box.padding = 0.33, point.padding = 0.6, min.segment.length = 0.2, max.overlaps = 8,
26. inherit.aes = FALSE) +
27. scale_color_manual(
28. values = c("LNSTCPP" = "#6d6875", "DoanhThu" = "#b5838d"),
29. labels = c("LNSTCPP" = "LNSTCPP (nét đứt)", "DoanhThu" = "Doanh thu (nét liền)"),
30. name = "Chỉ tiêu") +
31. scale_fill_manual(
32. values = c("LNSTCPP" = "#f8bbd0", "DoanhThu" = "#cebbf7"),
33. labels = c("LNSTCPP" = "LNSTCPP (nét đứt)", "DoanhThu" = "Doanh thu (nét liền)"),
34. name = "Chỉ tiêu") +
35. scale_linetype_manual(
36. values = c("LNSTCPP" = "dotted", "DoanhThu" = "solid"),
37. labels = c("LNSTCPP" = "LNSTCPP (nét đứt)", "DoanhThu" = "Doanh thu (nét liền)"),
38. name = "Chỉ tiêu") +
39. labs(
40. title = "Biến động LNSTCPP & Doanh thu",
41. x = "Năm", y = "Giá trị") +
42. theme_minimal(base_size = 10, base_family = "Arial") +
43. theme(
44. plot.title = element_text(face = "bold", size = 18, hjust = 0.5),
45. legend.position = "bottom",
46. legend.title = element_text(size = 13, face = "bold", family = "Arial"),
47. legend.text = element_text(size = 13, family = "Arial"),
48. legend.key.width = unit(2.5, "lines"),
49. legend.key.height = unit(1.3, "lines")) +
50. scale_y_continuous(labels = label_number(big.mark = ".")) +
51. scale_x_continuous(breaks = HSG$nam, labels = HSG$nam)
>Nhận xét: Biểu đồ “Biến động LNSTCPP & Doanh
thu bán hàng theo năm” cho thấy doanh nghiệp có tốc độ tăng trưởng doanh
thu khá ấn tượng, với các giá trị cao nhất nằm ở giai đoạn 2020–2022.
Tuy nhiên, lợi nhuận sau thuế chưa phân phối lại không tăng tương ứng,
thậm chí có sự chênh lệch đáng kể giữa hai chỉ tiêu này ở hầu hết các
năm. Việc doanh thu đạt đỉnh nhưng LNSTCPP vẫn còn ở mức chưa cao cho
thấy doanh nghiệp cần tiếp tục tối ưu hóa các chi phí vận hành, kiểm
soát hiệu quả tài chính, cũng như nâng cao khả năng chuyển hóa doanh thu
thành lợi nhuận thực sự tích lũy cho cổ đông.
Giải thích:
- Dòng 7: Khởi tạo biểu đồ.
- Dòng 8: geom_ribbon(): Vẽ vùng tô màu giúp làm nổi bật phạm vi chênh lệch giữa hai chỉ tiêu LNSTCPP và Doanh thu qua các năm. Ribbon màu nhạt tốt cho nhìn tổng quan biên động dòng tiền hoặc lợi nhuận so với doanh thu.
- Dòng 11, 12: geom_line():Vẽ đường thể hiện biến động LNSTCPP theo năm,
- Dòng 13 - 14: Thêm điểm đánh dấu tại mỗi năm để biểu đồ trực quan hơn.
- Dòng 15: ggrepel::geom_label_repel() gắn nhãn nổi bật cho các giá trị lớn nhất, nhỏ nhất và năm cuối của LNSTCPP và Doanh thu. Việc dùng ggrepel giúp nhãn không bị đè lên nhau và không che khuất dữ liệu.
1. library(ggplot2)
2. library(scales)
3. format_tien_ty <- function(x, digits = 1){
4. paste0(round(x / 1e12, digits = digits) %>%
5. format(big.mark = ".", decimal.mark = ","), " T")}
6. ggplot(HSG, aes(x = nam, y = `loi nhuan thuan`)) +
7. geom_step(color = "#FF99C8", linewidth = 2.1, direction = "hv") +
8. geom_text_repel(
9. aes(label = format_tien_ty(`loi nhuan thuan`, digits = 2)),
10. size = 4,
11. nudge_y = 0.02 * max(HSG$`loi nhuan thuan`, na.rm = TRUE),direction = "y",
12. segment.color = "gray50", segment.size = 0.5, max.overlaps = Inf) +
13. geom_point(size = 3, fill = "#B9FBC0", color = "#FF99C8", shape = 21) +
14.
15. scale_x_continuous(
16. breaks = HSG$nam,
17. labels = as.character(HSG$nam)) +
18.
19. scale_y_continuous(
20. labels = function(x) paste0(round(x / 1e12, 2), " T"),
21. expand = expansion(mult = c(0, 0.13))) +
22.
23. labs(
24. title = "Lợi nhuận thuần bậc thang từng năm",
25. x = "Năm",
26. y = "Giá trị") +
27. theme_light(base_family = "Arial", base_size = 11) +
28. theme(
29. plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
30. axis.text.x = element_text(margin = margin(t = 17)),
31. plot.margin = margin(t = 20, r = 40, b = 120, l = 30)) +
32. coord_cartesian(clip = "off")
>Nhận xét: Biểu đồ “Lợi nhuận thuần bậc thang từng
năm” thể hiện xu hướng biến động rất mạnh mẽ của lợi nhuận thuần theo
từng năm giai đoạn 2015–2024. Trong giai đoạn 2015–2017, lợi nhuận thuần
ổn định nhưng ở mức thấp, phản ánh giai đoạn hồi phục hoặc tích lũy sau
khủng hoảng trước đó. Đặc biệt, năm 2021 ghi nhận mức tăng đột biến lên
trên 4,9 nghìn tỷ, cho thấy doanh nghiệp đạt được cú hích lớn về lợi
nhuận, có thể nhờ vào bối cảnh thuận lợi, các chính sách hỗ trợ, hoặc sự
chuyển biến mạnh về doanh thu. Tuy nhiên, sau đỉnh cao năm 2021–2022,
lợi nhuận lại giảm sâu vào năm 2023 và chỉ hồi phục nhẹ năm 2024, chứng
tỏ chu kỳ kinh doanh có tính biến động, dễ bị tác động bởi các nhân tố
bên ngoài như thị trường, dịch bệnh, chi phí đầu vào hoặc thay đổi chiến
lược.
Giải thích:
- Dòng 1: Khởi tạo biểu đồ
- Dòng 7: geom_step() vẽ đường bậc thang cho biến động dòng tiền qua thời gian
- Dòng 8: geom_text_repel(): thêm nhãn giá trị cho từng điểm
- Dòng 13: geom_point() Thêm chấm tròn lớn lên mỗi giá trị năm trong chuỗi.
- Dòng 15–17: scale_x_continuous(): Hiển thị đầy đủ các năm trong dữ liệu
- Dòng 19: Định dạng số theo đơn vị “T” (nghìn tỷ), làm tròn hai số
- labs(): Đặt tiêu đề lớn, tên trục x, y ,light(base_family=“Arial”, base_size=15)
- theme() Tạo giao diện cho biểu đồ
- Dòng 32: coord_cartesian(clip = “off”) Cho phép các nhãn và điểm vẽ vượt ra ngoài vùng chart mà không bị cắt, tăng thẩm mỹ và bảo toàn toàn bộ thông tin.
1. df_group <- HSG %>%
2. select(nam, TSCD, `von co phan`) %>%
3. pivot_longer(-nam, names_to = "Chitieu", values_to = "giatri") %>%
4. mutate(
5. Chitieu = recode(Chitieu, TSCD = 'TSCĐ', `von co phan` = 'Vốn cổ phần')) %>%
6. group_by(nam) %>%
7. mutate(la_max = giatri == max(giatri)) %>%
8. ungroup()
Giải thích:
- Dòng 2:
select(nam, TSCD, von co phan): Chỉ lấy các biến cần phân tích, giúp đơn giản hóa dataset và tăng tính tối ưu cho vẽ nhóm bar.- Dòng 3:
pivot_longer(-nam, ...): Chuyển từ dạng bảng ngang, mỗi năm một dòng, hai chỉ tiêu là hai cột TSCD/tien thành bảng dọc: mỗi dòng là một giá trị “năm - chỉ tiêu - giá trị”. Cần thao tác này vì ggplot2 hoạt động trực quan nhất với dữ liệu “long format”, đặc biệt khi vẽ bar nhóm.- Dòng 4:
mutate(Chitieu = recode(...)): Đổi tên tiếng Việt dễ đọcla_max = giatri == max(giatri): Đánh dấu trong từng năm dòng nào là lớn nhất (TRUE). Thao tác này sau khigroup_bynăm sẽ cho đúng logic: duy nhất bar giá trị lớn nhất mỗi năm mới TRUE. Dùng để tạo hiệu ứng nhãn số nổi bật.
1. ggplot(df_group, aes(x = nam, y = giatri, fill = Chitieu)) +
2. geom_col(position = position_dodge(width = 0.7), width = 0.55, color = "#dee2e6", alpha = 0.85) +
3. geom_text(aes(
4. label = scales::comma(giatri, big.mark = ".", decimal.mark = ","),
5. hjust = ifelse(la_max, 1.1, 0)),
6. position = position_dodge(width = 0.7),
7. nudge_y = 0.5, size = 2.4, fontface = "bold", family = "Arial") +
8. geom_vline(xintercept = unique(df_group$nam) + 0.5, color = "gray87", linetype = "dotted") +
9. scale_fill_manual(values = c("TSCĐ" = "#B5179E", "Vốn cổ phần" = "#48CAE4")) +
10. scale_x_continuous(breaks = unique(df_group$nam)) +
11. labs(title = "So sánh TSCD với vốn cổ phần từng năm",
12. x = "Năm", y = "Giá trị", fill = "Chỉ tiêu") +
13. theme_minimal(base_size = 9, base_family = "Arial") +
14. theme(
15. plot.title = element_text(face = "bold", size = 13, hjust = 0.5),
16. legend.position = "bottom",
17. plot.margin = margin(r = 40)) +
18. coord_flip()+ scale_y_continuous(labels = label_number(big.mark = "."))
>Nhận xét: Biểu đồ so sánh tài sản cố định và vốn cổ
phần theo từng năm cho thấy vốn cổ phần luôn chiếm tỷ trọng vượt trội so
với TSCĐ trong cơ cấu tài sản doanh nghiệp. Sự gia tăng liên tục và ổn
định của vốn cổ phần trong các năm gần đây khẳng định chiến lược tăng
cường huy động vốn chủ sở hữu nhằm mở rộng quy mô hoạt động. Trong những
năm 2015-2017, đầu tư vào tài sản cố định luôn cao hơn vốn cổ phần, điều
này có nghĩa là doanh nghiệp không chỉ dùng vốn cổ đông, mà còn vay thêm
hoặc sử dụng nguồn vốn bên ngoài. Ở những năm 2018 trở đi, vốn cổ phần
luôn chiếm tỉ trọng hơn, cho thấy doanh nghiệp dần đi vào ổn định, ít lệ
thuộc vào các khoản nợ.
Giải thích:
- Dòng 1: Khởi tạo biểu đồ
- Dòng 2, 3, 8: Vẽ biểu đồ cột nhóm, thêm nhãn số trên cột và thêm đường chia dọc giữa các năm màu xám nhạt.
- Dòng 9: tô màu cho biến. Dòng 10: hiện thị các năm trên trục X.
- labs(): Tạo tiêu đề và chú thích nhóm màu bar, theme_minimal()+theme() : tạo giao diện cho biểu đồ
- Dòng 18: coord_flip() Xoay chart từ dọc (vertical) sang ngang (horizontal), giúp đọc năm và số rõ ràng số nhiều.
1. df2 <- HSG %>%
2. select(nam, `vay va no thue tai chinh`, ` tien thu di vay`) %>%
3. pivot_longer(-nam, names_to = "KhoanMuc", values_to = "giatri") %>%
4. mutate(nam = as.factor(nam),
5. KhoanMuc = recode(KhoanMuc,
6. "vay va no thue tai chinh" = "Vay nợ thuê tài chính",
7. "tien thu di vay" = "Tiền thu đi vay"))
8. label_points <- df2 %>%
9. group_by(KhoanMuc) %>%
10. filter(giatri == max(giatri) | giatri == min(giatri)) %>%
11. ungroup()
Giải thích:
select(...): Lấy ra 3 cột cần thiết là ‘nam’, ‘vay va no thue tai chinh’, ‘tien thu di vay’.pivot_longer(-nam, ...): Chuyển dữ liệu từ wide sang long, gom hai biến về một cột “KhoanMuc”, giá trị về cột “giatri” để dễ biểu diễn dạng nhóm.mutate(..., ...): Chuyển ‘nam’ thành factor giúp nhóm theo trục x tốt hơn khi là barplot. Đổi tiếng Việt có dấu cho các tên khoản mục (dễ nhìn hơn khi vẽ).group_by(KhoanMuc): Nhóm theo từng khoản mục để lọc giá trị max/min mỗi nhóm.filter(...max... | ...min...): Lấy ra dòng có giá trị lớn nhất và nhỏ nhất của từng nhóm (chỉ hiện nhãn số trên bar cao/thấp nhất).ungroup(): Bỏ group-by để trả về bảng thường.
1. ggplot(df2, aes(x = nam, y = giatri, fill = KhoanMuc)) +
2. geom_col(position = "dodge", width = 0.6, alpha = 0.64) +
3. geom_text(
4. data = label_points,
5. aes(label = paste0(round(giatri / 1e12, 2), " T")),
6. position = position_dodge(width = 0.6),
7. vjust = -0.5, size = 2.9, fontface = "bold",mcolor = "#B5179E") +
8. geom_line(aes(group = KhoanMuc), position = position_dodge(width = 0.6), size = 0.9) +
9. geom_point(aes(y = giatri), position = position_dodge(width = 0.6), size = 1.5) +
10. geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
11. scale_fill_brewer(palette = "Accent") +
12. scale_y_continuous(
13. labels = function(x) paste0(round(x / 1e12, 2), " T"), # rút gọn tỷ đồng
14. expand = expansion(mult = c(0, 0.13))) +
15. labs(
16. title = "Vay nợ thuê tài chính & Tiền thu đi vay từng năm",
17. x = "Năm", y = "Giá trị (1T = 1 nghìn tỷ)", fill = "Khoản mục") +
18. theme_minimal(base_size = 11) +
19. theme(
20. plot.title = element_text(face = "bold", size = 13, hjust = 0.5),
21. axis.text.x = element_text(size = 9),
22. axis.text.y = element_text(size = 9),
23. legend.position = "bottom")
Nhận xét: Biểu đồ cho thấy trong giai đoạn 2015–2024, khoản mục “Tiền thu đi vay” chiếm tỷ trọng vượt trội so với “Vay nợ thuê tài chính”. Khoản tiền thu đi vay liên tục tăng mạnh và duy trì ở mức cao trong các năm 2018–2021, đặc biệt năm 2021 đạt đỉnh. Điều này phản ánh doanh nghiệp chủ động mở rộng quy mô vốn hoạt động bằng cách khai thác nguồn tài chính bên ngoài, đẩy mạnh các hoạt động đầu tư hoặc mở rộng sản xuất kinh doanh. Năm 2021 với tiền thu đi vay đạt đỉnh tại 38,25 nghìn tỷ, nhưng mức vay và nợ thuê tài chính ở mức khá thấp, cho thấy doanh nghiệp có khả năng tài chính tự chủ cao, ít phụ thuộc ngân hàng hay nhà đầu tư bên ngoài.
Giải thích:
- Dòng 1: Khởi tạo biểu đồ
- Dòng 2 , 3: Vẽ biểu đồ cột và gắn nhãn
- Dòng 8, 9: Thêm đường nối giữa các cột và điểm đánh dấu thể hiện xu hướng theo năm. Dòng 10: Thêm đường ngang tại giá trị 0 để biểu đồ có điểm tham chiếu trực quan hơn.
- labs(): tiêu đề cho biểu đồ., nhãn trục và chú thích màu (“Khoản mục”).
- theme( ): Theme tối giản của ggplot2, giữ chart gọn,Style cho từng phần: tiêu đề đậm, cỡ lớn, căn giữa; chữ ở trục và chú thích vừa đẹp. Đặt chú thích màu/bar ở phía dưới chart.
1. nam_moi <- max(HSG$nam)
2. df3 <- HSG %>%
3. filter(nam == nam_moi) %>%
4. select(`cac khoan phai thu dai han`, tien, TSCD) %>%
5. pivot_longer(everything(), names_to = "KhoanMuc", values_to = "giatri") %>%
6. mutate(KhoanMuc = recode(KhoanMuc,
7. "cac khoan phai thu dai han" = "Phải thu dài hạn",
8. "tien" = "Tiền mặt",
9. "TSCD" = "Tài sản cố định"),
10. tyle = giatri / sum(giatri))
Giải thích:
nam_moi <- max(HSG$nam): Dòng này lấy ra năm lớn nhất trong dữ liệu (tức là năm mới nhất hiện có).filter(nam == nam_moi): Chỉ giữ lại dữ liệu của năm mới nhất.select(...): Chọn đúng ba loại tài sản cần phân tích tỉ trọng.pivot_longer(...): “Kéo” dữ liệu từ dạng bảng ngang sang bảng dọc (mỗi dòng là một tài sản - cần cho pie chart).mutate(KhoanMuc = recode(...)): Đổi tên từng loại tài sản thành tiếng Việt dễ đọc trên chart.mutate(tyle = giatri / sum(giatri)): Tính tỉ trọng từng loại tài sản trên tổng tài sản, dùng làm giá trị y cho pie chart
1. pie_colors <- c("Phải thu dài hạn" = "#A3CEF1", "Tiền mặt" = "#FFC8DD", "Tài sản cố định" = "#B9FBC0")
2. ggplot(df3, aes(x = "", y = tyle, fill = KhoanMuc)) +
3. geom_col(width = 1, color = "gray95") +
4. coord_polar(theta = "y") +
5. geom_text(aes(label = scales::percent(tyle, accuracy = 0.1)),
6. position = position_stack(vjust = 0.66), size = 4, family = "Arial", fontface = "bold", color = "#333") +
7. scale_fill_manual(values = pie_colors) +
8. theme_void(base_family = "Arial") +
9. labs(title = paste("Tỷ trọng tài sản năm", nam_moi), fill = "Khoản mục") +
10. theme(plot.title = element_text(face = "bold", size = 18, hjust = 0.5),
11. legend.position = "right",
12. legend.title = element_text(size = 15, face = "bold"))
Nhận xét: Biểu đồ tròn về “Tỷ trọng tài sản chính năm 2024” cho thấy tài sản cố định chiếm ưu thế tuyệt đối trong cơ cấu tài sản của doanh nghiệp, với tỷ lệ lên tới 82.8%. Điều này phản ánh chiến lược tập trung đầu tư dài hạn vào tài sản sản xuất hoặc cơ sở hạ tầng. Tiền mặt đứng thứ hai với 12.6%, cho thấy doanh nghiệp vẫn duy trì mức thanh khoản hợp lý để đảm bảo các hoạt động giao dịch, phòng ngừa rủi ro và tận dụng cơ hội đầu tư ngắn hạn khi cần thiết. Phải thu dài hạn chỉ chiếm 4.5%, hàm ý doanh nghiệp kiểm soát tốt các khoản phải thu và giảm thiểu rủi ro liên quan đến công nợ.
Giải thích:
- Dòng 1: Khởi tạo biểu đồ
- Dòng 2: geom_col() Vẽ cột nhóm; các nhóm cách nhau 0.7. Dòng 3: Thêm nhãn giá trị lên cột. Dòng 8: Thêm đường kẻ dọc chấm mờ giữa các năm để tách nhóm, giúp dễ đọc hơn.
- Dòng 9: Tô màu cho từng chỉ tiêu. Dòng 10: Hiển thị các năm lên trục X.
- theme_void(base_family = “Arial”) và theme(): Tạo giao diện cho biểu đồ. labs(): Tạo tiêu đề và chú thích
- Dòng 18: coord_flip()Lật trục (trục X thành dọc, trục Y thành ngang) giúp dễ so sánh. Định dạng trục Y có dấu “.” làm dấu phân tách hàng nghìn
1. library(RColorBrewer)
2. years <- sort(unique(HSG$nam))
3. n_years <- length(years)
4. palette_paired <- colorRampPalette(brewer.pal(12, "Paired"))(n_years)
years <- sort(unique(HSG$nam)): Lấy danh sách tất cả năm duy nhất, sắp xếp tăng dần, đảm bảo các đánh dấu/legend trùng khớp dữ liệu.n_years <- length(years): Xác định số lượng năm để phối màu động, đảm bảo mỗi năm một màu riêng.palette_paired <- colorRampPalette(brewer.pal(12, "Paired"))(n_years): Sử dụng hàm colorRampPalette phối đủ màu cho từng năm bằng bộ Paired (12 màu gốc), màu sẽ tươi trẻ và không bị trùng kể cả số năm > 7.
1. ggplot(HSG, aes(x = `von co phan`, y = `loi nhuan gop`, color = as.factor(nam))) +
2. geom_point(size = 4, alpha = 0.7, position = position_jitter(width = 0.5)) +
3. geom_smooth(method = "lm", se = FALSE, color = "#E09EA6", size = 1.2) +
4. scale_x_continuous(
5. labels = scales::comma_format(big.mark = "."),
6. expand = expansion(mult = c(0.12, 0.16)),
7. breaks = pretty(HSG$`von co phan`, n = 7) ) +
8. scale_y_continuous(labels = scales::comma_format(big.mark = ".")) +
9. scale_color_manual(
10. name = "Năm",
11. values = setNames(palette_paired, years)) +
12. labs(
13. title = "Vốn cổ phần và Lợi nhuận gộp",
14. x = "Vốn cổ phần (VNĐ)", y = "Lợi nhuận gộp (VNĐ)") +
15. theme_minimal(base_size = 11) +
16. theme(
17. plot.title = element_text(face = "bold", size = 13, hjust = 0.5),
18. axis.text.x = element_text(size = 9, angle = 25, vjust = 0.6),
19. axis.text.y = element_text(size = 9),
20. legend.position = "bottom",
21. legend.text = element_text(size = 9),
22. legend.title = element_text(size = 10, face = "bold"))
>Nhận xét: Biểu đồ “Vốn cổ phần và Lợi nhuận gộp”
cho thấy mối quan hệ tích cực giữa hai chỉ tiêu tài chính quan trọng của
doanh nghiệp qua các năm. Đường xu hướng tăng phản ánh rằng khi quy mô
vốn cổ phần được mở rộng, doanh nghiệp có điều kiện gia tăng hiệu quả
sản xuất kinh doanh, dẫn đến lợi nhuận gộp cũng tăng trưởng tương ứng.
Đặc biệt, những năm có vốn cổ phần lớn đi kèm lợi nhuận gộp cao đã chứng
minh chiến lược gia tăng vốn là lựa chọn hợp lý giúp nâng cao hiệu quả
kinh doanh. Tuy nhiên, một số năm dù vốn lớn nhưng lợi nhuận gộp chưa
đạt hiệu quả tối đa, hàm ý doanh nghiệp cần tối ưu hơn về cấu trúc chi
phí và hoạt động sản xuất để tận dụng tốt nhất nguồn vốn huy động. Nhìn
tổng thể, tăng vốn cổ phần vẫn là động lực chủ đạo thúc đẩy tăng trưởng
lợi nhuận gộp trong dài hạn.
Giải thích:
- Dòng 1: khởi tạo biểu đồ
- Dòng 2, 3: Biểu diễn điểm và đường xu thế.
- labs(title = “Vốn cổ phần và Lợi nhuận sau thuế”, x = “Vốn cổ phần (VNĐ)”, y = “Lợi nhuận sau thuế (VNĐ)”) Đặt tiêu đề chart, tên trục x/y chuẩn báo cáo kế toán.
- theme_minimal(base_size = 11) Layout nhẹ, giảm thông tin thừa, font size nhỏ giú gọn cho báo cáo.
- theme(… plot.margin = margin(…)) Tiêu đề to vừa phải, trục x/y nhỏ, legend nhỏ cho gọn chart, margins chuẩn để text và điểm không bị tràn ra ngoài hình khi chèn vào file báo cáo.
1. long_df <- HSG %>%
2. select(nam, `loi nhuan gop`, `loi nhuan thuan`) %>%
3. pivot_longer( cols = c(`loi nhuan gop`, `loi nhuan thuan`),
4. names_to = "chi_tieu", values_to = "gia_tri")
5. long_df <- long_df %>% mutate(
6. gia_tri_fmt = label_number(big.mark = ".", decimal.mark = ",")(gia_tri))
7. head(long_df)
Giải thích: HSG %>% select(...) chọn
ra 3 cột: nam, loi nhuan gop và loi nhuan thuan từ bảng HSG.
- %>% là toán tử pipe, truyền kết quả qua bước tiếp theo để dễ đọc và logic mạch lạc.
pivot_longer(cols = ..., names_to = ..., values_to = ...)chuyển dữ liệu từ dạng rộng (wide) sang dạng dài (long format).cols = ...chỉ định các cột bạn muốn gom lại thành một cột (ở đây là Hai chỉ tiêu lợi nhuận), names_to = “Chi_tieu”: tên mới cho cột lưu tên chỉ tiêu, values_to = “Gia_tri”: tên mới cho cột chứa giá trị các chỉ tiêu lợi nhuận. Kết quả sẽ là bảng mới, mỗi dòng là một năm, một chỉ tiêu (Lợi nhuận gộp hoặc Lợi nhuận thuần), và giá trị tương ứng.
1. ggplot(long_df, aes(x = factor(nam), y = gia_tri, fill = chi_tieu)) +
2. geom_col(position = "dodge", alpha = 0.9) +
3. geom_text(aes(label = scales::comma(gia_tri / 1e9, big.mark = ".", decimal.mark = ",")),
4. position = position_dodge(0.9),
5. hjust = 0.5, # nhãn bên trong thanh
6. color = "black",
7. size = 3.7) +
8. labs(
9. title = "So sánh lợi nhuận gộp & lợi nhuận thuần theo năm",
10. x = "Năm",
11. y = "Giá trị (1B = 1.000.000.000 VNĐ)",
12. fill = "Chỉ tiêu") +
13. scale_y_continuous(
14. labels = function(x) paste0(scales::number(x / 1e9, big.mark = ".", decimal.mark = ","), "B")) +
15. theme_minimal(base_size = 13) +
16. theme(
17. plot.title = element_text(face = "bold", size = 17),
18. legend.position = "bottom")+
19. coord_flip()
Nhận xét: Các năm gần đây, HSG duy trì mức lợi nhuận gộp trên 4.000-8.800 tỷ đồng, đặc biệt năm 2021 đạt đỉnh trên 8.800 tỷ đồng, nhưng lợi nhuận thuần thường chỉ thường thấp hơn lợi nhuận gộp (2021 đạt 3.917 tỷ, nhiều năm chỉ quanh mức 300-500 tỷ đồng). Kết quả này cho thấy công ty vẫn giữ được biên lợi nhuận sản xuất cao, tuy nhiên phần lớn lợi nhuận đã bị bào mòn bởi các khoản chi phí ngoài giá vốn. Từ năm 2022 trở lại đây, dù doanh thu và lợi nhuận gộp chỉ giảm nhẹ, nhưng lợi nhuận thuần về tay doanh nghiệp lại giảm sâu (năm 2023 chỉ 96 tỷ, năm 2024 là 510 tỷ), có thể đây dấu hiệu khó khăn về chi phí hoạt động, tài chính, hoặc ảnh hưởng từ biến động thị trường.
Giải thích:
- `Dòng 1: Khởi tạo biểu đồ
- Dòng 2: geom_col() vẽ cột nhóm, các cột của từng chỉ tiêu được đặt cạnh nhau
- Dòng 3: Thêm nhãn giá trị lên trên đầu mỗi cột.
- labs()Đặt tiêu đề, nhãn trục x, trục y và nhãn giải thích màu. theme_minimal(base_size = 13) + theme() Tạo giao diện cho biểu đồ
- Dòng 13: Định dạng trục y để các giá trị lớn hiển thị phân cách hàng nghìn bằng chấm.
library(readxl) library(dplyr) library(ggplot2) library(ggrepel)
library(tidyr) install.packages(“tinytex”) tinytex::install_tinytex()
tinytex::tinytex_root()
library(RColorBrewer) library(scales) library(tidyverse)
library(lubridate) library(scales) library(ggrepel)
library(cowplot)
library(viridis)