Python制作動態(tài)詞頻條形圖的全過程
”數(shù)據(jù)可視化“這個話題,相信大家并不陌生,在一些平臺,經(jīng)??梢钥吹揭恍﹦討B(tài)條形圖的視頻,大多都是某國家 GDP 的變化或者不同國家疫情中感染人數(shù)的變化等等。
這篇文章,我們將使用 Python 繪制動態(tài)詞頻條形圖,顧名思義,就是以詞頻作為數(shù)量指標的動態(tài)條形圖。
前期準備
輸入以下命令,安裝必須的庫:
pip install JiashuResearchTools pip install jieba pip install pandas pip install bar_chart_race
數(shù)據(jù)的選擇與獲取
我們這次使用的數(shù)據(jù)是簡書文章收益排行榜,日期范圍為 2020 年 6 月 20 日至 2021 年 9 月 18 日。
從網(wǎng)頁中解析數(shù)據(jù)的過程較為復(fù)雜,我們使用簡書數(shù)據(jù)科學(xué)庫 JianshuResearchTools 完成。
為方便調(diào)試,我們使用 Jupyter Notebook 進行交互式開發(fā)。
導(dǎo)入 JianshuResearchTools,并為其設(shè)置別名:
import JianshuResearchTools as jrt
調(diào)用接口,獲取 2021 年 9 月 17 日的數(shù)據(jù):
jrt.rank.GetArticleFPRankData("20210917")
返回的數(shù)據(jù)如下:
[{'ranking': 0, 'aslug': 'a03adf9d5dd5', 'title': '幸得君心似我心', 'author_name': '雁陣驚寒', 'author_avatar_url': 'https://upload.jianshu.io/users/upload_avatars/26225608/682b892e-6661-4f98-9aab-20b4038a433b.jpg', 'fp_to_author': 3123.148, 'fp_to_voter': 3123.148, 'total_fp': 6246.297}, {'ranking': 1, 'aslug': '56f7fe236842', 'title': '傷痕', 'author_name': '李文丁', 'author_avatar_url': 'https://upload.jianshu.io/users/upload_avatars/26726969/058e18c4-908f-4710-8df7-1d34d05d61e3.jpg', 'fp_to_author': 1562.198, 'fp_to_voter': 1562.198, 'total_fp': 3124.397}, (以下省略)
可以看出,返回的數(shù)據(jù)中包含文章的排名、標題、作者名、作者頭像鏈接和關(guān)于簡書資產(chǎn)的一些信息。
我們只需要文章的標題進行統(tǒng)計,所以我們將上面獲取到的數(shù)據(jù)賦值給變量 raw_data,然后:
[item["title"] for item in raw_data]
使用列表推導(dǎo)式,我們得到了文章標題組成的列表。
為方便處理,我們將這些數(shù)據(jù)連接起來,中間用空格分隔:
" ".join([item["title"] for item in raw_data])
但是我們遇到了報錯:
TypeError: sequence item 56: expected str instance, NoneType found
從報錯信息中可以看出,我們獲取到的文章標題列表中有空值,導(dǎo)致字符串的連接失敗了。
(空值是因為作者刪除了文章)
所以我們還需要加入去除空值的邏輯,代碼編程這樣:
" ".join(filter(None, [item["title"] for item in raw_data]))
filter 函數(shù)在第一個參數(shù)為 None 時,默認過濾掉列表中的空值。
現(xiàn)在我們獲取到的數(shù)據(jù)如下:
'幸得君心似我心 傷痕 短篇|阿生 “我最喜愛的友友”大評選|理事會 · 中秋嘉年華,等你來! 是緣是劫無須問,石火窮年一蝶迷 職業(yè)日記|從蜜月到陌路:我和美國外教的一點事 紅樓||淺談《紅樓夢》開篇一頑石 城市印象|走筆八卦城 花豹與狗的愛情終結(jié)在人與動物的戰(zhàn)爭里(以下省略)
接下來,我們需要獲取時間范圍內(nèi)的所有數(shù)據(jù)。
查詢 JRT 的函數(shù)文檔可知,我們需要一個字符串類型,格式為”YYYYMMDD“的參數(shù)表示目標數(shù)據(jù)的日期。
所以我們需要寫一段程序,用于實現(xiàn)這些日期字符串的生成,代碼如下:
from datetime import date, timedelta def DateStrGenerator(): start_date = date(2020, 6, 20) after = 0 result = None while result != "20210917": current_date = start_date + timedelta(days=after) result = current_date.strftime(r"%Y%m%d") yield result after += 1
接下來,我們編寫一段代碼,實現(xiàn)對這些數(shù)據(jù)的獲?。?/p>
result = [] for current_date in tqdm(DateStrGenerator(), total=455): raw_data = jrt.rank.GetArticleFPRankData(current_date) processed_data = " ".join(filter(None, [item["title"] for item in raw_data])) result.append({"date": current_date, "data": processed_data})
這里使用 tqdm 庫顯示了一個進度條,非必須。
使用 Pandas 庫,將我們采集到的數(shù)據(jù)轉(zhuǎn)換成 DataFrame:
df = pandas.DataFrame(result)
分詞
我們使用 jieba 庫實現(xiàn)分詞,先嘗試對第一條數(shù)據(jù)進行處理:
jieba.lcut(df["data"][0])
使用 Python 標準庫 collections 中的 Counter 進行詞頻統(tǒng)計:
Counter(jieba.lcut(df["data"][0]))
簡單畫個條形圖:
可以看到,空格和一些標點符號,包括”的“、”我“之類無意義詞匯出現(xiàn)頻率很高,我們需要將它們剔除出去。
我們構(gòu)建一個存放停用詞的 txt 文檔,之后使用如下代碼將其讀取,并轉(zhuǎn)換成一個列表:
stopwords_list = [item.replace("\n", "") for item in open("stopwords.txt", "r", encoding="utf-8").readlines()]
接下來,編寫一個函數(shù),實現(xiàn)停用詞的剔除,為了方便后續(xù)的數(shù)據(jù)處理,我們也一并剔除單字和只出現(xiàn)一次的詞語:
def process_words_count(count_dict): result = {} for key, value in count_dict.items(): if value < 2: continue if len(key) >= 2 and key not in stopwords_list: result[key] = value return result
另外,我們使用 jieba 庫的 add_word 函數(shù)將一些簡書中的組織名和專有名詞添加到詞庫中,從而提高分詞的準確性,代碼如下:
keywords_list = [item.replace("\n", "") for item in open("keywords.txt", "r", encoding="utf-8").readlines()] for item in keywords_list: jieba.add_word(item)
經(jīng)過一番處理,現(xiàn)在分詞效果有了明顯的改善:
最后,用這段代碼對所有數(shù)據(jù)進行分詞,并將結(jié)果保存到另一個 DataFrame 中:
data_list = [] date_list = [] for _, item in df.iterrows(): date_list.append(datetime(int(item["date"][0:4]), int(item["date"][4:6]), int(item["date"][6:8]))) data_list.append(process_words_count(Counter(jieba.lcut(item["data"])))) processed_df = pandas.DataFrame(data_list, index=date_list)
我最終得到的結(jié)果是一個 455 行,2087 列的 DataFrame。
篩選與可視化
這樣多的數(shù)據(jù),其中很大一部分都不能代表整體情況,所以我們需要進行數(shù)據(jù)篩選。
使用以下代碼,統(tǒng)計所有列數(shù)值的總和,即每個關(guān)鍵詞在全部數(shù)據(jù)中出現(xiàn)的次數(shù),存儲到名為 sum 的行中:
try: result = [] for i in range(3000): result.append(processed_df.iloc[:, i].sum()) except IndexError: processed_df.loc["sum"] = result
運行以下代碼,只保留在數(shù)據(jù)集中出現(xiàn) 300 次以上的關(guān)鍵詞:
maller_df = processed_df.T[processed_df.T["sum"] >= 300].T smaller_df = smaller_df.drop(labels="sum") smaller_df.columns
現(xiàn)在,數(shù)據(jù)集中的列數(shù)減少到了 24 個,可以進行可視化了。
不要忘記先導(dǎo)入模塊:
import bar_chart_race as bcr
使用此模塊需要先安裝 ffmpeg,這方面教程可以自行查找。
另外,為了支持中文顯示,我們需要打開這個模塊下的 _make_chart.py 文件,在 import 之后增加以下兩行代碼:
plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False
這兩行代碼將會把 matplotlib 的默認字體替換成支持中文顯示的字體。
最后,使用一行代碼完成可視化:
bcr.bar_chart_race(smaller_df, steps_per_period=30, period_length=1500, title="簡書文章收益排行榜可視化", bar_size=0.8, fixed_max=10, n_bars=10)
在這行代碼中,我們使用 smaller_df 作為數(shù)據(jù)集,輸出文件為 output.mp4,幀率設(shè)置為 30,每行數(shù)據(jù)顯示 2 秒。
由于數(shù)據(jù)較多,這一步時間較長,而且會占用較多內(nèi)存。運行結(jié)束后,即可在目錄中找到輸出的文件。
總結(jié)
到此這篇關(guān)于Python制作動態(tài)詞頻條形圖的文章就介紹到這了,更多相關(guān)Python制作動態(tài)詞頻條形圖內(nèi)容請搜索本站以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持本站!
版權(quán)聲明:本站文章來源標注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請保持原文完整并注明來源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學(xué)習(xí)參考,不代表本站立場,如有內(nèi)容涉嫌侵權(quán),請聯(lián)系alex-e#qq.com處理。