当前位置: 首页 > 科技观察

数据科学家而不是DJ?Python助你实现

时间:2023-03-18 18:56:07 科技观察

数据科学是一门庞大的学科,不断扩展到新的行业,音乐行业就是其中之一。如果将这些应用程序视为“黑匣子”,则可以观察到它的输入(数据)和输出(产品)。该项目旨在使用Python处理Spotify音乐数据,有两个范围:演示API(应用程序编程接口)的存在,该API对于为算法提供超细粒度数据非常重要。演示简单的统计数据(如果应用得当)如何编码日常行为,将其分解为基本元素,并在此基础上构建有价值的产品。这个故事最初是对音乐背后的统计数据进行调查,结果证明等式背后也有“音乐”……这个概念假设了一个场景。作为一名数据科学家,我工作的数据公司(DataCorp)记录了青年营销部门赚取的丰厚利润,因此公司决定举办一场派对来招待年轻客户。在没有DJ的情况下,主管让我负责音乐,让派对一直持续到早上!她给了我一些Spotify播放列表,我最终选择并创建了一个。然而,忽视现代音乐趋势给我留下了一个棘手的问题。如何使用Python访问所有播放列表,提取每个曲目的每个音频特征进行统计分析,并将最适合(聚会)的曲目包装到最终播放列表中?当然,这里有个技术问题:abeat也听不见!为了更好地传达结果,假设:#1:个人Spotify播放列表代表公司给我的内容。#2:派对对象是18-30岁的年轻人,意思是……跳舞!然而,他们中的许多人可能会有家人陪伴,这意味着一小群客人会更喜欢欢快的音乐。#3:在音频特征中,Spotify只考虑可跳舞性、能量、节奏、响度和效价(见第2节)。那是因为他们更好地表达了一段乐曲是否适合舞蹈。#4:有两种方法可以改进选定的播放列表:分别删除或添加被认为“坏”或“好”(涉及一种或多种音频特征)的曲目。我只使用后者来扩展最终播放列表。作者打算按照以下步骤进行:设置运行代码的环境。请求SpotifyAPI获取所有相关音乐数据并提供简短说明。使用Numpy、Pandas和一些其他Python库执行EDA(探索性数据分析),以数字和视觉方式探索候选播放列表。选择-使用两种统计技术优化最合适的播放列表。1.设置在本节中,设置所需的环境以应用分析技术。如果您已经准备好下面列出的任何部分,则可以跳过它们。申请一个Spotify开发者帐户并创建一个应用程序。[在此过程中,将创建一个客户端ID,并为应用程序提供一个客户端密码]。安装JupyterNotebook-一个开源Web应用程序,用于创建/共享包含实时代码、方程式、可视化和叙述文本的文档。安装Spotipy-一个用于访问SpotifyWebAPI的轻量级Python库和请求-一个用于寻址API的Python模块。可以使用CLI(命令行界面)或Jupyternotebook来运行以下命令:pipinstallspotipypipinstallrequestsinstall.py导入必要的库:#Importthelibrariesimportosimportpandasaspdimportnumpyasnpimportjsonimportmatplotlib.pyplotaspltimportseabornassnsimportspotipyimportspotipy.utilasutilfromspotipy.oauth2importSpotifyClientCredentials执行授权代码流:#Declarethecredentialscid='XXXX'secret='XXXX'redirect_uri='http://localhost:7777/callback'username='XXXX'#Authorizationflowscope='user-top-read'token=util.prompt_for_user_token(username,scope,client_id=cid,client_secret=secret,redirect_uri=redirect_uri)iftoken:sp=spotipy.Spotify(auth=token)else:print("Can'tgettokenfor",username)auth.pyNotethatinsteadofdeclaringcredentialsdirectlythroughthenotebook,youcanmakethemtemporarilyavailablebysettingtheenvironmentvariableaccordingly:exportSPOTIPY_CLIENT_ID="XXXX"exportSPOTIPY_CLIENT_SECRET="XXXX"exportSPOTIPY_REDIRECT_URI="http://localhost:7777/callback"2.DataInterpretationandAcquisitionSpotifyprovidesitsdeveloperswithmanyaudiofeaturesthatcharacterizeaudiotracks(morecomprehensiveinformationaboutaudiofeatureobjectsforanexplanation,seehere).下面列出要使用的特性,并进行简要说明:Loudness:[-60.0-0db]描述了音轨的整体响度,或者更确切地说,声音的质量,这是与体力相关的主要心理因素(振幅)。能量:[0.0-1.0]描述了对活动和强度的感知测量。充满活力的配乐感觉快速、响亮且嘈杂。效价:[0.0-1.0]描述音轨听起来的“侵略性”。更高的价格意味着更积极的声音(如欢快、欢快等)。速度:描述BPM中曲目的总体估计速度(每分钟节拍数),直接从平均节拍的持续时间得出。可跳舞性:[0.0-1.0]根据音乐元素(节奏、稳定性、节拍强度等)的组合,描述曲目是否适合跳舞。低值意味着更少的舞步。数据提取部分分三步完成:访问用户播放列表;提取每个播放列表的曲目;提取每个轨道的音频特征。对于每个步骤,创建一个函数来实现相应的Spotipy方法。(a)访问用户的播放列表deffetch_playlists(sp,username):"""Returnstheuser'splaylists."""id=[]name=[]num_tracks=[]#MaketheAPIrequestplaylists=sp.user_playlists(username)forplaylistinplaylists['items']:id.append(playlist['id'])name.append(playlist['name'])num_tracks.append(playlist['tracks']['total'])#Createthefinaldfdf_playlists=pd.DataFrame({"id":id,"name":name,"#tracks":num_tracks})returnf_playlistsplaylists=fetch_playlists(sp,username)playlists=playlists[:4].copy()playlistsfetch_plst.py该函数返回一个dataframe,其中包含id,用户播放列表的曲目名称和曲目数#tracks。显然,有4个候选播放列表:playlistsdataframe(b)获取播放列表的曲目deffetch_playlist_tracks(sp,username,playlist_id):"""Returnsthetracksforthegivenplaylist."""offset=0tracks=[]#在True:content=sp时发出API请求。user_playlist_tracks(username,playlist_id,fields=None,limit=100,offset=offset,market=None)tracks+=content['items']ifcontent['next']isnotNone:offset+=100else:breaktrack_id=[]track_name=[]fortrackintracks:track_id.append(track['track']['id'])track_name.append(track['track']['name'])#Createthefinaldfdf_playlists_tracks=pd.DataFrame({"track_id":track_id,"track_name":track_name})returndf_playlists_tracksfetch_trcs.py该函数以playlist_id为参数,返回一个数据框,包括每个曲目的track_id和track_name。不要直接调用它,而是在下面的函数中使用它。(c)获取歌曲目标的音频特征deffetch_audio_features(sp,username,playlist_id):"""为给定的播放列表返回每个曲目的所选音频特征。"""#Usethefetch_playlist_tracksfunctiontofetchallofthetracksplaylist=fetch_playlist_tracks(sp,username,playlist_id)index=0audio[#audio]_features.[0]:audio_features+=sp.audio_features(playlist.iloc[index:index+50,0])index+=50#Appendtheaudiofeaturesinalistfeatures_list=[]forfeaturesinaudio_features:features_list.append([features['可舞性'],features['能量'],features['tempo'],features['loudness'],features['valence']])df_audio_features=pd.DataFrame(features_list,columns=['danceability','energy','tempo','loudness','valence'])#Setthe'tempo'&'loudness'inthesamerangewiththerestfeaturesforfeatureindf_audio_features.columns:iffeature=='tempo'orfeature=='loudness':continuedf_audio_features[feature]=df_audio_features[feature]*100#Createthefinaldf,usingthe'track_id'作为未来参考的索引df_playlist_audio_features=pd.concat([playlist,df_audio_features],axis=1)df_playlist_audio_features.set_index('track_id',inplace=True,drop=True)returnf_playlist_audio_featuresfetch_audio_features.py返回给定的每个参数通过这个函数track_id,轨道的名称和音频特征(可舞性、能量、速度、响度、价)。因此,对于4个播放列表中的每一个,创建一个相应音频特征的数据框:df_dinner=fetch_audio_features(sp,username,'37SqXO5bm81JmGCiuhin0L')df_party=fetch_audio_features(sp,username,'2m75Xwwn4YqhwsxHH7Qc9W')df_lounge=fetch_spio,_features,s('6Jbi3Y7ZNNgSrPaZF4DpUp')df_pop=fetch_audio_features(sp,username,'3u2nUYNuI08yUg877JE5FI')aud_ftrs.pydf_dinner数据框显示示例仅仅借用API的力量就获得了所有必要数据的纯编码3.EDA为了减少混乱,这里没有包含数据可视化代码,但可以在GitHubrepo上找到。首先,所有播放列表的音频特性都绘制在一张图表中,以便轻松了解哪个最适合派对。音频功能水平条形图显然,从整体上看功能,Party和Pop播放列表取代了其他两个。仔细看看这两个可以更清楚地了解哪个占优势......df_party和df_pop水平条形图在派对播放列表中的其他功能比danceability功能更高。这是必须选择和构建以完善最终播放列表。四、播放列表的优化其主要功能是尽可能增加派对播放列表的音频特性。但是,添加一项功能可能会减少另一项功能,因此必须考虑优先级。就作者而言,根据假设2,danceability(年轻人)应该是主要特征,其次是valence(家庭成员)。这些变量是定量的,同时在比率尺度上进行测量。因此,箱线图可以有效地描述每个特征的个体分布。此类描述性统计图表(通过pandas.DataFrame.describe方法)可以很好地直观表示每个特定四分位数下的值的比例。原始df_party数据框详述如下,突出了danceability和valencemean、second(median)、thirdquartiles:df_party数据的描述性统计和boxplot垂直黄线为中位数,?符号代表均值。总的目标是将每个特征的分布尽可能“推”到最右边,即沿着播放列表轨道方向增加,以获得更好的“聚会”体验!根据假设4,从df_pop(secondfinalsplaylist)开始,每次寻找机会:将均值右移(增加平均音频签名)或将中值向均值右侧移动(确保至少50%的歌曲高于平均值))或两者-一个好的起点是取df_pop样本并将其添加到主样本(df_party),除了随机。通过pandas.DataFrame.sample()函数和weights参数,可以预先配置danceability值越大,对应行越有可能被采样。这种方法产生的数据框是df_party_exp_I(exp代表扩展)。#TakeasamplefromthePopplaylistdf_pop_sample_I=df_pop.sample(n=40,weights='danceability',random_state=1)df_pop_sample_I.describe()#Concatenatetheoriginalplaylistwiththesampledf_party_exp_I=pd.concat([df_party,df_pop_sample_I])df_party_exp_I.describe()sample_I.exppy_If_party描述统计数据和箱线图主要音频功能增加了舞蹈能力;均值增加近0.5,分布略有优化。中位数从68.20升至69.30,第三(上)四分位数分别从77.20升至78.90。然而,化合价特征下降了0.61,并且没有一个四分位数向右移动。鉴于此,应该寻求进一步的优化机会。这次方法二将利用NumPy布尔索引并过滤Pop播放列表,以便只返回满足指定条件的行。特别是,可跳舞性和效价特征设置为高于派对播放列表的相应平均值,分别为69.55和51.89。#TakeasamplefromthePopplaylistdf_pop_sample_II=df_pop[(df_pop['danceability']>69.55)&(df_pop['valence']>51.89)].copy()#Concatenatetheoriginalplaylistwiththesampledf_party_exp_II=pd.concat([df_party,df_pop_sample_II])df_party_exp_II.describe()样本_II.pydf_party_exp_II描述性统计和boxplotdanceability添加更多。这次平均值增加了近2.17!由于中位数和上四分位数向右移动,沿此函数的曲目分布也得到了优化,这基本上意味着至少50%的播放列表高于主要的“新”更高平均值(71.71)声学功能。尽管如此,效价特征下降了4.21,第二和第三四分位数均高于平均值。方法三一个特征的优化并不一定意味着其他特征的优化。为了改善这个缺点,将引入一个方程,其变量是声学特征,其参数是分配给它们的权重。由于danceability特征很重要,相应的权重应该更高。最终得分计算如下:得分=(可舞性*30)+(能量*20)+(节拍*20)+(响度*10)+(价*20)为播放列表中的每个单曲计算此得分(创建一个新的列得分),然后计算各自的描述性统计量。这样,df_party可以得到更好的评估和丰富,同时在每个特征上实现更统一(在权重方面)的优化。简而言之,df_party、df_party_exp_I和df_party_exp_II的平均分数分别为7355、7215和7416。很明显,虽然方法1发现与原始播放列表相比更好的舞蹈性,但它破坏了派对的整体体验(平均分数从7355下降到7215)。就第二种方法而言,平均分提高了近62分。但是,也可以不使用这两种方法......这次,通过使用新引入的分数列,df_pop数据框将被过滤并获取分数高于df_party平均值的行。所以,加上后者!#TakeasamplefromthePopplaylistdf_pop_sample_III=df_pop[df_pop['score']>df_party['score'].mean()].copy()#Concatenatetheoriginalplaylistwiththesampledf_be_party_exp_III=pd.concat([df_party,df_pop_desc_sample_III])_partri(III)sample_III.pydf_party_exp_III描述性统计而boxplot实际上,这一次:danceabilityfeature提高了差不多1.17,valence提高了4.06(向均值右侧移动)两个分布都得到了改善(中位数向均值右侧移动)得分为122.3是迄今为止最好的!(上下文意味着更高的潜力,播放列表在加权音频特性方面更统一)作为一个完整的检查,所有的框图都应该被一次性描述和比较——这可能看起来有点拥挤。幸运的是,变量的性质(见上文)允许使用KDE(内核密度图)。KDE图现在非常清楚,方法三(绿色分布)是最好的,因为它实现了更高的右移。最后,生成的数据帧(df_party_exp_III)包含最终音轨。唯一待处理的操作是将其转换为真正的播放列表。下面,第一个函数创建了最终的播放列表,将其名称作为参数以及描述。另一个,从数据帧迁移轨迹。请注意,授权流程将再次运行,这次具有不同的范围(播放列表修改公共)。只需查看指南(https://github.com/makispl/Spotify-Data-Analysis/blob/master/README.md)。defcreate_playlist(sp,username,playlist_name,playlist_description):playlists=sp.user_playlist_create(username,playlist_name,description=playlist_description)create_plst.pydefenrich_playlist(sp,username,playlist_id,playlist_tracks):index=0results=[]whileindex