pandas数据分析和pyecharts可视化周杰伦MV弹幕(多图长文)
周杰倫MV彈幕
- 數(shù)據(jù)來源:B站爬蟲
- 導(dǎo)入模塊包
- 1. 中文分詞庫 jieba
- 2. 數(shù)據(jù)分析包 pandas
- 3. 可視化包 matplotlib
- 4. 交互可視化包 pyecharts
- 5. 正則表達式 re
- 1. 數(shù)據(jù)預(yù)處理
- 1.1 讀取數(shù)據(jù)
- 1.2 查看數(shù)據(jù)描述信息
- 1.3各列數(shù)據(jù)的含義
- 1.4 抽樣查看數(shù)據(jù)
- 1.5 查看前三行數(shù)據(jù)
- 1.6 查看后三行數(shù)據(jù)
- 1.7 查看重復(fù)數(shù)據(jù)
- 1.8 清洗數(shù)據(jù)
- 2. 數(shù)據(jù)提取和可視化
- 2.1 專輯模塊
- 2.1.1 文件名中提取歌名和專輯名
- 2.1.2 查看各專輯的彈幕數(shù)量(存在單曲的,只選擇 1st 2nd 等開頭的專輯)
- 2.1.3 各專輯彈幕數(shù)
- 2.1.4. 各專輯的用戶參與人數(shù)
- 2.1.5. 開屏彈幕最多的專輯(小于1秒)
- 2.1.6 將參與人數(shù),總彈幕數(shù),開屏彈幕數(shù)合成一個新表
- 統(tǒng)計各個專輯的顏色數(shù)目
- 2.1.7 繪制雷達圖
- 3. 歌曲模塊
- 3.1. 每首歌的詞云圖
- 3.2. 歌曲的彈幕顏色分布
- 3.3. 歌曲的彈幕模式
- 3.4. 歌曲的彈幕發(fā)表時刻
- 3.5 對彈幕高峰時刻查看彈幕模式
- 3.6 對彈幕高峰時刻查看內(nèi)容詞云圖
- 3.7 對彈幕高峰時刻查看顏色圖
- 4. 用戶模塊
- 4.1 用戶發(fā)送的彈幕總數(shù)
- 4.2.用戶最常發(fā)表的彈幕關(guān)鍵詞
- 4.3 用戶最愛發(fā)彈幕的前N首歌曲
- 4.4. 用戶發(fā)送彈幕的時間
- 4.5. 用戶發(fā)送的顏色占比
- 4.6 統(tǒng)計包含關(guān)鍵詞的次數(shù)(一個用戶在單首歌只統(tǒng)計一次)
- 4.7 統(tǒng)計包含關(guān)鍵詞的次數(shù)(一個用戶在單首歌統(tǒng)計多次)
本文涉及pandas和pyecharts方法庫使用,re和jieba庫輔助文本處理
數(shù)據(jù)來源:B站爬蟲
【經(jīng)典】周杰倫全MV 【193P】
之前B站的彈幕接口可以使用,后來接口更新了,得到的彈幕是亂碼
新的數(shù)據(jù)接口每首歌曲最多收集一千條,舊接口可以根據(jù)日期獲取彈幕數(shù)據(jù),需要自己對xml文件中信息提取
https://comment.bilibili.com/2154849.xml (2154849是視頻號bid)
導(dǎo)入模塊包
1. 中文分詞庫 jieba
2. 數(shù)據(jù)分析包 pandas
3. 可視化包 matplotlib
4. 交互可視化包 pyecharts
5. 正則表達式 re
import re import pandas as pd from pyecharts import options as opts from pyecharts.charts import WordCloud import jieba from pyecharts.globals import SymbolType from pyecharts.charts import Grid, Line, Scatter,Pie,Bar import matplotlib # 顯示坐標中的負號 matplotlib.rcParams["axes.unicode_minus"] = False # 顯示中文字符 matplotlib.rc("font", family="SimHei", weight="bold", size=16)1. 數(shù)據(jù)預(yù)處理
1.1 讀取數(shù)據(jù)
如果內(nèi)容列存在英文逗號,使用read_csv或出現(xiàn)列數(shù)不符合字段數(shù)
df = pd.read_csv("./周杰倫MV.csv")1.2 查看數(shù)據(jù)描述信息
可以看到彈幕模式列出現(xiàn)異常,內(nèi)容列存在缺失
df.info()1.3各列數(shù)據(jù)的含義
發(fā)表時刻 : 彈幕出現(xiàn)的時間以秒數(shù)為單位。
彈幕模式: 彈幕的模式1…3 滾動彈幕 4底端彈幕 5頂端彈幕 6.逆向彈幕 7精準定位 8高級彈幕
字體大小 字號, 12非常小,16特小,18小,25中,36大,45很大,64特別大
顏色 字體的顏色以HTML顏色的十進制為準
時刻 Unix格式的時間戳?;鶞蕰r間為 1970-1-1 08:00:00
彈幕池 0普通池 1字幕池 2特殊池【目前特殊池為高級彈幕專用】
發(fā)送者ID 發(fā)送者的ID,用于“屏蔽此彈幕的發(fā)送者”功能
彈幕ID 彈幕在彈幕數(shù)據(jù)庫中rowID 用于“歷史彈幕”功能。
文件名 包含歌名和專輯名,部分歌曲是單曲
內(nèi)容 彈幕內(nèi)容
1.4 抽樣查看數(shù)據(jù)
df.sample(5)1.5 查看前三行數(shù)據(jù)
df.head(3)1.6 查看后三行數(shù)據(jù)
df.tail(3)1.7 查看重復(fù)數(shù)據(jù)
df[df.duplicated()]1.8 清洗數(shù)據(jù)
清理數(shù)據(jù)一般涉及檢驗重復(fù)值,缺失值,異常值
#如果文件名和發(fā)送者ID為空,去掉該數(shù)據(jù),同時更新df df.dropna(inplace=True,subset=['文件名', '發(fā)送者ID']) print(df.shape)數(shù)據(jù)規(guī)模 (303258, 10) 303258行,10列
2. 數(shù)據(jù)提取和可視化
將pyecharts的餅圖封裝成一個函數(shù) ,詳細需要閱讀官網(wǎng):pyecharts
def GetPieFig(data:dict,title:str,width="600px",height="400px"):"""use pyecharts to show pie figure-----------data: series into dict title: Figure title"""pie = (Pie(init_opts=opts.InitOpts(width=width,height=height)).add(title,[[i,j] for i,j in data.items()],center=["40%", "40%"],radius=["30%","50%"],label_opts=opts.LabelOpts(is_show=True)).set_global_opts(title_opts=opts.TitleOpts(title=title),legend_opts=opts.LegendOpts(type_="scroll",pos_left="80%",orient="vertical"),toolbox_opts=opts.ToolboxOpts(pos_bottom="10%"),).set_series_opts(label_opts=opts.LabelOpts( formatter=":{c} (ze8trgl8bvbq%)",is_show=True)))return pie彈幕內(nèi)容存在特殊串
def FilterWords(x):"過濾特殊字符 只返回由中文字母數(shù)字和下劃線組成的字符串"x = str(x)if x.startswith("[") and len(x.split(","))>6:return x.split(",")[4][1:-1]return " ".join(re.findall("\w+",x)) df["內(nèi)容"] = df["內(nèi)容"].apply(FilterWords)2.1 專輯模塊
2.1.1 文件名中提取歌名和專輯名
df["歌名"] = df["文件名"].str.extract("(\w+)") def getAlbum(x):m = re.search("【([\w ]+)】",x)if m:return m.group(1)else:return x df["專輯"] = df["文件名"].apply(getAlbum) df[["歌名","專輯"]].sample(5)2.1.2 查看各專輯的彈幕數(shù)量(存在單曲的,只選擇 1st 2nd 等開頭的專輯)
不需要獲取所有的列
album = df[df["專輯"].str.contains(r'^(\d)')][["發(fā)表時刻","時刻","顏色","內(nèi)容","發(fā)送者ID","專輯"]] #r'^(?:531|92|541[6-9])')] album2.1.3 各專輯彈幕數(shù)
albumName = album["專輯"].value_counts().index.tolist() albumCount = album["專輯"].value_counts().values.tolist() c = (Bar().add_xaxis(albumName).add_yaxis("周杰倫各專輯彈幕數(shù)", albumCount,).reversal_axis().set_series_opts(label_opts=opts.LabelOpts(position="right")).set_global_opts(xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=0)),title_opts=opts.TitleOpts(title="周杰倫各專輯彈幕數(shù)", subtitle="水平柱狀圖/解決標簽名字過長的問題"),) ) c.render_notebook()
由此得到周杰倫的14張專輯的彈幕數(shù)量(趕緊出新專輯)
2.1.4. 各專輯的用戶參與人數(shù)
2.1.5. 開屏彈幕最多的專輯(小于1秒)
方法一:分組
albumDanmu = album[album["發(fā)表時刻"]<1].groupby("專輯")["發(fā)送者ID"].count()方法二:對特定列計數(shù)
albumDanmu = album[album["發(fā)表時刻"]<1]["專輯"].value_counts() import matplotlibmatplotlib.rcParams["axes.unicode_minus"] = False matplotlib.rc("font", family="SimHei", weight="bold", size=16)albumDanmu.plot(kind="barh")2.1.6 將參與人數(shù),總彈幕數(shù),開屏彈幕數(shù)合成一個新表
統(tǒng)計各個專輯的顏色數(shù)目
color_dict = {} for i in albumName:color_dict[i] = album.groupby("專輯").get_group(i)["顏色"].unique().shape[0] albumColor = pd.Series(color_dict) # names: 索引命名 # keys: 列命名 albumTotalDanmu = album["專輯"].value_counts() albumJoin = pd.Series(join_dict) album_merge = pd.concat([albumJoin, albumTotalDanmu, albumDanmu,albumColor],keys=["彈幕參與人數(shù)","總彈幕數(shù)","開屏彈幕數(shù)","顏色數(shù)量"],names=["專輯"],axis=1) album_merge2.1.7 繪制雷達圖
#雷達圖的標簽項 schema = [] for name,value in album_merge.max().to_dict().items():schema.append(opts.RadarIndicatorItem(name=name, max_=value)) name1,name2,name3 = "4th 葉惠美","5th 七里香","6th 十一月的蕭邦" ## 獲取所在行的所有值 album1 = album_merge.loc[name1,:] album2 = album_merge.loc[name2,:] album3 = album_merge.loc[name3,:] ## 值轉(zhuǎn)換為二維數(shù)組 v1 = [album1.values.tolist()] v2 = [album2.values.tolist()] v3 = [album3.values.tolist()]import pyecharts.options as opts from pyecharts.charts import Radar"""根據(jù)"彈幕參與人數(shù)","總彈幕數(shù)","開屏彈幕數(shù)","顏色數(shù)量" 繪制專輯的雷達圖 """ (Radar(init_opts=opts.InitOpts(width="800px", height="600px", bg_color="#CCCCCC")).add_schema(schema=schema,splitarea_opt=opts.SplitAreaOpts(is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)),textstyle_opts=opts.TextStyleOpts(color="dodgerblue"),).add(series_name=name1,data=v1,linestyle_opts=opts.LineStyleOpts(color="#CD0000"),).add(series_name=name2,data=v2,linestyle_opts=opts.LineStyleOpts(color="#5CACEE"),).add(series_name=name3,data=v3,linestyle_opts=opts.LineStyleOpts(color="#05FF00"),).set_series_opts(label_opts=opts.LabelOpts(is_show=True)).set_global_opts(title_opts=opts.TitleOpts(title="基礎(chǔ)雷達圖",subtitle="single單例模式\nmultiple多選模式",subtitle_textstyle_opts={"color":"red"}), legend_opts=opts.LegendOpts(selected_mode="multiple"),).render_notebook() )3. 歌曲模塊
3.1. 每首歌的詞云圖
獲取停用詞表
def get_stopword():"使用集合來獲取停用詞表的詞組"s = set()with open(r"./百度停用詞表.txt", encoding="utf-8") as f:for line in f:s.add(line.strip()) # 去掉每行末尾的換行符return s獲取文本的詞頻
def GetWordFrequency(content:str,pattern=None,mode="sub",min_length = 2,min_app=2)->dict:"""content: strpattern: str default [\W]+mode: str `sub` or `findall` min_length: shortest length of wordmin_app: word mininum appearance times--------------------------some sybolm: [,!\"#, -. : ; <=>^_`~!,。?、¥… ():【《》‘’“”\s]+chinese : [\u4e00-\u9fa5]+"""if not pattern:pattern = "[\W]+" # 非中文,字母 和 空格的就替換re_obj = re.compile(pattern)# 預(yù)編譯,減少重復(fù)匹配text = Noneif mode=="sub":text = re_obj.sub("", content) #正則表達式替換else:text = "".join(re.findall(re_obj,content))wordList = jieba.cut(text) # 分詞s = get_stopword() # 獲取停用詞集合# 字符集的最短長度為2,去除 類似啊啊啊的彈幕內(nèi)容min_length = 2word_dict = {}for i in wordList:if (len(set(i))>=min_length) and (i not in s):word_dict[i] = word_dict.get(i,0) + 1result = {}for k,v in word_dict.items():if v>=min_app:result[k] = vreturn result獲取詞云圖
def GetWordCloud(word_dict,title="WordCloud")->WordCloud:"""word_dict: dict or listmin_app: word mininum appearance timesmin_length: shortest length of word"""if isinstance(word_dict,dict):word_dict = [(i,j) for i,j in word_dict.items()]wc = (WordCloud().add("", word_dict, word_size_range=[20, 100], shape=SymbolType.DIAMOND).set_global_opts(title_opts=opts.TitleOpts(title=title)))return wc song = df[["發(fā)表時刻","顏色","時刻","發(fā)送者ID","歌名","內(nèi)容"]] songName = "七里香" songContentSeris = song.groupby(["歌名"]).get_group(songName)["內(nèi)容"] songContentStr = "".join(songContentSeris.tolist()) # 只選出詞頻至少為50的中文字詞 freq = GetWordFrequency(songContentStr,pattern="[\u4e00-\u9fa5]+",mode="findall",min_app=50) GetWordCloud(freq,songName).render_notebook()3.2. 歌曲的彈幕顏色分布
song[“十六進制顏色”] = song[“顏色”].astype(“int”).apply(lambda x:"#%06x"%x) 但是Pie內(nèi)部好像不能識別不了這種格式的顏色
將float型的顏色轉(zhuǎn)成int型,再根據(jù)需要轉(zhuǎn)成rgb或者十六進制顏色
餅圖
def ColorPie(data,title,min_times=100,bg_color="#d9d9d9"):"data:Series"Data = data[(data>min_times)]colorIndex = Data.index.tolist()colorValue = Data.values.tolist()c = (Pie(init_opts=opts.InitOpts(bg_color=bg_color)).add("", [list(z) for z in zip(colorIndex,colorValue)],).set_colors(colorIndex).set_series_opts(label_opts=opts.LabelOpts( formatter="{c} (ze8trgl8bvbq%)",is_show=True)).set_global_opts(title_opts=opts.TitleOpts(title=title),legend_opts=opts.LegendOpts(type_="scroll",pos_left="80%",orient="vertical"),))return c關(guān)閉餅圖的白色圖例后
說明七里香的彈幕顏色主要是紅色 黃色 和 粉色
再來看看 一路向北的
真 一綠向北
3.3. 歌曲的彈幕模式
songName = "七里香" # 彈幕模式映射 modeMap = {"1":"滾動彈幕","2":"滾動彈幕","3":"滾動彈幕","4":"底端彈幕","5":"頂端彈幕","6":"逆向彈幕","7":"精準定位","8":"高級彈幕"} songMode = song.groupby(["歌名"]).get_group(songName)["彈幕模式"].map(modeMap).value_counts() GetPieFig(songMode,songName+"彈幕模式").render_notebook()輸出:
3.4. 歌曲的彈幕發(fā)表時刻
def GetLineFig(data,title:str,subtitle:str,series_name:str,):"""data: Series of Datatitle : figure main titlesubtitle: figure second titleseries_name: figure series name"""data.sort_index(inplace=True)x1 = [str(i) for i in data.index.tolist()]y1 = data.values.tolist()c11 = (Line(init_opts=opts.InitOpts(width="600px", height="400px")).add_xaxis(xaxis_data=x1,).add_yaxis(series_name=series_name,y_axis=y1,markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max", name="最大值"),opts.MarkPointItem(type_="min", name="最小值"),]),markline_opts=opts.MarkLineOpts(data=[opts.MarkLineItem(type_="average", name="平均值")]),).set_global_opts(title_opts=opts.TitleOpts(title=title, subtitle=subtitle),tooltip_opts=opts.TooltipOpts(trigger="axis"),toolbox_opts=opts.ToolboxOpts(is_show=True),xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False),))return c11時刻向上取整,也可以用ceil函數(shù)
song["time"] = song["發(fā)表時刻"].apply(lambda x:int(x)+1) songName = "七里香" timeCount = song.groupby(["歌名"]).get_group(songName)["time"].value_counts() GetLineFig(timeCount,songName,"各時刻的彈幕數(shù)量變化",songName).render_notebook()結(jié)果
查看該時刻的詞云圖
3.5 對彈幕高峰時刻查看彈幕模式
由上圖,將鼠標移動到一個高峰,看到時刻為84,查看該時刻的彈幕模式
songTime = song.groupby("歌名").get_group(songName) timePoint = 84 modeMap = {"1":"滾動彈幕","2":"滾動彈幕","3":"滾動彈幕","4":"底端彈幕","5":"頂端彈幕","6":"逆向彈幕","7":"精準定位","8":"高級彈幕"}d1 = songTime[songTime["time"]==timePoint]["彈幕模式"].map(modeMap).value_counts().to_dict() GetPieFig(d1,f"{songName}在{timePoint}秒時刻的彈幕模式詞云圖").render_notebook()
視頻中的彈幕是這樣的
3.6 對彈幕高峰時刻查看內(nèi)容詞云圖
看看詞云圖
songTime = song.groupby("歌名").get_group(songName) timePoint = 84 songContent = "".join(songTime[songTime["time"]==timePoint]["內(nèi)容"].tolist()) word_dict = GetWordFrequency(songContent,"[\u4e00-\u9fa5]+","findall",min_app=1) GetWordCloud(word_dict,f"{songName}在{timePoint}秒時刻的詞云圖").render_notebook()3.7 對彈幕高峰時刻查看顏色圖
再看顏色占比
songTime = song.groupby("歌名").get_group(songName) song.loc[:,"rgb"] = song.loc[:,"顏色"].astype("int").apply(lambda x:f"rgb({x>>16},{(x>>8)&255},{x&255})") timePoint = 84 singleSongStamp = songTime[songTime["time"]==timePoint]["rgb"].value_counts() ColorPie(singleSongStamp,songName,min_times=1).render_notebook()4. 用戶模塊
4.1 用戶發(fā)送的彈幕總數(shù)
user = df[["發(fā)表時刻","顏色","彈幕模式","時刻","發(fā)送者ID","歌名","內(nèi)容"]] user["發(fā)送者ID"].value_counts().head(5)4.2.用戶最常發(fā)表的彈幕關(guān)鍵詞
userID = "750ff223" userDanmu = user.groupby(["發(fā)送者ID"]).get_group(userID)["內(nèi)容"].tolist() user_dict = GetWordFrequency("".join(userDanmu),"[\u4e00-\u9fa5]+","findall",min_app=10) GetWordCloud(user_dict,title=userID+"的彈幕關(guān)鍵詞").render_notebook()結(jié)果:
4.3 用戶最愛發(fā)彈幕的前N首歌曲
N = 10 # plot版: 適用于簡單查看 user.groupby(["發(fā)送者ID"]).get_group(userID)["歌名"].value_counts().head(N).plot(kind="pie") # pyecharts版本 userFav = user.groupby(["發(fā)送者ID"]).get_group(userID)["歌名"].value_counts().head(N).to_dict() GetPieFig(userFav,f"{userID}最愛發(fā)的彈幕{N}首歌").render_notebook()4.4. 用戶發(fā)送彈幕的時間
user["hour"] = pd.to_datetime(user["時刻"],unit="s").dt.hour # 轉(zhuǎn)換時間格式 user.head() userTime = user.groupby(["發(fā)送者ID"]).get_group(userID)["hour"].value_counts() GetLineFig(userTime,f"{userID}發(fā)送彈幕時間",None,userID).render_notebook()
這娃絕對是愛修仙的,讓我們看看下一個選手
嗯嗯,這個娃修仙的道行低了點
4.5. 用戶發(fā)送的顏色占比
user.loc[:,"顏色"] =user.loc[:,"顏色"].astype("int")# 自身替換 user.loc[:,"rgb"] = user.loc[:,"顏色"].apply(lambda x:f"rgb({x>>16},{(x>>8)&255},{x&255})") userColor = user.groupby("發(fā)送者ID").get_group(userID)["rgb"].value_counts() ColorPie(userColor,title=f"{userID}彈幕顏色占比",min_times=1,bg_color="gray").render_notebook()
此用戶最常用的顏色是粉色和白色
4.6 統(tǒng)計包含關(guān)鍵詞的次數(shù)(一個用戶在單首歌只統(tǒng)計一次)
4.7 統(tǒng)計包含關(guān)鍵詞的次數(shù)(一個用戶在單首歌統(tǒng)計多次)
group = user[user["內(nèi)容"].str.contains(keyword)].groupby(["歌名"]) keyword_dict = {} min_times = 100 for name in group.groups.keys():size = group.get_group(name)["發(fā)送者ID"].sizeif size>=min_times:keyword_dict[name] = size GetPieFig(keyword_dict,f"{keyword}").render_notebook()
完結(jié)
后期會嘗試聯(lián)系一些模型,如RFM模型,回歸分析等
總結(jié)
以上是生活随笔為你收集整理的pandas数据分析和pyecharts可视化周杰伦MV弹幕(多图长文)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电源检测工具OCCT v9.0.4,小巧
- 下一篇: 迈向“超人认知”:脑机接口的未来