messenger_logo
Liên hệ qua Messenger
SciEco

Bùng nổ home run trong bóng chày: trực quan hóa dữ liệu cùng r

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

Bóng chày luôn không ngừng biến đổi qua thời gian, nhưng ít có xu hướng nào thể hiện sự chuyển mình rõ rệt như sự gia tăng của những cú home run. Một thế kỷ trước, việc ghi được vài cú home run trong cả mùa giải đã là thành tích đáng kinh ngạc. Ngày nay, đó lại là kỳ vọng tối thiểu đối với mỗi đội bóng. Nhờ sự cải tiến trong huấn luyện, kỹ thuật phân tích dữ liệu và thậm chí là sự thay đổi cấu trúc quả bóng, số lượng home run đã tăng vọt qua từng mốc lịch sử. Hãy cùng khám phá câu chuyện này qua dữ liệu giải bóng chày chuyên nghiệp Mỹ từ năm 1901 đến nay bằng ngôn ngữ lập trình R.

Chuẩn bị và xử lý dữ liệu lịch sử với Lahman

Để thực hiện bài phân tích, chúng ta sử dụng bộ dữ liệu Lahman, một trong những cơ sở dữ liệu lịch sử toàn diện nhất về bóng chày. Dữ liệu chứa thông tin chi tiết về từng mùa giải, đội bóng và cầu thủ qua hơn một thế kỷ.

Bước đầu tiên là cài đặt các thư viện cần thiết và tính toán chỉ số home run trung bình trên mỗi trận đấu cho toàn giải đấu qua từng năm. Vì mỗi trận đấu luôn có hai đội tham gia, tổng số trận của toàn giải sẽ bằng tổng số trận các đội thi đấu chia cho hai.

1packages <- c("tidyverse", "Lahman", "scales", "gganimate", "gifski")
2to_install <- packages[!packages %in% installed.packages()[, "Package"]]
3if (length(to_install)) install.packages(to_install, dependencies = TRUE)
4library(tidyverse)
5library(Lahman)
6library(scales)
7library(gganimate)
8library(gifski)
9season_hr <- Teams %>%
10  filter(!is.na(HR), !is.na(G), yearID >= 1901) %>%
11  group_by(yearID) %>%
12  summarise(
13    hr_total = sum(HR, na.rm = TRUE),
14    games_team_total = sum(G, na.rm = TRUE),
15    .groups = "drop"
16  ) %>%
17  mutate(
18    games_league = games_team_total / 2,
19    hr_per_game = hr_total / games_league
20  )
21peak <- season_hr %>% slice_max(hr_per_game, n = 1)
22latest_year <- max(season_hr$yearID, na.rm = TRUE)

Xây dựng biểu đồ xu hướng theo thời gian

Sau khi đã chuẩn bị xong chuỗi dữ liệu, bước tiếp theo là dựng biểu đồ đường để quan sát xu hướng biến động. Chúng ta kết hợp đường xu hướng làm mịn bằng phương pháp loess để thấy rõ định hướng dài hạn, đồng thời đánh dấu điểm đỉnh cao nhất từng ghi nhận trong lịch sử.

1p_static <- ggplot(season_hr, aes(yearID, hr_per_game)) +
2  geom_line(linewidth = 1) +
3  geom_smooth(se = FALSE, method = "loess", span = 0.2) +
4  geom_point(data = peak, aes(yearID, hr_per_game), size = 3) +
5  ggrepel::geom_text_repel(
6    data = peak,
7    aes(label = paste0("Peak: ", yearID, "\n", round(hr_per_game, 2), " HR/game")),
8    nudge_y = 0.1,
9    min.segment.length = 0
10  ) +
11  scale_x_continuous(breaks = pretty_breaks()) +
12  scale_y_continuous(labels = label_number(accuracy = 0.01)) +
13  labs(
14    title = "The Home Run Boom in MLB",
15    subtitle = paste0("League-wide home runs per game, 1901–", latest_year),
16    x = "Season",
17    y = "Home runs per game (league-wide)",
18    caption = "Source: Lahman Baseball Database | Made in R"
19  ) +
20  theme_minimal(base_size = 13) +
21  theme(
22    plot.title = element_text(face = "bold"),
23    plot.caption = element_text(margin = margin(t = 8))
24  )
25ggsave("mlb_hr_per_game.png", p_static, width = 10, height = 6.2, dpi = 220)

So sánh xu hướng giữa Giải Mỹ và Giải Quốc gia

Mỗi liên đoàn trong giải đấu đều có những quy định và đặc thụ vận hành riêng. Việc tách dữ liệu theo hai liên đoàn AL và NL giúp xác định xem liệu đà tăng trưởng này xảy ra trên toàn bộ hệ thống hay chỉ tập trung ở một nhóm đội bóng nhất định.

1season_hr_lg <- Teams %>%
2  filter(!is.na(HR), !is.na(G), yearID >= 1901, !is.na(lgID)) %>%
3  group_by(yearID, lgID) %>%
4  summarise(
5    hr_total = sum(HR, na.rm = TRUE),
6    games_team_total = sum(G, na.rm = TRUE),
7    .groups = "drop_last"
8  ) %>%
9  mutate(games_league = games_team_total / 2, hr_per_game = hr_total / games_league) %>%
10  ungroup()
11p_facets <- ggplot(season_hr_lg, aes(yearID, hr_per_game)) +
12  geom_line() +
13  geom_smooth(se = FALSE, method = "loess", span = 0.25) +
14  facet_wrap(~ lgID, nrow = 2) +
15  labs(
16    title = "AL vs NL: home runs per game over time",
17    subtitle = paste0("1901–", latest_year),
18    x = "Season",
19    y = "HR per game",
20    caption = "Source: Lahman Baseball Database | Made in R"
21  ) +
22  theme_minimal(base_size = 12) +
23  theme(plot.title = element_text(face = "bold"))
24ggsave("mlb_hr_per_game_al_vs_nl.png", p_facets, width = 10, height = 7, dpi = 220)

Tạo hiệu ứng động sinh động với gganimate

Trực quan hóa dạng động giúp người xem theo dõi hành trình lịch sử theo từng năm một cách tự nhiên. Sử dụng gói gganimate, đường biểu đồ sẽ vẽ tiến trình phát triển từ quá khứ đến hiện tại.

1p_anim <- ggplot(season_hr, aes(yearID, hr_per_game)) +
2  geom_line() +
3  geom_point(size = 1.5) +
4  labs(
5    title = "MLB Home Runs per Game — {closest_state}",
6    subtitle = paste0("1901–", latest_year),
7    x = "Season",
8    y = "HR per game",
9    caption = "Source: Lahman Baseball Database | Made in R (gganimate)"
10  ) +
11  theme_minimal(base_size = 13) +
12  transition_reveal(yearID)
13animate(
14  p_anim, width = 900, height = 540, fps = 30, duration = 12, end_pause = 10,
15  renderer = gifski_renderer("mlb_hr_per_game.gif")
16)

Bức tranh lịch sử đằng sau những con số

Nhìn vào đường biểu đồ, các giai đoạn phát triển của thể thao đỉnh cao hiện ra rất rõ ràng qua từng thập kỷ.

Giai đoạn bóng chết từ thập niên 1900 đến 1910 ghi nhận tỷ lệ cực kỳ thấp. Các cầu thủ ném bóng làm chủ hoàn toàn trận đấu do chất liệu quả bóng khi đó khá mềm và chiến thuật thi đấu thiên về kiểm soát bóng ngắn.

Giai đoạn từ thập niên 1920 đến 1950 đánh dấu sự xuất hiện của kỷ nguyên sức mạnh với đại diện tiêu biểu là Babe Ruth. Lối chơi chuyển dịch sang hướng tấn công chủ động và home run trở thành vũ khí hàng đầu.

Giai đoạn thập niên 1990 đến 2000 chứng kiến sự bùng nổ vượt ngưỡng trung bình 1 cú đánh mỗi trận. Kỹ thuật thể lực và chiến thuật tấn công đạt đỉnh cao mới.

Từ thập niên 2010 đến nay là cuộc cách mạng góc phát lực. Việc ứng dụng công nghệ theo dõi quỹ đạo giúp cầu thủ tối ưu hóa góc đánh nhằm tạo ra tầm bay xa nhất. Đến năm 2019, giải đấu đã chạm mốc kỷ lục lịch sử với 1.39 cú home run mỗi trận, gấp hơn 6 lần so với thời kỳ năm 1910.

Ý nghĩa đối với phân tích dữ liệu và thị trường dự đoán

Sự thay đổi về tần suất home run mang lại nhiều bài học giá trị cho các nhà phân tích dữ liệu và mô hình hóa:

Điều chỉnh hạn mức điểm số: Khi tổng số cú đánh tăng, điểm số trung bình mỗi trận tăng theo. Các mô hình dự đoán phải cập nhật điểm mốc tổng số bàn thắng lên cao hơn so với lịch sử.

Chỉ số ảnh hưởng của sân thi đấu: Kích thước và độ cao của các sân vận động tác động trực tiếp đến khả năng bóng ra ngoài biên. Sự kết hợp giữa lối đánh tối ưu góc vung gậy và yếu tố địa lý tạo ra biến số lớn cho các chỉ số dự báo cá nhân.

Tránh thiên kiến dữ liệu gần: Tỷ lệ home run không tăng cố định mà luôn biến động theo các điều kiện vật lý như cấu tạo bóng hay quy định vùng ném bóng. Việc chỉ dùng dữ liệu ngắn hạn dễ dẫn đến những dự báo sai lệch khi luật chơi thay đổi.

✨ Giá trị đắt giá từ bài phân tích:

Phân tích chuỗi thời gian cần gắn liền với bối cảnh lịch sử. Sự thay đổi trong dữ liệu không chỉ đến từ yếu tố ngẫu nhiên mà phản ánh trực tiếp sự tiến hóa của công nghệ, vật liệu và chiến thuật trong thực tế. Việc kết hợp kỹ năng xử lý dữ liệu bằng R cùng tư duy lịch sử giúp nhà phân tích nhìn thấy bản chất thực sự đằng sau những đỉnh nhọn trên biểu đồ.

Câu hỏi tư duy hoặc bài tập ứng dụng:

Thử sử dụng gói dữ liệu Lahman để tính toán tỷ lệ strikeout trên mỗi trận đấu cùng giai đoạn 1901 đến nay. Hãy kiểm tra xem liệu sự gia tăng của home run có đi kèm với việc gia tăng số lần cầu thủ đánh hụt hay không, và biểu diễn sự tương quan đó trên cùng một biểu đồ trong R.


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