messenger_logo
Liên hệ qua Messenger
SciEco

Hướng dẫn phân tích và trực quan hóa dữ liệu cầu thủ nba bằng r với hoopr và ggplot2

I
IEFPA
Ngày viết: 26/08/2026

Phân tích số liệu thể thao hiện đại, đặc biệt là giải bóng rổ nhà nghề Mỹ NBA, là một trong những mảng ứng dụng trực quan và cuốn hút nhất của khoa học dữ liệu. Thay vì phải tải về các tệp tin bảng tính thủ công hoặc tự viết các bộ cào dữ liệu phức tạp, hệ sinh thái ngôn ngữ R cung cấp cho người dùng những công cụ mạnh mẽ để kết nối trực tiếp với nguồn dữ liệu thể thao uy tín. Chỉ với vài dòng mã lệnh đơn giản kết hợp giữa gói hoopR và bộ công cụ tidyverse, bạn hoàn toàn có thể trích xuất các thông số thi đấu chi tiết từ ESPN và tạo ra biểu đồ xếp hạng cầu thủ chuyên nghiệp.

Thiết lập môi trường và tải dữ liệu từ hoopR

Gói hoopR là cầu nối dữ liệu chuyên dụng, cho phép tải toàn bộ thông tin chi tiết từng trận đấu của giải đấu một cách nhanh chóng. Để bắt đầu, chúng ta cần nạp hai thư viện nền tảng là tidyverse phục vụ cho việc xử lý cấu trúc dữ liệu và hoopR để lấy thông số cầu thủ cho mùa giải gần nhất.

Hàm load_nba_player_box sẽ tải toàn bộ bảng thống kê cá nhân của từng lượt trận trong mùa giải 2023–2024.

1library(tidyverse)
2library(hoopR)
3nba_data <- hoopR::load_nba_player_box(seasons = 2024)

Xử lý và tính toán điểm số trung bình

Dữ liệu thô ban đầu chứa rất nhiều biến số và các dòng ghi nhận những cầu thủ không ra sân thi đấu. Để tìm ra mười cây ghi điểm xuất sắc nhất mùa giải, quy trình tiền xử lý đòi hỏi chúng ta phải lọc bỏ các trường hợp vắng mặt, gom nhóm dữ liệu theo từng cầu thủ cùng câu lạc bộ chủ quản, sau đó tính toán số trận ra sân và điểm số trung bình mỗi trận.

Đồng thời, để đảm bảo tính đại diện thống kê và loại bỏ những trường hợp mẫu nhỏ do thi đấu quá ít trận, tiêu chí lọc tối thiểu 30 trận được áp dụng trước khi sắp xếp và lấy ra 10 vị trí dẫn đầu.

1top_scorers <- nba_data %>%
2  filter(is.na(did_not_play) | did_not_play == FALSE | did_not_play == "FALSE") %>%
3  group_by(athlete_display_name, team_abbreviation) %>%
4  summarise(
5    games_played = n(),
6    avg_points = mean(points, na.rm = TRUE),
7    .groups = "drop"
8  ) %>%
9  filter(games_played >= 30) %>%
10  arrange(desc(avg_points)) %>%
11  slice_head(n = 10)

Xây dựng biểu đồ xếp hạng bằng ggplot2

Sau khi đã có bảng tổng hợp mười cầu thủ dẫn đầu, bước tiếp theo là chuyển đổi các con số thành biểu đồ cột nằm ngang trực quan bằng ggplot2. Việc đảo trục tọa độ giúp tên cầu thủ hiển thị rõ ràng, dễ đọc hơn so với dạng cột dọc truyền thống.

Các tham số đồ họa như nhãn giá trị điểm số được làm tròn một chữ số thập phân, khoảng đệm trục tọa độ và chủ đề tối giản giúp biểu đồ đạt tiêu chuẩn thẩm mỹ cao, phù hợp để xuất bản hoặc đưa vào báo cáo phân tích.

1ggplot(top_scorers, aes(
2  x = reorder(athlete_display_name, avg_points),
3  y = avg_points,
4  fill = team_abbreviation
5)) +
6  geom_col(fill = "steelblue") +
7  geom_text(aes(label = round(avg_points, 1)), hjust = -0.2, size = 4, color = "black") +
8  coord_flip() +
9  scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
10  labs(
11    title = "Top 10 NBA Scorers (2023–24)",
12    x = "Player",
13    y = "Avg Points per Game"
14  ) +
15  theme_minimal(base_size = 14) +
16  theme(
17    plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
18    axis.title = element_text(face = "bold"),
19    axis.text = element_text(size = 12),
20    axis.text.x = element_text(size = 10),
21    legend.position = "none"
22  )

Mở rộng không gian phân tích sang các chỉ số khác

Quy trình làm việc trên không chỉ giới hạn ở chỉ số ghi điểm mà còn có thể tùy biến linh hoạt cho nhiều khía cạnh chiến thuật khác nhau.

Bạn có thể dễ dàng thay đổi điều kiện phân tích theo các hướng:

Thay đổi ngưỡng số trận thi đấu

Điều chỉnh điều kiện lọc số trận tối thiểu để đánh giá độ ổn định của cầu thủ xuyên suốt mùa giải hoặc xem xét các mẫu nhỏ hơn cho các tân binh.

Phân tích chuỗi thời gian qua nhiều mùa giải

Thay đổi tham số mùa giải để so sánh hiệu suất thi đấu của các siêu sao qua từng năm khác nhau.

Đánh giá các chỉ số chuyên môn đa dạng

Thay thế biến điểm số bằng số lần kiến tạo, số lần bắt bóng bật bảng hoặc các thông số phòng ngự để có cái nhìn toàn diện về đóng góp của từng vị trí trên sân.

✨ Sự kết hợp giữa hoopR và ggplot2 mang lại một quy trình phân tích dữ liệu thể thao khép kín, từ khâu thu thập tự động, làm sạch theo chuẩn dữ liệu gọn gàng cho đến trực quan hóa chuyên sâu mà không cần rời khỏi môi trường R.

Thử thách ứng dụng dành cho bạn

Hãy áp dụng quy trình trên để tạo một biểu đồ thanh ngang hiển thị 10 cầu thủ có số lần kiến tạo trung bình mỗi trận cao nhất trong mùa giải 2023–2024 với điều kiện thi đấu tối thiểu 40 trận. Bạn sẽ cần thay đổi biến số nào trong hàm tính toán tổng hợp?


Bài viết khác
Trong hành trình phát triển các lệnh ước lượng chuyên sâu trong Stata, việc tích hợp mã nguồn từ ngôn ngữ khác như C, C++ hay Java mở ra một thế giới mới về hiệu suất và khả năng tùy biến. Một trong những kỹ thuật mạnh mẽ nhất là viết plugin — hay còn gọi là thư viện liên kết động (DLL) — để tận dụng sức mạnh của C trong môi trường Stata. Bài viết này là phần thứ hai trong chuỗi chuyên đề “Viết một lệnh ước lượng trong Stata”, tiếp nối bài trước về việc chuẩn bị viết plugin. Ở đây, chúng ta sẽ xây dựng một plugin C thực hiện chính xác các phép tính mà hàm mymean_work() trong tệp mymean11.ado đã làm. Mục tiêu không chỉ là minh họa cách giao tiếp giữa C và Stata, mà còn cung cấp một nền tảng vững chắc cho các tính toán hiệu suất cao trong các mô hình kinh tế lượng phức tạp. Viết một plugin C đơn giản: “Hello, C!” Trước khi tiến vào tính toán thực tế, hãy bắt đầu bằng một ví dụ đơn giản: một plugin C hiển thị thông điệp “Hello from C” trong cửa sổ Stata. Mã nguồn cho myhello.ado được trình bày như sau:
Trong bài viết trước, chúng ta đã xây dựng một đường ống phân tích văn bản sử dụng quanteda. Quy trình đó tạo ra ma trận đặc trưng văn bản (DFM), áp dụng trọng số TF-IDF và đo lường sự tương đồng qua cosine similarity. Tuy nhiên, phương pháp này bộc lộ một hạn chế căn bản: cosine similarity tính trên các vector TF-IDF thưa chỉ phản ánh sự trùng lặp từ vựng, chứ không nắm bắt được ý nghĩa ngữ nghĩa. Xét ví dụ hai câu: "Người vay nợ không thực hiện nghĩa vụ trả nợ" và "Khách hàng không đáp ứng được cam kết trả nợ". Sau khi loại từ dừng, chúng không chia sẻ từ vựng nào, dẫn đến độ tương đồng TF-IDF gần như bằng 0. Dù vậy, bất kỳ аналитик nào cũng nhận ra chúng mang ý nghĩa như nhau. Giải pháp nằm ở vector nhúng dày đặc (dense embeddings) — biểu diễn thần kinh nơi các văn bản mang ý nghĩa gần nhau được ánh xạ đến các vị trí lân cận trong không gian vectơ. Nhờ đó, chúng ta có thể đo lường sự tương đồng ngữ nghĩa ngay cả khi không có từ chung. Bài viết này sẽ hướng dẫn xây dựng một đường ống Tạo sinh tăng cường truy xuất (RAG) trong R, sử dụng ragnar cho kho truy xuất và ellmer cho tương tác mô hình ngôn ngữ lớn (LLM), minh họa sức mạnh của nhúng dày đặc trong truy xuất và sinh câu trả lời. Toàn bộ quy trình chạy cục bộ nhờ Ollama.
SciEco
Science for Economics
Định hướng đào tạo phân tích dữ liệu, xây dựng chính sách, tối ưu hoá danh mục tài chính cá nhân và dự báo thị trường.
Liên hệ
Địa chỉ: Số 60, ngõ 41, Phố Thái Hà, Trung Liệt, Đống Đa, Hà Nội (Google Map)
Email: [email protected]
Hotline: 03.57.94.7680 (Mrs. Hà)
Mạng xã hội