據(jù)分析課設(shè)實(shí)戰(zhàn):豆瓣電影分析全流程指南)
簡(jiǎn)介數(shù)據(jù)分析項(xiàng)目的核心從來不是跑通代碼而是建立從假設(shè)到驗(yàn)證的完整思維鏈。在真實(shí)工程場(chǎng)景中數(shù)據(jù)清洗、字段設(shè)計(jì)、可視化呈現(xiàn)與交付復(fù)現(xiàn)環(huán)環(huán)相扣任何環(huán)節(jié)的疏漏都會(huì)導(dǎo)致最終結(jié)論失真。Python作為數(shù)據(jù)分析的主流語言配合pandas、matplotlib等工具能夠高效完成結(jié)構(gòu)化數(shù)據(jù)的預(yù)處理與可視化分析。無論是處理評(píng)分分布、類型交叉分析還是基于分詞的詞云挖掘都遵循先探索、再清洗、后建模的通用方法論。本文以經(jīng)典的豆瓣電影課程設(shè)計(jì)為切入點(diǎn)從選題規(guī)劃、數(shù)據(jù)獲取、清洗規(guī)范、多維可視化到zip打包復(fù)現(xiàn)完整拆解一個(gè)可交付的數(shù)據(jù)分析項(xiàng)目如何落地。對(duì)于正在準(zhǔn)備數(shù)據(jù)分析作業(yè)或希望提升工程實(shí)踐能力的學(xué)習(xí)者這份指南提供了避開常見坑位的實(shí)戰(zhàn)經(jīng)驗(yàn)。 豆瓣電影分析_Python數(shù)據(jù)分析課設(shè).zip這個(gè)文件名我一年能見到幾十次。有人認(rèn)認(rèn)真真把手里的Python數(shù)據(jù)分析作業(yè)做完從數(shù)據(jù)采集一路做到可視化報(bào)告最后壓縮打包交上去也有人是從網(wǎng)上拖了一份源碼包下來連壓縮文件本身都沒法干凈打開就急著提交結(jié)果答辯時(shí)被問兩句就露餡。今天我把這個(gè)典型課設(shè)題目拆開講從選題、數(shù)據(jù)清洗、可視分析到最終壓成zip交付把容易被忽略的細(xì)節(jié)按我自己反復(fù)踩過的坑重新捋一遍。這門課如果認(rèn)真做收獲絕對(duì)不止一個(gè)“優(yōu)”而是能讓你完整走一遍數(shù)據(jù)分析項(xiàng)目的全流程。1. 課設(shè)選題與整體方案設(shè)計(jì)為什么豆瓣電影題目經(jīng)久不衰1.1 選豆瓣電影當(dāng)課設(shè)題目的三個(gè)現(xiàn)實(shí)理由先別急著寫代碼。課程設(shè)計(jì)和公司里接需求不一樣公司里項(xiàng)目成敗看業(yè)務(wù)指標(biāo)課設(shè)成敗看“你能不能把一個(gè)模糊問題拆成可執(zhí)行步驟”。豆瓣電影這個(gè)題目之所以被一屆又一屆學(xué)生選本質(zhì)上是因?yàn)樗瑫r(shí)滿足三個(gè)條件。第一個(gè)條件叫數(shù)據(jù)語義直觀。每個(gè)人平時(shí)都看電影說起“評(píng)分是不是虛高”“類型對(duì)口碑有沒有影響”大家天然有判斷力。做數(shù)據(jù)分析最怕連業(yè)務(wù)背景都不懂就開始跑代碼而豆瓣電影幾乎不需要額外科普。老師看你的報(bào)告時(shí)不需要先理解復(fù)雜的行業(yè)知識(shí)直接就能判斷你的結(jié)論靠不靠譜。第二個(gè)條件是數(shù)據(jù)維度足夠豐富。豆瓣電影數(shù)據(jù)通常包含電影名稱、導(dǎo)演、主演、類型、地區(qū)、語言、上映年份、片長(zhǎng)、評(píng)分、評(píng)分人數(shù)、評(píng)論內(nèi)容等字段。這些字段可以被組合出無數(shù)種分析角度比如年份與評(píng)分趨勢(shì)、類型與票房熱度、片長(zhǎng)與口碑關(guān)系、導(dǎo)演/演員合作網(wǎng)絡(luò)、短評(píng)關(guān)鍵詞聚簇。一個(gè)課設(shè)能覆蓋到的分析方法很全數(shù)值型數(shù)據(jù)能做統(tǒng)計(jì)描述分類型數(shù)據(jù)能做頻數(shù)分析文本數(shù)據(jù)有評(píng)論能上分詞和詞云。第三個(gè)條件是工作量可控。相比電商訂單數(shù)據(jù)、金融交易數(shù)據(jù)動(dòng)輒幾百萬行豆瓣電影數(shù)據(jù)集做課程設(shè)計(jì)用幾百到幾千條記錄就足夠了。這個(gè)數(shù)據(jù)規(guī)模用pandas處理沒有性能壓力也方便把完整邏輯講清楚。你不用為了跑個(gè)中型數(shù)據(jù)集去折騰分布計(jì)算框架反而能把重心放在分析方法本身上。1.2 分析目標(biāo)要從“我想看”變成“我要證明什么”選完題目后最常見的翻車做法是一拿到數(shù)據(jù)就開始畫圖畫到什么算什么。這就像沒定目的地就開車結(jié)果分析報(bào)告里堆了十幾張互不相關(guān)的圖表老師一問“你的核心結(jié)論是什么”答不上來。我的習(xí)慣是動(dòng)工之前把分析目標(biāo)寫成一句句可以用數(shù)據(jù)回答的問題。以豆瓣電影項(xiàng)目為例可以定四條主線豆瓣評(píng)分是否存在虛高或兩極分化整體分布是偏態(tài)還是正態(tài)高分區(qū)和低分區(qū)分別占多少比例。不同類型電影的口碑差異有多大哪些類型常年高分哪些類型容易踩雷評(píng)分人數(shù)與評(píng)分之間有沒有相關(guān)性。電影片長(zhǎng)與口碑有沒有真實(shí)關(guān)系是不是越長(zhǎng)的電影評(píng)分越高這個(gè)現(xiàn)象在不同類型里是否一致。近年國(guó)產(chǎn)電影口碑變化趨勢(shì)如何年度平均分是否逐年上升高分組電影和低分組電影的比例怎樣變化。每個(gè)目標(biāo)對(duì)應(yīng)具體的分析方法、圖表類型甚至想好主結(jié)論預(yù)判。比如“片長(zhǎng)與評(píng)分”這個(gè)目標(biāo)我會(huì)先建立假設(shè)片長(zhǎng)適中的電影100-120分鐘通常更受歡迎極短或過長(zhǎng)的電影評(píng)分會(huì)偏低。后面數(shù)據(jù)分析就是去驗(yàn)證或推翻這個(gè)假設(shè)。這種“假設(shè)-驗(yàn)證-結(jié)論”的路徑才是數(shù)據(jù)分析課設(shè)真正想考察的能力。1.3 技術(shù)棧選型與運(yùn)行環(huán)境準(zhǔn)備豆瓣電影分析用到的技術(shù)棧在網(wǎng)絡(luò)熱搜詞里基本都覆蓋了Python、數(shù)據(jù)分析與可視化、python安裝、pandas、matplotlib等。我推薦的組合是Anaconda管理Python環(huán)境創(chuàng)建獨(dú)立的conda env避免多個(gè)項(xiàng)目之間包版本沖突。Jupyter Notebook作為主開發(fā)工具方便把清洗過程和分析過程一步步拆開展示。pandas numpy做數(shù)據(jù)處理與數(shù)值計(jì)算。matplotlib做基礎(chǔ)靜態(tài)圖表如果要更炫一點(diǎn)可以用pyecharts生成可交互HTML圖表答辯演示效果更好。wordcloud jieba做短評(píng)文本的詞云分析這也是熱門加分項(xiàng)。環(huán)境準(zhǔn)備上有一個(gè)建議不要直接在你的主Python環(huán)境里裝包而是新建一個(gè)課設(shè)專用環(huán)境。命令行下兩條命令就夠conda create -n douban python3.10 conda activate douban pip install pandas numpy matplotlib pyecharts wordcloud jieba notebook為什么特別強(qiáng)調(diào)環(huán)境隔離因?yàn)檎n程設(shè)計(jì)做完了要打包提交老師很可能把它放到另一臺(tái)機(jī)器上運(yùn)行。如果你把依賴裝得亂七八糟或者版本沖突解決不了等項(xiàng)目交上去才發(fā)現(xiàn)跑不起來補(bǔ)救成本非常高。后面我在第5部分會(huì)詳細(xì)說怎么用requirements.txt把環(huán)境鎖住。2. 數(shù)據(jù)怎么拿課程設(shè)計(jì)場(chǎng)景下最穩(wěn)的三種方式2.1 公開數(shù)據(jù)集、爬蟲采集、手工整理怎么選很多初學(xué)者一上來就考慮寫爬蟲。我理解這種興奮感爬蟲確實(shí)看著很酷。但把話說直白一點(diǎn)課程設(shè)計(jì)的核心目的是展示數(shù)據(jù)分析能力不是展示爬蟲技巧。而且要考慮到爬蟲本身有合規(guī)風(fēng)險(xiǎn)目標(biāo)網(wǎng)站的頁(yè)面結(jié)構(gòu)也可能隨時(shí)變化。你辛辛苦苦寫好的爬蟲過了兩周頁(yè)面一改版采集結(jié)果就完全變了到時(shí)候整個(gè)分析鏈條都得重來。更現(xiàn)實(shí)的問題是數(shù)據(jù)可復(fù)現(xiàn)性。課設(shè)提交之后老師會(huì)檢查你的分析邏輯是否合理。如果你的數(shù)據(jù)來源是“某天隨機(jī)抓取的一批頁(yè)面”別人沒法復(fù)現(xiàn)你的數(shù)據(jù)分析的嚴(yán)謹(jǐn)性就會(huì)打折扣。所以我給三種方式排個(gè)優(yōu)先級(jí)數(shù)據(jù)獲取方式優(yōu)點(diǎn)缺點(diǎn)適用場(chǎng)景公開數(shù)據(jù)集穩(wěn)定、可復(fù)現(xiàn)、開箱即用數(shù)據(jù)可能不夠新或字段不全絕大多數(shù)課設(shè)首選小型爬蟲采集數(shù)據(jù)新鮮、可自定義字段頁(yè)面改版風(fēng)險(xiǎn)、合規(guī)風(fēng)險(xiǎn)明確了解風(fēng)險(xiǎn)且需要最新數(shù)據(jù)時(shí)手工整理/抽樣質(zhì)量可控、規(guī)模精確耗時(shí)數(shù)據(jù)量受限補(bǔ)充缺失字段、做小規(guī)模驗(yàn)證網(wǎng)上有很多公開的豆瓣電影數(shù)據(jù)集如帶電影基本信息、短評(píng)、評(píng)分人數(shù)等的CSV文件下載后就能直接進(jìn)入清洗環(huán)節(jié)。如果你確實(shí)想用爬蟲也強(qiáng)烈建議把爬下來的數(shù)據(jù)立刻存成靜態(tài)CSV之后所有分析都基于這個(gè)CSV進(jìn)行而不是每次跑分析都重新訪問網(wǎng)站。這樣既保留了爬蟲的學(xué)習(xí)過程也保證了分析鏈路的穩(wěn)定。2.2 字段怎么設(shè)計(jì)才能撐起整個(gè)分析字段設(shè)計(jì)決定你之后能做什么分析我建議至少包含這些核心字段字段名說明類型分析用途movie_id唯一標(biāo)識(shí)int/str主鍵去重title電影名str展示、去重directors導(dǎo)演str導(dǎo)演維度分析actors主演str演員熱度分析genres類型str可多值類型交叉分析region地區(qū)str地區(qū)差異分析language語言str語言分布year上映年份int年份趨勢(shì)runtime片長(zhǎng)分鐘int片長(zhǎng)與評(píng)分關(guān)系rating豆瓣評(píng)分float核心數(shù)值指標(biāo)rating_count評(píng)分人數(shù)int熱度代理指標(biāo)comments短評(píng)/簡(jiǎn)介str文本分析、詞云注意兩個(gè)容易忽視的細(xì)節(jié)。第一rating_count是很有價(jià)值的熱度代理指標(biāo)因?yàn)槎拱瓴还_票房數(shù)據(jù)短評(píng)數(shù)也和評(píng)論行為有關(guān)評(píng)分人數(shù)是衡量電影關(guān)注度最接近的指標(biāo)。第二一部電影的genres字段通常會(huì)有多個(gè)值建議用豎線分隔比如“劇情|愛情|歷史”方便后面用split和explode展開分析。如果用的是公開數(shù)據(jù)集字段名可能不盡相同一定要在清洗階段統(tǒng)一規(guī)范。2.3 數(shù)據(jù)文件編碼與路徑的坑數(shù)據(jù)文件保存有兩個(gè)高頻坑第一個(gè)是編碼。如果你在Windows上用Excel打開過CSV應(yīng)該見過滿屏亂碼。原因是pandas默認(rèn)讀入CSV時(shí)假設(shè)編碼為UTF-8而Excel默認(rèn)用GBK打開文件。解決辦法是保存時(shí)加BOM頭讓Excel自動(dòng)識(shí)別編碼。在pandas中寫入CSV時(shí)指定編碼df.to_csv(data/douban_movies.csv, indexFalse, encodingutf-8-sig)讀取時(shí)保持對(duì)應(yīng)import pandas as pd df pd.read_csv(data/douban_movies.csv, encodingutf-8-sig)第二個(gè)坑是路徑。我見過太多同學(xué)代碼里寫死絕對(duì)路徑比如C:/Users/張三/Desktop/課程設(shè)計(jì)/data/movies.csv。一旦zip包被解壓到別的電腦路徑全失效整個(gè)項(xiàng)目直接跑不起來。正確做法是讓所有代碼都使用相對(duì)路徑假設(shè)你的工作根目錄就是項(xiàng)目文件夾代碼里統(tǒng)一寫data/movies.csv、output/*.png。這樣無論項(xiàng)目被解壓到哪里都能正常運(yùn)行。后面打包章節(jié)我還會(huì)專門講目錄結(jié)構(gòu)就是為了解決這個(gè)路徑問題。3. 清洗數(shù)據(jù)的每一步都要能說出理由3.1 先摸清數(shù)據(jù)底細(xì)再動(dòng)手刪改拿到數(shù)據(jù)后第一件事不是畫圖而是先看數(shù)據(jù)長(zhǎng)什么樣。這一步在數(shù)據(jù)分析流程里叫探索性數(shù)據(jù)檢查是評(píng)分和答辯時(shí)最容易加印象分的環(huán)節(jié)。我先跑一個(gè)核心命令# 打印各字段的非空數(shù)量與類型 df.info() # 查看數(shù)值型字段的統(tǒng)計(jì)概覽 df.describe() # 統(tǒng)計(jì)缺失值 df.isnull().sum() # 統(tǒng)計(jì)完全重復(fù)的行 df.duplicated().sum()以豆瓣電影數(shù)據(jù)為例通常會(huì)發(fā)現(xiàn)的問題有部分電影的評(píng)分缺失片長(zhǎng)字段是“123分鐘”這種帶單位的字符串年份字段被識(shí)別成字符串類型字段里有空值還有一批完全重復(fù)的電影記錄。這些問題如果不在清洗階段處理后面的統(tǒng)計(jì)和繪圖都會(huì)出錯(cuò)。3.2 刪除、填充還是保留判斷邏輯是什么很多同學(xué)會(huì)問遇到缺失值到底是刪還是填我的判斷標(biāo)準(zhǔn)只有一條這條記錄對(duì)我要做的分析是否不可或缺。如果一部電影的評(píng)分缺失而我要做的是“評(píng)分分布”和“評(píng)分與其他字段關(guān)系”的分析那這條記錄的評(píng)分就是核心字段缺失了我就只能刪掉。如果缺失的只是主演可我要做的是年份趨勢(shì)分析主演字段對(duì)我的分析目標(biāo)沒有影響那就不刪記錄頂多把缺失值填成“未知”保持?jǐn)?shù)據(jù)完整性。如果一個(gè)數(shù)據(jù)集中只有幾十條缺失占總樣本比例不到5%刪除通常是安全的。如果缺失占比很高比如評(píng)分缺失了30%那就需要考慮是不是采集階段出了問題而不是簡(jiǎn)單刪除。課程設(shè)計(jì)的數(shù)據(jù)量本來就不大我傾向于用明確簡(jiǎn)單的處理策略分析核心字段缺失則直接刪除次要字段缺失則統(tǒng)一填充占位符。這個(gè)策略要在報(bào)告里明確寫出來說明原因不要默默處理完就結(jié)束。示例清洗代碼# 保留核心字段非空的記錄 df df.dropna(subset[rating, rating_count, title]) # 次要字段缺失填充為“未知” df[directors] df[directors].fillna(未知) df[actors] df[actors].fillna(未知) df[genres] df[genres].fillna(未知) # 刪除完全重復(fù)行 df df.drop_duplicates(subset[movie_id, title])3.3 格式統(tǒng)一和字段拆分要靠正則表達(dá)式原始數(shù)據(jù)里最常見的格式問題有三個(gè)年份混在日期里、片長(zhǎng)帶著中文單位、評(píng)分是字符串。逐一處理。年份字段可能原始數(shù)據(jù)是“2019-12-05”或“2019年”只提取四位數(shù)字df[year] df[year].astype(str).str.extract(r(\d{4})).astype(float)片長(zhǎng)字段比如“123分鐘”把非數(shù)字部分去掉再轉(zhuǎn)成整數(shù)df[runtime] df[runtime].str.replace(分鐘, , regexFalse).astype(int)評(píng)分字段把字符串轉(zhuǎn)成浮點(diǎn)數(shù)遇到無法轉(zhuǎn)換的強(qiáng)制變成NaN再統(tǒng)一處理這種寫法在數(shù)據(jù)科學(xué)里很常見它的好處是保證后面的計(jì)算不會(huì)因?yàn)閭€(gè)別臟數(shù)據(jù)崩潰。然后再用前面的dropna邏輯清理一次即可。df[rating] pd.to_numeric(df[rating], errorscoerce) df[rating_count] pd.to_numeric(df[rating_count], errorscoerce)為什么我反復(fù)強(qiáng)調(diào)“能說清楚每一步為什么要這么處理”因?yàn)榇疝q時(shí)老師不會(huì)只看你的圖他們會(huì)問數(shù)據(jù)清洗的問題比如“你刪了多少條數(shù)據(jù)為什么刪”你如果能答出“刪除缺失評(píng)分的300條記錄因?yàn)槲医酉聛硪鲈u(píng)分相關(guān)性分析這些記錄無法參與計(jì)算”這比你堆十個(gè)炫酷圖表都更顯實(shí)力。3.4 類型字段的一對(duì)多展開電影類型是典型的一對(duì)多字段。如果直接按genres分組統(tǒng)計(jì)會(huì)把“劇情|愛情”當(dāng)成一個(gè)整體這樣統(tǒng)計(jì)就失真了。正確的做法是先拆分再展開讓每一行只包含一個(gè)類型信息。# 先用豎線拆分再用explode把列表展開為多行 df_exploded df.assign(genresdf[genres].str.split(|)).explode(genres) df_exploded[genres] df_exploded[genres].str.strip()explode是pandas里處理一對(duì)多關(guān)系非常好用的函數(shù)它把原來一行里的列表拆成多行其他字段自動(dòng)復(fù)制。這樣后面按類型聚合時(shí)“劇情”和“愛情”就是完全獨(dú)立的個(gè)體統(tǒng)計(jì)口徑才正確。4. 從分析到圖表數(shù)據(jù)可視化怎么落地4.1 先看評(píng)分分布的總體面貌數(shù)據(jù)分析要從總體到局部。第一步先看評(píng)分分布直方圖了解數(shù)據(jù)的整體形態(tài)。import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, PingFang SC] plt.rcParams[axes.unicode_minus] False fig, ax plt.subplots(figsize(10, 5)) ax.hist(df[rating], bins20, edgecolorwhite) ax.set_title(豆瓣電影評(píng)分分布) ax.set_xlabel(評(píng)分) ax.set_ylabel(電影數(shù)量) plt.tight_layout() plt.savefig(output/rating_dist.png, dpi150) plt.show()在觀察圖表的同時(shí)輸出df[rating].describe()重點(diǎn)看均值、中位數(shù)和標(biāo)準(zhǔn)差。我之前做過一個(gè)實(shí)際項(xiàng)目的統(tǒng)計(jì)結(jié)果均值在6.2左右中位數(shù)在6.4左右標(biāo)準(zhǔn)差接近2.0。這里能看出兩個(gè)有意思的結(jié)論一是分?jǐn)?shù)并不呈現(xiàn)正態(tài)分布而是左偏的高分段電影數(shù)量明顯少二是中位數(shù)高于均值說明大量電影集中在中間偏低區(qū)間但有一些超高分電影會(huì)把均值整體拉高。這種“從數(shù)據(jù)到結(jié)論”的表達(dá)方式才是分析報(bào)告真正要體現(xiàn)的能力而不是“我畫了一張直方圖”就完了。4.2 類型、年份、片長(zhǎng)多維交叉分析有了清洗好的數(shù)據(jù)可以做交叉分析了。我舉三個(gè)最經(jīng)典的維度類型與口碑關(guān)系用展開后的df_exploded做分組聚合重點(diǎn)看兩列平均評(píng)分和電影數(shù)量。注意如果某類型只有3部電影平均分9.0也不說明任何問題。要設(shè)置一個(gè)最低樣本量門檻比如只統(tǒng)計(jì)記錄數(shù)不少于30的類型。gen_stats ( df_exploded.groupby(genres)[rating] .agg([mean, count]) .reset_index() ) # 只保留樣本量足夠的類型 gen_stats gen_stats[gen_stats[count] 30] gen_stats gen_stats.sort_values(mean, ascendingFalse) print(gen_stats.head(10))年份與口碑趨勢(shì)這個(gè)適合畫折線圖。先計(jì)算每年的平均評(píng)分和評(píng)分電影數(shù)量year_stats df.groupby(year)[rating].agg([mean, count]).reset_index() # 過濾樣本量過少的年份 year_stats year_stats[year_stats[count] 20]然后畫折線圖觀察十年或二十年的口碑走勢(shì)。你會(huì)發(fā)現(xiàn)某些年份整體評(píng)分偏高某些年份大熱電影扎堆這些都可以作為報(bào)告的分析素材。片長(zhǎng)與評(píng)分關(guān)系先做分箱處理把連續(xù)型片長(zhǎng)分為幾個(gè)區(qū)間比如“90分鐘以下”“90-120分鐘”“120-150分鐘”“150分鐘以上”再計(jì)算各箱體的平均評(píng)分和數(shù)量。bins [0, 90, 120, 150, 300] labels [90分鐘以下, 90-120分鐘, 120-150分鐘, 150分鐘以上] df[runtime_bin] pd.cut(df[runtime], binsbins, labelslabels) runtime_stats df.groupby(runtime_bin, observedFalse)[rating].agg([mean, count]) print(runtime_stats)實(shí)踐中經(jīng)常能看到一種現(xiàn)象片長(zhǎng)120分鐘以上的電影平均評(píng)分更高。但這背后并不是“越長(zhǎng)越好”而是電影工業(yè)的習(xí)慣——低成本、口碑差的片子通常會(huì)控制在90分鐘左右重工業(yè)大制作或作者電影往往有更充裕的篇幅。所以報(bào)告里不能只看現(xiàn)象還要解釋現(xiàn)象背后的業(yè)務(wù)邏輯這才是數(shù)據(jù)分析的加分項(xiàng)。4.3 評(píng)論詞云讓文本分析成為亮點(diǎn)如果你的數(shù)據(jù)里有短評(píng)或者劇情簡(jiǎn)介可以順手做一個(gè)詞云分析。這是很多課設(shè)里最抓眼球的部分因?yàn)閳D表直觀、顏色豐富老師一眼就能看到工作量。詞云分析的大致流程是讀取文本字段用jieba分詞去掉停用詞再用wordcloud生成詞云。import jieba from wordcloud import WordCloud # 把評(píng)論文本合并成一個(gè)大字符串 all_text .join(df[comments].dropna().astype(str).tolist()) # 分詞 words jieba.cut(all_text) # 過濾掉長(zhǎng)度小于2的詞和常見停用詞 stopwords set([電影, 一部, 一個(gè), 我們, 就是, 但是, 可以]) filtered_words [w for w in words if len(w) 1 and w not in stopwords] wordcloud WordCloud( font_pathpath/to/simhei.ttf, width800, height400, background_colorwhite ).generate( .join(filtered_words)) wordcloud.to_file(output/comment_wordcloud.png)中文字體路徑是wordcloud的常見坑。Windows的話可以用C:/Windows/Fonts/simhei.ttfmacOS可以用/System/Library/Fonts/PingFang.ttc。如果不指定字體中文會(huì)全部變成方塊。更有分析力度的做法是不做全量詞云而是把評(píng)論按評(píng)分分成“高分評(píng)論”和“低分評(píng)論”兩組分別生成詞云。高分組的詞云里可能出現(xiàn)“經(jīng)典”“溫暖”“震撼”低分組則可能出現(xiàn)“無聊”“拖沓”“失望”。這種對(duì)比分析比一張全量詞云更能體現(xiàn)你的分析思維。4.4 中文圖表三件套字體、畫布和保存用matplotlib畫中文圖字體配置是必修課。上面代碼里plt.rcParams[font.sans-serif]就是用來設(shè)置默認(rèn)字體為支持中文的字體。設(shè)置plt.rcParams[axes.unicode_minus] False則是為了修復(fù)坐標(biāo)軸負(fù)號(hào)顯示為方塊的問題。這兩句不寫圖里中文就是一片亂碼答辯時(shí)場(chǎng)面會(huì)很尷尬。畫布的尺寸也值得講究。默認(rèn)畫布太小圖里的字會(huì)擠成一片。用figsize(10, 5)或更大保存時(shí)再設(shè)置dpi150輸出圖片足夠清晰插入報(bào)告、放進(jìn)PPT都不會(huì)糊。再配合bbox_inchestight可以自動(dòng)裁剪掉多余空白區(qū)域讓圖表更緊湊。最后強(qiáng)調(diào)一個(gè)輸出規(guī)范所有圖表統(tǒng)一保存到output/目錄文件名要能對(duì)應(yīng)上分析內(nèi)容比如rating_dist.png、genre_rating.png、year_trend.png。這既方便報(bào)告插入也方便最后打包時(shí)檢查有沒有漏生成的圖。5. 交付前打包從代碼整理到可復(fù)現(xiàn)的zip5.1 zip包里應(yīng)該有什么目錄結(jié)構(gòu)怎么搭很多人認(rèn)為打包就是右鍵壓縮把整個(gè)文件夾塞進(jìn)zip就完事。其實(shí)課設(shè)zip的內(nèi)部結(jié)構(gòu)直接決定老師能不能順利解開、能不能跑起來。我見過太多zip包里面既有源代碼又有幾百?gòu)埮R時(shí)圖片還有好幾個(gè)版本的Notebook混亂程度不亞于電腦桌面。一個(gè)成熟的課設(shè)zip目錄結(jié)構(gòu)我建議這樣安排豆瓣電影分析_課程設(shè)計(jì)/ ├── data/ │ ├── douban_movies.csv │ └── douban_comments.csv ├── code/ │ ├── 01_數(shù)據(jù)清洗.py │ ├── 02_數(shù)據(jù)分析.py │ └── 分析演示.ipynb ├── output/ │ ├── rating_dist.png │ ├── genre_rating.html │ └── comment_wordcloud.png ├── report/ │ ├── 數(shù)據(jù)分析報(bào)告.pdf │ └── 答辯PPT.pptx ├── requirements.txt └── README.md這個(gè)結(jié)構(gòu)的邏輯是數(shù)據(jù)、代碼、結(jié)果、報(bào)告四類文件分開放任何人打開包都能迅速定位。README.md是給老師看的第一份文件里面要寫清楚運(yùn)行環(huán)境、啟動(dòng)方式、各個(gè)腳本的作用、輸出結(jié)果在哪里。不要覺得寫README是浪費(fèi)時(shí)間它其實(shí)是給老師的“使用說明書”。5.2 依賴鎖定requirements.txt正確姿勢(shì)很多同學(xué)的requirements.txt不知道是哪里來的可能只有一行pandas也可能把整個(gè)環(huán)境幾百個(gè)包全部導(dǎo)出。這兩種都不對(duì)。推薦做法是在你新建的conda環(huán)境里手動(dòng)整理一份精簡(jiǎn)的依賴清單。方法很簡(jiǎn)單在環(huán)境里運(yùn)行pip list把你實(shí)際用到的核心包寫進(jìn)文件并固定大版本號(hào)。pandas2.0,3.0 numpy1.24 matplotlib3.7 jieba0.42 wordcloud1.9 pyecharts2.0 notebook7.0要不要固定到小版本號(hào)是門學(xué)問。固定太死比如pandas2.1.4換個(gè)環(huán)境可能裝不上固定太松可能過兩年pandas發(fā)布新版本舊代碼在新版本上又跑不通。課設(shè)交付我會(huì)建議用一個(gè)大版本范圍保證兼容性。在驗(yàn)收時(shí)的環(huán)境下安裝命令就一行pip install -r requirements.txt5.3 用Linux命令壓縮zip的正確方式既然文件名里帶zip壓縮這一步本身也要保證不出岔子。Windows下右鍵壓縮很簡(jiǎn)單但有個(gè)小問題如果文件夾路徑里的文件被某些安全軟件占用壓縮出來的zip可能不完整解壓時(shí)就會(huì)遇到“File is not a zip file”的錯(cuò)誤。如果你用的是Linux環(huán)境或者Windows自帶的WSL建議直接命令行壓縮。比如當(dāng)前目錄下有一個(gè)豆瓣電影分析_課程設(shè)計(jì)文件夾想把它壓成zipzip -r 豆瓣電影分析_Python數(shù)據(jù)分析課設(shè).zip 豆瓣電影分析_課程設(shè)計(jì)/如果提示zip命令不存在先安裝sudo apt install zip使用zip -r遞歸壓縮文件夾比右鍵壓縮更可控因?yàn)樗鼤?huì)明確輸出每個(gè)文件是否成功。壓縮完成后建議馬上做一個(gè)完整性驗(yàn)證在Linux下用unzip -t檢查壓縮包內(nèi)容是否完整unzip -t 豆瓣電影分析_Python數(shù)據(jù)分析課設(shè).zip最終顯示No errors detected in compressed data就說明這份zip沒問題。這個(gè)驗(yàn)證很多同學(xué)從來不做等到老師那邊打不開就晚了。5.4 答辯前在干凈環(huán)境跑一遍全流程打包前最后一件事是模擬老師的視角在干凈環(huán)境里完整跑一遍你的項(xiàng)目。具體操作是conda create -n douban_check python3.10 conda activate douban_check pip install -r requirements.txt cd 豆瓣電影分析_課程設(shè)計(jì) python code/01_數(shù)據(jù)清洗.py python code/02_數(shù)據(jù)分析.py這個(gè)過程能暴露一批“本地能跑、換環(huán)境就炸”的典型問題依賴沒寫全、路徑用了絕對(duì)路徑、某個(gè)依賴版本過于老舊。如果你有精力還可以寫一個(gè)簡(jiǎn)單的自查腳本自動(dòng)檢查關(guān)鍵文件是否存在、數(shù)據(jù)是否能讀、圖表是否已生成。示例腳本大概是這樣的import os import pandas as pd from pathlib import Path base Path(.) required_files [data/douban_movies.csv, output/rating_dist.png] for f in required_files: if (base / f).exists(): print(f[通過] {f}) else: print(f[缺少] {f}) df pd.read_csv(base / data/douban_movies.csv, encodingutf-8-sig) print(f數(shù)據(jù)行數(shù): {len(df)}) print(f評(píng)分缺失數(shù): {df[rating].isnull().sum()})這種腳本不是給老師看的是給你自己省麻煩的。數(shù)據(jù)課設(shè)最怕的就是“本地跑得好好的一提交就廢了”而絕大多數(shù)問題都能在干凈環(huán)境復(fù)現(xiàn)這一關(guān)被擋下。6. 常見報(bào)錯(cuò)與排查交上去的包為什么打不開6.1 一網(wǎng)打盡壓縮包與依賴的高頻報(bào)錯(cuò)這部分有沒有價(jià)值要看你是否真正吃過虧。我這些年在各種課程設(shè)計(jì)交流群里看到過太多類似問題整理成一張速查表建議直接收藏。錯(cuò)誤現(xiàn)象可能原因解決辦法解壓提示File is not a zip filezip下載不完整、傳輸中斷或文件被改名成zip但實(shí)際不是壓縮格式重新打包用unzip -t驗(yàn)證完整性提示invalid zip archive: could not find EOCD壓縮包嚴(yán)重?fù)p壞EOCD記錄缺失通常是文件截?cái)鄬?dǎo)致從源目錄重新壓縮不要修復(fù)損壞包解壓時(shí)提示需要密碼zip被加密了輸出無密碼壓縮包老師端打開帶密碼包體驗(yàn)很差ModuleNotFoundError: No module named pandas環(huán)境缺少依賴執(zhí)行pip install -r requirements.txtmatplotlib圖里中文全是方塊沒有配置中文字體配置plt.rcParams[font.sans-serif]并指定本機(jī)可用中文字體pandas讀取CSV報(bào)編碼錯(cuò)誤CSV編碼與讀取編碼不一致讀取時(shí)指定encodingutf-8-sig相對(duì)路徑報(bào)錯(cuò)找不到文件工作目錄不是項(xiàng)目根目錄在項(xiàng)目根目錄運(yùn)行腳本或代碼里基于Path(__file__).parent定位pyecharts生成的html是空白本地渲染依賴JS資源未加載用render生成獨(dú)立HTML文件答辯時(shí)用瀏覽器打開查看6.2 本地沒問題別人電腦上報(bào)錯(cuò)的排查順序如果你把項(xiàng)目發(fā)給同學(xué)對(duì)方解壓后跑不起來就不要懷疑對(duì)方“操作有問題”了先按順序自查。第一步檢查依賴。運(yùn)行環(huán)境里缺少包是最常見原因。讓對(duì)方把報(bào)錯(cuò)信息發(fā)出來只要看到ModuleNotFoundError直接讓他執(zhí)行pip install -r requirements.txt第二步檢查Python版本。如果你的代碼用了3.10才有的語法對(duì)方電腦是3.7必然會(huì)報(bào)錯(cuò)。所以在requirements.txt旁邊建議在README里寫清楚推薦的Python版本。第三步檢查工作目錄。對(duì)方解壓zip后有沒有把終端路徑切到項(xiàng)目根目錄如果他在其他目錄直接運(yùn)行python code/01_數(shù)據(jù)清洗.py代碼里的相對(duì)路徑就會(huì)失效??梢栽谀_本開頭加一個(gè)保護(hù)性代碼自動(dòng)切換到項(xiàng)目根目錄import os from pathlib import Path # 切換到當(dāng)前腳本所在項(xiàng)目的根目錄 os.chdir(Path(__file__).resolve().parent.parent)這樣無論從哪個(gè)路徑啟動(dòng)腳本工作目錄都會(huì)被修正能避免大量“路徑錯(cuò)位”問題。第四步檢查文件是否完整。用第5.3節(jié)的方法讓對(duì)方跑一下unzip -t確認(rèn)zip沒有被郵箱、網(wǎng)盤等工具二次修改。6.3 用一個(gè)小習(xí)慣避免“交上去就廢”最后一個(gè)經(jīng)驗(yàn)是從無數(shù)次教訓(xùn)里沉淀出來的從開始做課設(shè)的第一天就假設(shè)最終交付的是一份“別人需要無腦復(fù)現(xiàn)”的包來寫代碼。這個(gè)習(xí)慣體現(xiàn)在幾個(gè)細(xì)節(jié)里。比如每個(gè)Notebook開頭用Markdown寫清楚“這個(gè)文件做什么、輸入數(shù)據(jù)在哪、輸出結(jié)果到哪”每一步清洗操作后面加一行注釋說明為什么這樣做圖表保存統(tǒng)一到一個(gè)目錄關(guān)閉代碼里的調(diào)試性輸出。這些細(xì)節(jié)看起來不直接給分但會(huì)讓評(píng)審者覺得這是一份真正用心做的作品而不是臨時(shí)拼湊的作業(yè)。我見過不少案例兩個(gè)同學(xué)分析內(nèi)容和結(jié)論幾乎一樣一個(gè)因?yàn)榇a清晰、包結(jié)構(gòu)完整、README寫得好拿了優(yōu)秀另一個(gè)因?yàn)榇a里亂糟糟的絕對(duì)路徑和缺失的依賴說明被扣了分。課設(shè)拼的不只是技術(shù)還有交付意識(shí)。還有一個(gè)小技巧如果在線下載的某些開源示例項(xiàng)目一直解壓失敗注意檢查下載工具是否把文件下載成了HTML格式比如網(wǎng)頁(yè)跳轉(zhuǎn)后實(shí)際保存的文件并不是zip而是報(bào)錯(cuò)頁(yè)面或廣告頁(yè)面這種情況在瀏覽器直接下載時(shí)經(jīng)常發(fā)生。遇到這種問題換一個(gè)下載方式重新獲取或者檢查文件大小是否合理就能快速判斷是文件格式錯(cuò)了還是傳輸過程出了問題。7. 最后一個(gè)建議我自己從一開始做數(shù)據(jù)課設(shè)到現(xiàn)在幫很多人看數(shù)據(jù)項(xiàng)目最深的感觸是大部分“看起來突然翻車”的問題都不是分析本身出錯(cuò)而是“交付”環(huán)節(jié)出了問題。數(shù)據(jù)分析課程設(shè)計(jì)練的其實(shí)是兩件事——把模糊問題變成可量化問題以及讓別人能無痛復(fù)現(xiàn)你的過程。豆瓣電影分析這個(gè)題目再普通只要你能把這兩件事做到位分?jǐn)?shù)不會(huì)差能力也不會(huì)差。所以如果你正在準(zhǔn)備類似的Python數(shù)據(jù)分析課設(shè)我愿意分享一個(gè)保留習(xí)慣每處理一步數(shù)據(jù)就順手在notebook里用Markdown寫一句話解釋為什么這么做。答辯時(shí)哪怕圖表做得普通你也能把自己的思考過程講得清清楚楚這遠(yuǎn)比堆十個(gè)花哨圖表更有說服力。祝你這次課設(shè)不只是拿到一個(gè)zip文件名而是真正掌握了從數(shù)據(jù)到?jīng)Q策的完整路徑。本文還有配套的精品資源點(diǎn)擊獲取