いつから曲の長さは短くなっていったのか、調べてみる
こんにちは、Quarkです。
突然ですが、最近の曲って短くないですか?
特に、ストリーミングサービスだと、そもそもフルレングスでないバージョンで公開されているのを結構見ます。これも拍車を掛けている気がしますが、数年前から5分台の曲ってあまり見なくなった印象があります。
ということで、いつから楽曲が短くなっていってるのかを調べてみたいと思います。
Spotify Web APIで楽曲情報を集める
実は、Spotify Web API Pythonライブラリの Spotipy を使ってみたくて今回のテーマで使ってみました。
Spotify Web APIについてそんなに詳しいわけじゃないんですが、Spotifyの楽曲情報を取得する目的で使用します。
テーマの主目的ではないので、使い方は省略しますが、Spotify Web APIのDASHBOARDにてアプリを作成したときのclient_id,secret_idを用いて楽曲情報を取得することができます。
# python3コード
pip install Spotipy
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import sys
client_id = 'client_id'
client_secret = 'secret_id'
client_credentials_manager = SpotifyClientCredentials(client_id, client_secret)
spotify = spotipy.Spotify(client_credentials_manager = client_credentials_manager)
spotify変数を使って情報を取得できます。
spotify.album() # アルバム情報を取得
spotify.artist() # アーティスト情報を取得
spotify.album_tracks() # トラック情報を取得
album_tracks()で取得できる情報にduration_msという、ms単位での楽曲の長さの情報が入っています。
spotifyのアーティストIDをせっせこ集めます。
お気に入りに入れているアーティストの中からHardcoreを中心にリリースしているアーティスト100名ほどをピックアップしてIDを集めました。
IDは Spotify Web版URLの
https://open.spotify.com/artist/6lnEWBl7dhcA1FL5yqRHPO
の '6lnEWBl7dhcA1FL5yqRHPO' の部分になります。
# ID一覧を集めて、データを収集する
hardcore_artists = ['04G86bE80jBhRVfH7SvQyJ','04k0n1Rcz2MxqvZfioAOTE','05thJTo0y3RT4EWF7CnOLv','06F6RSEhZkDNezw1cB80cb','0Ke7ZqzaFiIaVySGcbyKnw','0PHHKCmnQpS14HORG1YYBb',
'0S6b11xqvO6XOWZSukSjiY','0XvAc2MBJgzxDdzuzOjsmr','0b2rM3fXiBkA4c1SpSkoqE','0bmxO9kydmqJXyWHz8CNvl','0bx9MkEjHPLChMh8Wn6BS9','0caJEGgVuXuSHhhrMCmlkI',
'0dvmxtAgqN2UAFyRA8JLpf','0eoAQPA85UyOqUJGwt3cvm','0gplvIWFBXieC14rQPCOy8','0hHKtZEXHNsXfgrNgU7Zkl','0k4QVT7AfBtNcgftg7rHsm','0k6qTt3hZMm8W9MnsrN4YH',
'0kyjNsbKXmVOtnaAMOVhW6','0lmhVC2shJnPTNZgfTml94','0smPkYpuobCNxQj8kJzf4U','0zCs1TQIjYoXm0CNHEdpsN','123hDJRbi4KtCdBaaKNHW6','1JuRY72tmWh2rKqz75gCl2',
'1LgLuJSqAJJ6v5RCvjUiQh','1NGSmZz3W7RduM185NLWdk','1ODM6xNS8Osji0prNFRK9H','1Rrgj81U1W0kRhxvzeCXVQ','1RsU9zuGACUb1NGShiFpcP','1Y1sNScqx8BPZceaO7LjTO',
'1Yc03TvBp08WN2oHVuvewX','1d4T4OjQ2lg3QQKzU07DLV','1dWCpNKvuNDv2rE4gCVNwj','1oZ7OpE1SHjyUjXgYKaLpM','1ovLf87ytwpNoA4prvV8wt','1rWaCpcmmjycvD00Kf6YyE',
'1wpaywUewZ3v9UMP9sBcN7','2AfGElfjqXuSyUny7dsj9p','2Az0Qi9cIskM6aYRCHu044','2CTPZndAY5BwdgHk8AX0B7','2Qfe8raQEsAYOlSbTZG4aB','2RoJa2qF4fdyhBkVcl5pNi',
'2aa14y6NqeLUzi2N0IagU2','2bEBnikH5Y1l4vsNbY1Pvf','2bx5R936CdNRuZLmRiMAI2','2gRSrXu8APvASvSMZK1hO2','2kK1cYRoYo24RzsHADtD0E','2lW5IbF53ZuYk98CZ2Ws2s',
'2ryXW39uQFig8qnQHaMVvh','2ym6Gwn7qNzgiAm6VA3nsV','39cgo5SPJygKIlIcrwkd73','3GEDzLFDpKR3tsq72ZRTP7','3Ij56hbjOTHq8RgutQwfxC','3JH8uhrl9I29STPv0fwPxE',
'3WYaiHWRdQhyhjHIWNDfjL','3aXox59c2JVDCGYgB16WmT','3btdbz86t5EFJ5KglZPbmg','3jQSKka1OAFLo5RVqmzIO1','3mZnhzeAyjpFhO3cIepzBr','3n8JNh6L06fF33IOT75Cmy',
'3ovMVfc0goF4SEurQ6rgAF','3wRhQfErLcQxYFRZGlHTXR','45v249ZA13O6zMpmg7djby','4FiprH50L3spazvyHTGMkd','4Gh02gVaInzoBvqEnJFQDS','4NS6tpO6Wi7Z5FVcwS0EZP',
'4OoHneMX97SjUXKWgsyrP4','4RbUYWWjEBb4umwqakOEd3','4SYJNUTeuqa13uUqrRGGgt','4XCq6wVD10ui7rkXScdWvP','4aBZtFUcaeqWOpAq5H3nRq','4f8x3gw9REomgjxI1KdxOA',
'4lSE8OyTMhErkE7OshR2Hq','4sQNUQjOYj9rV2sdfJ8laS','53EHsN2X6QI9xsmunKAW85','54vURjjcnkvQ9XoaxLgnCi','5K4DYOZmv58mpArt4NCumc','5MeNCyt5G7I8SRIEoH3tCD',
'5NFKnt1CcDxFGCuagHIvFp','5UpoEonoqVkfRlySIcEU64','5YG7cC1VX7Nh7AjUOf6PcG','5kKBrMDQlJDmcDKRmHjj5T','6dD5LzTwdYS3gRvRSCOIVP','65T2gXuk9TCJk0kuMubwXH',
'69IwChH6kBVij0cmVHSOtt','6CG5i0dfyqWIOrqFY60ooq','6D38nDWoSHyLycaidI4dPz','6GR6nVejsTwxyjtPqBHqyo','6GhHpobLFwP7PwixWz6otN','6IzjY421I2xp5UR4dkMDsU',
'6MUXMQLSPFynFBwF2Qz2CU','6NLgJoWLqJQelg75YArKKK','6UKH4iUhcq2EmANQtM8nDe','6Vh8H80QdaXyQYGjEpzuCY','6VnVa9tgzzOq1Whs7KMTm3','6XPfY4QyCgpGvRcvHt4b7W',
'6i5yMFG0gFxanyB8GGxpjt','6lnEWBl7dhcA1FL5yqRHPO','6peYaEfmnfpZNfpyOFRxVz','71W46CYYyiO9xKUO5wD9A7','71xytiJEuIEgxrcV6sghd6',
'75VK7WCZG35rkWVfkDBY6m','76raIy8boaM9sf9gMGXGJ5','776uRsooWrGiVZkVWtvfgO','79JBzbzeNHhY3HDtbCUcxc','7E6DrjKJieOdJKO8mbwCMO','7IUDsMuTzIENoCjnskVBBS',
'7KAMvC5fpPMWUgZYu3mEYJ','7aaDZoHDdXgij23Dutg4C3','7izfdXPLe9PjsIN0A0k2pE','7njBiH1Uy0qNA8VvPPtEG7','7oX7rzli18XsB2WFd88oW4','7rPru5POhHFkrg62q9zuyD',
'7xROwHGVE5PdFV9KRPxsto','7zXir1JPk4DA5u0Dln80VO']
# アーティストのID入れたらアルバムタイトル、リリース日、トラック名、曲の長さを返す
def get_track_length(artist_url, album_type):
import pandas as pd
from tqdm import tqdm
df_list = []
urn = f'spotify:artist:{artist_url}'
album_artist = spotify.artist(urn)['name']
try:
album_list = list(map(lambda x : x['uri'], spotify.artist_albums(urn, country='JP', album_type=album_type, limit=None)['items']))
album_title = list(map(lambda x : x['name'], spotify.artist_albums(urn, country='JP', album_type=album_type, limit=None)['items']))
album_release = list(map(lambda x : x['release_date'] ,spotify.artist_albums(urn, country='JP', album_type=album_type, limit=None)['items']))
album_track_list = list(map(lambda x : spotify.album(x)['tracks']['items'], album_list))
for a in tqdm(range(len(album_track_list))):
duration_ms = []
name = []
for i in range(len(album_track_list[a])):
duration_ms.append(album_track_list[a][i]['duration_ms'])
name.append(album_track_list[a][i]['name'])
df_list.append(pd.DataFrame({'artist_name': album_artist,
'album_title' : album_title[a],
'album_release' : album_release[a],
'duration_ms': duration_ms,
'track_name' : name}))
total_df = pd.concat([ df_list[d] for d in range(len(df_list))], axis=0).reset_index(drop=True)
return total_df
except:
print(f'{album_artist} is no {album_type}')
#結合する
import pandas as pd
hardcore_releases_single = list(map(lambda x : get_track_length(x, 'single'), hardcore_artists))
hardcore_releases_album = list(map(lambda x : get_track_length(x, 'album'), hardcore_artists))
released_df_single = pd.concat([ hardcore_releases_single[d] for d in range(len(hardcore_releases_single)) ])
released_df_album = pd.concat([ hardcore_releases_album[d] for d in range(len(hardcore_releases_album)) ])
released_df_single['album_type'] = 'single'
released_df_album['album_type'] = 'album'
total_df = pd.concat([released_df_single, released_df_album], axis=0).reset_index(drop=True)
こんな感じで取得できました。
ここから、楽曲のMix Cutや、コンピレーションアルバムでの再録、Poscast等が混ざっているので、それらを削除していきます。
このあたりは今回の趣旨からかけ離れるので、割愛しています。気になる方はGistにコードをアップしているので見てみてください。
こんな感じで、6182曲のデータが集まりました。これを使って月別の楽曲秒数平均を出し、楽曲秒数の変化した月を探そうと思います。
・データ
・月別楽曲数
・月別リリース楽曲平均秒数(2010年1月以降を表示)
目視で見ても、徐々に秒数が下がっていっているのがわかります。
楽曲の長さが変化した月を求める
ベイズ推論を用いて、事後分布をシミュレートし、楽曲の長さが変化したと言えるであろう点を探索します。
Pythonのベイズ推定ライブラリ PyMC3 を用いて月別平均楽曲秒数の変化点(月)τを探索します。
まずは集計データより、2010年1月~2020年8月を抜き出し使用します。一応、2010年2月と2011年2月のみ欠損してますが、問題ないと判断しています。
「楽曲秒数が変化した月である確率」が、2020年1月~2020年8月までの各月それぞれ一様だと仮定します。
そして、仮定した月であるτに対してτよりも前の月の期待値をλ_1,後の月の期待値をλ_2として、別々の事前分布を用います。事前分布には指数分布を使います。
import pymc3 as pm
import theano.tensor as tt
mean_length_data = np.array(monthly_length['mean'])
monthly_n = len(mean_length_data)
with pm.Model() as model:
alpha = 1.0 / mean_length_data.mean() # 指数分布でλをモデル化=指数分布の期待値とする
lambda_1 = pm.Exponential('lambda_1', alpha) # tauより前のlambda
lambda_2 = pm.Exponential('lambda_2', alpha) # tauより後のlambda
# 変化点tau
tau = pm.DiscreteUniform('tau', lower=0, upper=monthly_n - 1)
idx = np.arange(monthly_n)
lambda_ = pm.math.switch(tau > idx, lambda_1, lambda_2)
# lambda_1,lambda_2の確率変数から確率変数lambda_を作成し、各月すべての平均よりポアソン分布のオブジェクトを生成する
observation = pm.Poisson('obs', lambda_, observed=mean_length_data)
# 探索する
with model:
step = pm.Metropolis()
trace = pm.sample(10000, tune=5000,step=step)
# 結果の値を格納
lambda_1_samples = trace['lambda_1']
lambda_2_samples = trace['lambda_2']
tau_samples = trace['tau']
# 結果をプロットする
plt.figure(figsize=(40, 24))
plt.subplot(311)
plt.hist(np.int32(lambda_1_samples), bins=100, histtype='stepfilled', alpha=0.8, density=True)
plt.title('Posterior dist lambda_1')
plt.subplot(312)
plt.hist(np.int32(lambda_2_samples), bins=100, histtype='stepfilled', alpha=0.8, density=True)
plt.title('Posterior dist lambda_2')
plt.subplot(313)
w = 1.0 / tau_samples.shape[0] * np.ones_like(tau_samples)
plt.hist(tau_samples, bins=monthly_n, alpha=1,
color='g', weights=w, rwidth=2.)
plt.xticks(np.arange(monthly_n))
plt.xticks(rotation=270)
plt.title('tau value')
plt.show()
結果
結果としては、期待値300~305秒くらいの長さから245~250秒へと、2015年6月~8月に変わっていったといえますね。
変化点τである確率のX軸が数値なので、まとめるとこうです。
体感的にも、まぁ確かにこのあたりから知らずに短くなっていった気がするなぁというのはありますね。
最近は、また別で
フルレングスでないバージョンで公開されている
の影響で、新しい変化点もありそうですね。変化点τを2つに増やせば、これも見つけることはできると思います。
こういう変化は、ジャンル別に違うと思うので、気になった方はご自身の好きなジャンルを集めて見てみても面白そうですね。
ソースコードはGistに乗せてますので、是非やってみてください。環境がなくても、colaboratoryで可能です!
ではでは
この記事が気に入ったらサポートをしてみませんか?