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.

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()