1.Nhập và Kiểm tra Dữ liệu Ban đầu

Trong bối cảnh ngành công nghiệp âm nhạc số phát triển mạnh mẽ, dữ liệu từ các nền tảng streaming như Spotify là một nguồn tài nguyên quý giá để phân tích xu hướng và hành vi người nghe. Bộ dữ liệu “Spotify Dataset 1921-2020” cung cấp thông tin chi tiết về hơn 170,000 bài hát, bao gồm các thuộc tính âm nhạc và năm phát hành. Trong chương này, nhóm sẽ tiến hành các bước đầu tiên để nhập và khám phá sơ bộ bộ dữ liệu, tạo nền tảng cho các phân tích sâu hơn ở các chương sau. Ở giai đoạn này, chúng ta sẽ tải bộ dữ liệu Spotify vào môi trường R và thực hiện các bước kiểm tra cơ bản để hiểu rõ về cấu trúc và nội dung của nó.


# Tải thư viện và đọc dữ liệu
library(tidyverse)
spotify_data <- read_csv("data.csv")
dim(spotify_data)
## [1] 170653     19

Bộ dữ liệu này có tổng cộng 170,653 dòng và 19 cột, bao gồm các thông tin về các bài hát trên nền tảng Spotify từ năm 1921 đến 2020

glimpse(spotify_data)
## Rows: 170,653
## Columns: 19
## $ valence          <dbl> 0.0594, 0.9630, 0.0394, 0.1650, 0.2530, 0.1960, 0.406…
## $ year             <dbl> 1921, 1921, 1921, 1921, 1921, 1921, 1921, 1921, 1921,…
## $ acousticness     <dbl> 0.9820, 0.7320, 0.9610, 0.9670, 0.9570, 0.5790, 0.996…
## $ artists          <chr> "['Sergei Rachmaninoff', 'James Levine', 'Berliner Ph…
## $ danceability     <dbl> 0.279, 0.819, 0.328, 0.275, 0.418, 0.697, 0.518, 0.38…
## $ duration_ms      <dbl> 831667, 180533, 500062, 210000, 166693, 395076, 15950…
## $ energy           <dbl> 0.2110, 0.3410, 0.1660, 0.3090, 0.1930, 0.3460, 0.203…
## $ explicit         <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,…
## $ id               <chr> "4BJqT0PrAfrxzMOxytFOIz", "7xPhfUan2yNtyFG0cUWkt8", "…
## $ instrumentalness <dbl> 8.78e-01, 0.00e+00, 9.13e-01, 2.77e-05, 1.68e-06, 1.6…
## $ key              <dbl> 10, 7, 3, 5, 3, 2, 0, 1, 5, 8, 9, 10, 5, 8, 7, 7, 2, …
## $ liveness         <dbl> 0.6650, 0.1600, 0.1010, 0.3810, 0.2290, 0.1300, 0.115…
## $ loudness         <dbl> -20.096, -12.441, -14.850, -9.316, -10.096, -12.506, …
## $ mode             <dbl> 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1,…
## $ name             <chr> "Piano Concerto No. 3 in D Minor, Op. 30: III. Finale…
## $ popularity       <dbl> 4, 5, 5, 3, 2, 6, 4, 2, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0,…
## $ release_date     <chr> "1921", "1921", "1921", "1921", "1921", "1921", "1921…
## $ speechiness      <dbl> 0.0366, 0.4150, 0.0339, 0.0354, 0.0380, 0.0700, 0.061…
## $ tempo            <dbl> 80.954, 60.936, 110.339, 100.109, 101.665, 119.824, 6…
library(tibble)
spotify_metadata <- tribble(
  ~Variable,          ~Data_Type, ~Description,
  "valence",          "double",   "Mức độ tích cực trong âm nhạc (0 = buồn, 1 = vui)",
  "year",             "double",   "Năm phát hành của bài hát",
  "acousticness",     "double",   "Khả năng bài hát là acoustic (âm thanh mộc)",
  "artists",          "character","Danh sách nghệ sĩ thể hiện bài hát",
  "danceability",     "double",   "Mức độ dễ nhảy theo bài hát (0 đến 1)",
  "duration_ms",      "double",   "Thời lượng bài hát (miligiây)",
  "energy",           "double",   "Mức năng lượng của bài hát",
  "explicit",         "double",   "Bài hát có nội dung nhạy cảm không (0 = không, 1 = có)",
  "id",               "character","Mã định danh bài hát trên Spotify",
  "instrumentalness", "double",   "Xác suất bài hát là nhạc không lời",
  "key",              "double",   "Tông nhạc chính của bài hát (0 = C, 1 = C#, ..., 11 = B)",
  "liveness",         "double",   "Khả năng bài hát được thu âm trực tiếp",
  "loudness",         "double",   "Mức âm lượng trung bình (đơn vị decibel)",
  "mode",             "double",   "Thang âm chính (1) hoặc phụ (0)",
  "name",             "character","Tên bài hát",
  "popularity",       "double",   "Mức độ phổ biến (0-100)",
  "release_date",     "character","Ngày phát hành bài hát",
  "speechiness",      "double",   "Mức độ chứa lời thoại trong bài hát",
  "tempo",            "double",   "Tốc độ của bài hát (nhịp/phút - BPM)"
)
print(spotify_metadata, n = Inf)
## # A tibble: 19 × 3
##    Variable         Data_Type Description                                       
##    <chr>            <chr>     <chr>                                             
##  1 valence          double    Mức độ tích cực trong âm nhạc (0 = buồn, 1 = vui) 
##  2 year             double    Năm phát hành của bài hát                         
##  3 acousticness     double    Khả năng bài hát là acoustic (âm thanh mộc)       
##  4 artists          character Danh sách nghệ sĩ thể hiện bài hát                
##  5 danceability     double    Mức độ dễ nhảy theo bài hát (0 đến 1)             
##  6 duration_ms      double    Thời lượng bài hát (miligiây)                     
##  7 energy           double    Mức năng lượng của bài hát                        
##  8 explicit         double    Bài hát có nội dung nhạy cảm không (0 = không, 1 …
##  9 id               character Mã định danh bài hát trên Spotify                 
## 10 instrumentalness double    Xác suất bài hát là nhạc không lời                
## 11 key              double    Tông nhạc chính của bài hát (0 = C, 1 = C#, ..., …
## 12 liveness         double    Khả năng bài hát được thu âm trực tiếp            
## 13 loudness         double    Mức âm lượng trung bình (đơn vị decibel)          
## 14 mode             double    Thang âm chính (1) hoặc phụ (0)                   
## 15 name             character Tên bài hát                                       
## 16 popularity       double    Mức độ phổ biến (0-100)                           
## 17 release_date     character Ngày phát hành bài hát                            
## 18 speechiness      double    Mức độ chứa lời thoại trong bài hát               
## 19 tempo            double    Tốc độ của bài hát (nhịp/phút - BPM)

1.1 Kiểm tra 6 dòng đầu và cuối của dữ liệu

head(spotify_data)
## # A tibble: 6 × 19
##   valence  year acousticness artists    danceability duration_ms energy explicit
##     <dbl> <dbl>        <dbl> <chr>             <dbl>       <dbl>  <dbl>    <dbl>
## 1  0.0594  1921        0.982 ['Sergei …        0.279      831667  0.211        0
## 2  0.963   1921        0.732 ['Dennis …        0.819      180533  0.341        0
## 3  0.0394  1921        0.961 ['KHP Kri…        0.328      500062  0.166        0
## 4  0.165   1921        0.967 ['Frank P…        0.275      210000  0.309        0
## 5  0.253   1921        0.957 ['Phil Re…        0.418      166693  0.193        0
## 6  0.196   1921        0.579 ['KHP Kri…        0.697      395076  0.346        0
## # ℹ 11 more variables: id <chr>, instrumentalness <dbl>, key <dbl>,
## #   liveness <dbl>, loudness <dbl>, mode <dbl>, name <chr>, popularity <dbl>,
## #   release_date <chr>, speechiness <dbl>, tempo <dbl>

1.2 Danh sách tên các biến

colnames(spotify_data)
##  [1] "valence"          "year"             "acousticness"     "artists"         
##  [5] "danceability"     "duration_ms"      "energy"           "explicit"        
##  [9] "id"               "instrumentalness" "key"              "liveness"        
## [13] "loudness"         "mode"             "name"             "popularity"      
## [17] "release_date"     "speechiness"      "tempo"

1.3 kiểm tra giá trị thiếu

sum(is.na(spotify_data))
## [1] 0

Không có giá trị thiếu trong bộ dữ liệu

1.4 Kiểm tra số lượng quan sát trùng lặp

duplicated_rows <- sum(duplicated(spotify_data))
print(paste("Số lượng quan sát trùng lặp là:", duplicated_rows))
## [1] "Số lượng quan sát trùng lặp là: 0"

2. Phân tổ các biến và phân tích mối quan hệ giữa 2 biến

2.1 Phân tổ theo mức độ phổ biến và năm

library(dplyr)


# Tạo biến phân nhóm mức độ phổ biến 
spotify_data <- spotify_data %>%
  mutate(popularity_level = case_when(
    popularity <= 20 ~ "Thấp",
    popularity <= 50 ~ "Trung bình",
    popularity <= 80 ~ "Cao",
    TRUE            ~ "Rất cao"
  ))


# Phân tổ theo năm và mức độ phổ biến, đếm số bài hát
popularity_time_summary <- spotify_data %>%
  group_by(year, popularity_level) %>%
  summarise(So_bai_hat = n(), .groups = "drop") %>%
  arrange(year, popularity_level)

print(popularity_time_summary)
## # A tibble: 304 × 3
##     year popularity_level So_bai_hat
##    <dbl> <chr>                 <int>
##  1  1921 Thấp                    150
##  2  1922 Thấp                     71
##  3  1923 Thấp                    172
##  4  1923 Trung bình               13
##  5  1924 Thấp                    236
##  6  1925 Thấp                    269
##  7  1925 Trung bình                9
##  8  1926 Thấp                   1367
##  9  1926 Trung bình               11
## 10  1927 Thấp                    610
## # ℹ 294 more rows

Kết quả cho thấy trong các năm đầu thế kỷ 20, phần lớn bài hát thuộc nhóm thấp về mức độ phổ biến, với số lượng bài hát lớn hơn hẳn nhóm Trung bình. Số bài hát phổ biến ở các nhóm cao hơn gần như rất ít hoặc chưa xuất hiện, phản ánh xu hướng âm nhạc và khả năng lan tỏa hạn chế của những năm đó.

Điều này cũng phù hợp với thực tế phát triển công nghệ và ngành âm nhạc, khi mà sự phổ biến của bài hát chưa được mở rộng rộng rãi như ngày nay.

2.2 Phân tổ theo mức độ phổ biến và năng lượng

# Tạo biến phân nhóm năng lượng
spotify_data <- spotify_data %>%
  mutate(energy_level = case_when(
    energy <= 0.33 ~ "Thấp",
    energy <= 0.66 ~ "Trung bình",
    TRUE           ~ "Cao"
  ))

# Phân tổ theo popularity_level và energy_level, đếm số bài hát
pop_energy_summary <- spotify_data %>%
  group_by(popularity_level, energy_level) %>%
  summarise(So_bai_hat = n(), .groups = "drop") %>%
  arrange(popularity_level, energy_level)

print(pop_energy_summary)
## # A tibble: 12 × 3
##    popularity_level energy_level So_bai_hat
##    <chr>            <chr>             <int>
##  1 Cao              Cao               17033
##  2 Cao              Thấp               4384
##  3 Cao              Trung bình        14320
##  4 Rất cao          Cao                 229
##  5 Rất cao          Thấp                 32
##  6 Rất cao          Trung bình          288
##  7 Thấp             Cao                3374
##  8 Thấp             Thấp              35635
##  9 Thấp             Trung bình        15395
## 10 Trung bình       Cao               29801
## 11 Trung bình       Thấp              18492
## 12 Trung bình       Trung bình        31670

Kết quả cho thấy:

=> Năng lượng bài hát có mối liên hệ rõ nét với mức độ phổ biến: bài hát năng lượng cao thường có xu hướng được yêu thích và phổ biến hơn.

2.3 Phân tổ theo mức độ phổ biến và bài hát có lời tục tĩu hay không

# Phân tổ theo popularity_level và explicit, đếm số bài hát
pop_explicit_summary <- spotify_data %>%
  group_by(popularity_level, explicit) %>%
  summarise(So_bai_hat = n(), .groups = "drop") %>%
  arrange(popularity_level, explicit)

print(pop_explicit_summary)
## # A tibble: 8 × 3
##   popularity_level explicit So_bai_hat
##   <chr>               <dbl>      <int>
## 1 Cao                     0      28625
## 2 Cao                     1       7112
## 3 Rất cao                 0        353
## 4 Rất cao                 1        196
## 5 Thấp                    0      51829
## 6 Thấp                    1       2575
## 7 Trung bình              0      75413
## 8 Trung bình              1       4550

Kết quả cho thấy phần lớn bài hát ở mọi mức độ phổ biến đều không có explicit (explicit = 0). Tuy nhiên, tỉ lệ bài hát có explicit (explicit = 1) tăng dần theo mức độ phổ biến: nhóm Cao và Rất cao có số bài hát explicit nhiều hơn so với nhóm Thấp và Trung bình. Điều này gợi ý rằng bài hát có lời tục tĩu có thể có xu hướng phổ biến hơn trong một số trường hợp.

2.4 Trực quan hóa Mối quan hệ Năng lượng & Phổ biến

ggplot(pop_energy_summary, aes(x = popularity_level, y = So_bai_hat, fill = energy_level)) +
  geom_col(position = "dodge") +
  labs(title = "Số lượng bài hát theo Mức độ Phổ biến và Năng lượng",
       x = "Mức độ Phổ biến",
       y = "Số lượng bài hát",
       fill = "Mức Năng lượng") +
  theme_minimal()

Nhận xét: Biểu đồ cột nhóm này trực quan hóa rõ ràng nhận định ở trên. Ta có thể thấy ngay tại nhóm ‘Cao’ và ‘Trung bình’, các cột ‘Năng lượng Cao’ và ‘Năng lượng Trung bình’ chiếm đa số. Ngược lại, ở nhóm ‘Thấp’, cột ‘Năng lượng Thấp’ lại rất đáng kể. Điều này giúp người xem nắm bắt thông tin nhanh hơn nhiều so với việc đọc bảng số.

Đối với bảng pop_explicit_summary, điều chúng ta quan tâm là tỷ lệ phần trăm. Vì vậy, biểu đồ cột chồng 100% (100% stacked bar chart) là lựa chọn tốt nhất.

2.5 Trực quan hóa Tỷ lệ Bài hát ‘Explicit’

ggplot(pop_explicit_summary, aes(x = popularity_level, y = So_bai_hat, fill = factor(explicit))) +
  geom_col(position = "fill") +
  scale_y_continuous(labels = scales::percent_format()) +
  labs(title = "Tỷ lệ bài hát có lời tục tĩu (Explicit) theo Mức độ Phổ biến",
       x = "Mức độ Phổ biến",
       y = "Tỷ lệ phần trăm",
       fill = "Explicit (1=Có, 0=Không)") +
  theme_minimal()

Nhận xét: Biểu đồ này cho thấy một xu hướng rất rõ ràng: Mức độ phổ biến càng cao (‘Cao’ và ‘Rất cao’), thì tỷ lệ bài hát có nội dung ‘explicit’ (màu đỏ) càng lớn. Điều này khẳng định nhận định của nhóm rằng nội dung nhạy cảm có xu hướng xuất hiện nhiều hơn ở các bài hát nổi tiếng. # 3. Phân tích các biến # 3.1 Mức độ phổ biến

# Tính tần suất mức độ phổ biến
Bảng_tần_suất <- spotify_data %>%
  group_by(popularity_level) %>%
  summarise(So_bai_hat = n(), .groups = "drop") %>%
  mutate(Tỷ_lệ = round(So_bai_hat / sum(So_bai_hat) * 100, 2))
print(Bảng_tần_suất)
## # A tibble: 4 × 3
##   popularity_level So_bai_hat Tỷ_lệ
##   <chr>                 <int> <dbl>
## 1 Cao                   35737 20.9 
## 2 Rất cao                 549  0.32
## 3 Thấp                  54404 31.9 
## 4 Trung bình            79963 46.9

Phần lớn bài hát có mức độ phổ biến từ trung bình đến thấp, chiếm gần 78% tổng số. Các bài hát phổ biến cao chiếm khoảng 21%, trong khi bài hát rất nổi tiếng chỉ chiếm dưới 1%, cho thấy nhóm này rất hiếm.

library(ggplot2)
ggplot(Bảng_tần_suất, aes(x = popularity_level, y = So_bai_hat, fill = popularity_level)) +
  geom_col(show.legend = FALSE) +
  geom_text(aes(label = paste0(round(Tỷ_lệ, 1), "%")), vjust = -0.5) +
  labs(title = "Tần suất mức độ phổ biến bài hát",
       x = "Mức độ phổ biến",
       y = "Số lượng bài hát") +
  theme_minimal()

3.2 Năm phát hành

# Đếm số bài hát theo năm
year_summary <- spotify_data %>%
  group_by(year) %>%
  summarise(So_bai_hat = n(), .groups = "drop") %>%
  arrange(year)
print(year_summary)
## # A tibble: 100 × 2
##     year So_bai_hat
##    <dbl>      <int>
##  1  1921        150
##  2  1922         71
##  3  1923        185
##  4  1924        236
##  5  1925        278
##  6  1926       1378
##  7  1927        615
##  8  1928       1261
##  9  1929        952
## 10  1930       1924
## # ℹ 90 more rows

Số lượng bài hát phát hành tăng dần qua các năm đầu thế kỷ 20, từ vài chục bài năm 1922 lên đến hàng nghìn bài vào cuối thập niên 1920 và đầu 1930. Điều này cho thấy sự phát triển mạnh mẽ của ngành công nghiệp âm nhạc trong giai đoạn này, với ngày càng nhiều bài hát được sản xuất và ghi lại.

# Vẽ biểu đồ số bài hát theo năm
ggplot(year_summary, aes(x = year, y = So_bai_hat)) +
  geom_line(color = "blue") +
  labs(title = "Số lượng bài hát theo năm phát hành",
       x = "Năm phát hành",
       y = "Số bài hát") +
  theme_minimal()

3.3 Phân tích Mức độ “Dễ nhảy” (Danceability)

ggplot(spotify_data, aes(x = danceability)) +
  geom_histogram(bins = 30, fill = "darkgreen", alpha = 0.7) +
  labs(title = "Phân phối Mức độ Dễ nhảy của các Bài hát",
       x = "Mức độ Dễ nhảy (0 = Khó, 1 = Dễ)",
       y = "Số lượng bài hát") +
  theme_minimal()

Nhận xét: Biểu đồ phân phối cho thấy điểm danceability có xu hướng lệch về bên phải, tập trung nhiều ở khoảng 0.5 đến 0.8. Điều này có nghĩa là phần lớn các bài hát trong bộ dữ liệu có nhịp điệu khá phù hợp để nhảy, phản ánh đúng đặc tính của âm nhạc phổ thông.

3.4 Phân tích Mức độ “Vui vẻ” (Valence)

ggplot(spotify_data, aes(x = valence)) +
  geom_histogram(bins = 30, fill = "orange", alpha = 0.7) +
  labs(title = "Phân phối Mức độ Tích cực (Vui/Buồn) của các Bài hát",
       x = "Mức độ Tích cực (0 = Buồn, 1 = Vui)",
       y = "Số lượng bài hát") +
  theme_minimal()

Nhận xét: Khác với ‘danceability’, phân phối của ‘valence’ trông khá ‘phẳng’ và trải đều (gần giống phân phối đều). Điều này cho thấy một sự cân bằng thú vị trong kho nhạc của Spotify: số lượng các bài hát buồn/sâu lắng (valence thấp) gần như tương đương với số lượng các bài hát vui vẻ/tích cực (valence cao).

4. Phân tích Mối quan hệ Trực quan

4.1 Biểu đồ Tán xạ (Scatter Plot): Năng lượng (Energy) vs. Độ lớn (Loudness)

# Lấy một mẫu 10,000 bài để vẽ cho nhanh, tránh quá tải
spotify_sample <- sample_n(spotify_data, 10000)

ggplot(spotify_sample, aes(x = energy, y = loudness)) +
  geom_point(alpha = 0.3, color = "purple") +
  geom_smooth(method = "lm", color = "red") +
  labs(title = "Mối quan hệ giữa Năng lượng và Độ lớn",
       x = "Năng lượng",
       y = "Độ lớn (dB)") +
  theme_minimal()

Nhận xét: Biểu đồ tán xạ cho thấy một mối tương quan dương rất mạnh (các điểm đi theo đường chéo từ dưới lên). Đường xu hướng (màu đỏ) khẳng định điều này. Có thể kết luận rằng: các bài hát có năng lượng càng cao thì càng có xu hướng được mix (phối khí) to và rõ ràng hơn.

4.2 Biểu đồ Hộp (Box Plot): Mức độ “Vui vẻ” (Valence) vs. Mức độ Phổ biến

ggplot(spotify_data, aes(x = popularity_level, y = valence, fill = popularity_level)) +
  geom_boxplot() +
  labs(title = "Bài hát Nổi tiếng thì 'Vui' hay 'Buồn' hơn?",
       x = "Mức độ Phổ biến",
       y = "Mức độ Tích cực (Vui/Buồn)") +
  theme_minimal() +
  theme(legend.position = "none")

Nhận xét: Biểu đồ hộp này giúp chúng ta so sánh phân phối của ‘valence’ qua các nhóm phổ biến. Nhìn vào đường kẻ ngang ở giữa mỗi hộp (trung vị), ta thấy một xu hướng thú vị: các nhóm ‘Thấp’ và ‘Trung bình’ có mức độ vui vẻ trung vị cao hơn so với nhóm ‘Cao’ và ‘Rất cao’. Điều này gợi ý rằng các bài hát nổi tiếng hàng đầu có xu hướng ‘buồn’ hoặc ‘sâu lắng’ hơn một chút so với mặt bằng chung.

4.3 Phân tích Ma trận Tương quan

Chúng ta muốn biết các thuộc tính âm nhạc (như ‘năng lượng’, ‘độ vui vẻ’, ‘độ lớn’) liên quan với nhau và liên quan đến ‘độ nổi tiếng’ như thế nào. Một ma trận tương quan sẽ cho chúng ta câu trả lời nhanh nhất.

library(corrr)

# 1. Chọn các biến số (numeric) mà chúng ta quan tâm
numeric_vars <- spotify_data %>%
  select(popularity, danceability, energy, loudness, speechiness, 
         acousticness, instrumentalness, liveness, valence, tempo)

# 2. Tính toán ma trận tương quan
cor_matrix <- correlate(numeric_vars)

# 3. Trực quan hóa bằng biểu đồ nhiệt (heatmap)
# rplot() là một hàm đơn giản để vẽ biểu đồ nhiệt từ gói 'corrr'
rplot(cor_matrix, legend = TRUE, print_cor = TRUE) +
  labs(title = "Ma trận Tương quan giữa các Thuộc tính Âm nhạc")

Nhận xét:

Màu xanh dương (Số dương): Tương quan thuận. Khi một biến tăng, biến kia cũng có xu hướng tăng. (Ví dụ: energy và loudness có màu xanh rất đậm, nghĩa là chúng liên quan rất chặt chẽ).

Màu đỏ (Số âm): Tương quan nghịch. Khi một biến tăng, biến kia có xu hướng giảm. (Ví dụ: acousticness (độ mộc) và energy (năng lượng) có màu đỏ đậm, nghĩa là nhạc càng mộc thì càng ít năng lượng).

Hãy nhìn vào cột popularity:

Biến loudness (độ lớn) và energy (năng lượng) có vẻ có tương quan thuận (màu xanh) với popularity.

Biến acousticness (độ mộc) có tương quan nghịch (màu đỏ) mạnh nhất với popularity.

Kết luận: Từ biểu đồ này, chúng ta có thể rút ra một “công thức” sơ bộ cho một bài hát nổi tiếng: nó phải to, rõ ràng (loudness cao) và không quá mộc (acousticness thấp).

5. Phân tích Xu hướng Âm nhạc theo Thời gian

Để xem âm nhạc đã thay đổi như thế nào, chúng ta sẽ nhóm các bài hát theo từng thập kỷ và tính toán các giá trị trung bình.

library(tidyverse)

# Tạo biến 'decade' và lọc
spotify_processed <- spotify_data %>%
  mutate(decade = floor(year / 10) * 10) %>%
  filter(decade >= 1920)

# 5.1. Tính độ mộc trung bình theo từng thập kỷ
trends_over_time <- spotify_processed %>%
  group_by(decade) %>%
  summarise(
    mean_acousticness = mean(acousticness),
    mean_energy = mean(energy),
    mean_valence = mean(valence)
  )

# 5.2. Vẽ biểu đồ
ggplot(trends_over_time, aes(x = decade, y = mean_acousticness)) +
  geom_line(color = "brown", size = 1.2) +
  geom_point(color = "brown", size = 2) +
  labs(title = "Âm nhạc ngày càng 'Mộc' hay 'Điện tử' hơn?",
       subtitle = "Độ 'mộc' (acousticness) trung bình của âm nhạc qua các thập kỷ",
       x = "Thập kỷ",
       y = "Độ mộc trung bình") +
  theme_minimal()

Nhận xét: Biểu đồ đường cho thấy một xu hướng giảm rõ rệt. Âm nhạc ở thập niên 1920-1940 rất “mộc” (điểm cao), nhưng từ 1950 trở đi, với sự ra đời của nhạc cụ điện, độ mộc trung bình giảm mạnh và ổn định ở mức thấp. Đây là bằng chứng cho thấy sự “điện tử hóa” của âm nhạc hiện đại.

#5.3 Phân tích “Độ vui vẻ” của Âm nhạc theo Thời gian

ggplot(trends_over_time, aes(x = decade, y = mean_valence)) +
  geom_line(color = "blue", size = 1.2) +
  geom_point(color = "blue", size = 2) +
  labs(title = "Âm nhạc đang 'Vui' lên hay 'Buồn' đi?",
       subtitle = "Độ 'vui vẻ' (valence) trung bình của âm nhạc qua các thập kỷ",
       x = "Thập kỷ",
       y = "Độ vui vẻ trung bình") +
  theme_minimal()

Nhận xét: Biểu đồ này cho thấy một xu hướng giảm đáng lo ngại. Mức độ vui vẻ trung bình của âm nhạc đạt đỉnh vào những năm 1950 và sau đó giảm dần đều cho đến ngày nay. Điều này khẳng định lại phát hiện của chúng ta ở Node 4: âm nhạc phổ thông dường như đang ngày càng ‘buồn’ và ‘sâu lắng’ hơn.