SpotifyのWebAPIから取得できるデータを使い、国ごとに流行っている曲の傾向やグループ分けを行ってみた。 #muana #R言語 #rstats
音楽と国 ~spotifyrを用いて~ Music×Analytics Meetup Vol.11 (2023/10/28) @bob3bob3
View Slide
Spotify
Spotifyとは? Spotify(スポティファイ)は、スウェーデンの企業スポティファイ・テクノロジーによって運営されている音楽ストリーミングサービス。 (Wikipediaより引用)
spotifyr ● R言語のspotifyrパッケージを使って、SpotifyのWeb APIから楽曲やアルバム、アーティストなどの情報を一括で取得。 ● spotifyrで取得できる情報の一例 ○ アルバム単位 ■ ジャケット画像、曲数、アルバム名、リリース日、人気度など ○ アーティスト単位 ■ ジャンル、関連するアーティスト、人気度など ○ 楽曲単位 ■ アコースティック度、ダンス度、インスト度、音圧、テンポ、キー、人気度など ○ 詳しくはspotifyのwebAPIのページを参照のこと。
プレイリスト● Spotifyにはプレイリストという機能があります。好きな曲をまとめて公開する機能です。● Spotify公式のプレイリストもあって、例えば各国のTop50がプレイリストとして公開されていたりします。● これもspotifyrで扱えて、プレイリストごとに含まれる楽曲のデータなどを抽出できます。
やってみよう!● 「各国のTop50のプレイリストから、含まれる楽曲を抽出し、各楽曲の特徴を用いて各国をクラスタリングする。」というのをやってみます。● 事前準備としてSpotifyのアカウントと開発者アカウントの登録が必要です。● 2023年07月14日時点のデータです。
# パッケージ読み込みlibrary(conflicted) #関数の衝突防止library(tidyverse) #モダンなデータ処理library(spotifyr) #Spotifyの Web API 操作# 開発者アカウント認証Sys.setenv(SPOTIFY_CLIENT_ID = 'xxxxxxxxxx')Sys.setenv(SPOTIFY_CLIENT_SECRET = 'xxxxxxxxxx')access_token <- get_spotify_access_token()準備
# プレイリスト検索res_search <- search_spotify(q = 'top50',type = 'playlist',limit = 50) |>dplyr::filter(owner.id == "spotify") |> #公式プレイリストに絞るselect(name, id) |> #列を絞るmutate(name = name |> str_remove("Top 50 - ")) |> #プレイリスト名の整形dplyr::filter( #ノイズになる行を削除!(name %in% c("Global", "Greatest Hip-Hop Beats of All Time"))) |>rowid_to_column() #ID番号を振るTop50のプレイリストを検索
検索結果 国名とプレイリストの id。
playlists_tracks <- res_search |>pull(id) |>map( #各プレイリストに含まれる楽曲を抽出\(id) get_playlist_tracks(id) |> select(track.id, track.name),.progress = TRUE) |>list_rbind(names_to = "rowid")Top50のプレイリストから各楽曲のIDを検索
プレイリストに含まれる楽曲のリスト
各楽曲の分析情報を取得res_track <- playlists_tracks |>pull(track.id) |>unique() |>map(\(track.id) get_track_audio_features(track.id),.progress = TRUE) |>list_rbind() |>right_join(playlists_tracks |>left_join(res_search, by = join_by(rowid)),by = join_by(id == track.id)) |>mutate(duration_s = duration_ms / 1000, # ミリ秒を秒にcountry = as.factor(name)) |>select(country, duration_s, energy, acousticness, liveness, speechiness, valence, danceability,tempo, id, track.name)
各楽曲の分析情報を取得
各楽曲の分析情報を取得● duration_ms: 曲の長さ(ミリ秒)● energy: 0~1。騒がしい曲か静かな曲か。● acousticness: アコースティック度合。電気的に増幅されている程度。● liveness: 0~1。ライブ音源かスタジオ音源か。● speechiness: 0~1。歌ではない話し言葉の量。● valence: 0~1。ポジティブさ。● danceability: 0~1。踊りやすさ。● tempo: テンポ(BPM)。
各楽曲の分析情報
分析情報に関する発表事例
EDAlibrary(summarytools)res_track |>select(!c(country, id, track.name)) |>dfSummary() |>summarytools::view()
EDAlibrary(GGally)res_track |>select(!c(country, id, track.name)) |>ggpairs(aes(alpha = 0.1))
国ごとの違いres_track2 |>ggplot(aes(x = reorder(country,duration_s,FUN = median),y = duration_s)) +geom_boxplot() +coord_flip() +labs(x = "国", y = "演奏時間(秒)") +theme(text = element_text(size = 12))
クラスタリングしよう!# 国ごとに中央値を算出し、さらに標準化するmedian_by_country <- res_track |>select(!c(id, track.name)) |>group_by(country, .drop = FALSE) |>summarise(across(everything(), median)) |>column_to_rownames(var = "country") |>scale()# 階層型クラスタリングlibrary(factoextra)library(dendextend)cluster_tree <- median_by_country |>dist() |>hclust(method = "ward.D2")cluster_tree |>fviz_dend(k=6, cex=0.5, horiz = TRUE, label_cols = "black",k_colors = c("#ff4b00", "#990099", "#03af7a","#005aff", "#804000", "#ff8082"),rect = TRUE, rect_fill = TRUE, rect_border = 8)
地図!clusters <- tibble(country = median_by_country |> rownames(),cluster = cluster_tree |> cutree(k=6))library(ggrepel)library(sf)library(rnaturalearth)world_map <- ne_countries(scale = "small", returnclass = "sf") |>left_join(clusters |>mutate(country = country |>str_replace("USA", "United States") |>str_replace("South Korea", "Republic of Korea")),by=join_by(name_long == country))world_map |>ggplot() +geom_sf(aes(fill = as.factor(cluster))) +theme_light() +labs(fill = "cluster") +scale_colour_brewer(palette = "Dark2")
Enjoy!次回「2010年代 King Crimson のセットリスト分析」でお会いしましょう!