據(jù)分析與可視化項(xiàng)目全流程拆解)
簡介基于Python的中國交通事故數(shù)據(jù)分析可視化系統(tǒng)畢業(yè)設(shè)計(jì)項(xiàng)目面向計(jì)算機(jī)相關(guān)專業(yè)正在完成畢業(yè)設(shè)計(jì)、課程設(shè)計(jì)或期末大作業(yè)的學(xué)生也適合需要Python數(shù)據(jù)分析實(shí)戰(zhàn)練習(xí)的學(xué)習(xí)者解決從交通事故數(shù)據(jù)清洗、預(yù)處理、特征分析到可視化呈現(xiàn)的完整實(shí)現(xiàn)問題可作為同類選題的直接參考范本。壓縮包共7個(gè)文件整體大小約245KB包含3個(gè)Jupyter Notebook承載完整數(shù)據(jù)分析代碼、3個(gè)CSV數(shù)據(jù)文件原始事故數(shù)據(jù)與預(yù)處理后的分析數(shù)據(jù)和1個(gè)HTML可視化頁面用于展示最終圖表與結(jié)論。項(xiàng)目經(jīng)導(dǎo)師指導(dǎo)并認(rèn)可評審分為99分代碼完整確??蛇\(yùn)行目前已有98人學(xué)習(xí)下載。讀者可從中掌握pandas數(shù)據(jù)處理、事故特征探索與可視化圖表設(shè)計(jì)的整體思路并可復(fù)用其中的數(shù)據(jù)預(yù)處理腳本與Notebook代碼快速遷移到自己的項(xiàng)目中。1. 先拆個(gè)徹底這個(gè) Python 交通事故項(xiàng)目到底值不值得跑做數(shù)據(jù)分析項(xiàng)目的都知道真正拉開差距的不是畫圖炫不炫而是你拿到一份原始 CSV 之后敢不敢說自己能把空值、時(shí)間格式、重復(fù)記錄一次性清干凈。這份基于 Python 的中國交通事故數(shù)據(jù)分析可視化系統(tǒng)我拆完之后最大感受是它不是那種網(wǎng)上只放幾個(gè)圖表截圖、代碼跑起來全是報(bào)錯(cuò)的半成品而是把「模擬原始數(shù)據(jù) → 清洗預(yù)處理 → 探索性分析 → 可視化出圖 → 導(dǎo)出 HTML 報(bào)告」這條完整鏈路都給你塞進(jìn)了一個(gè)壓縮包里特別適合做 Python 畢業(yè)設(shè)計(jì)、數(shù)據(jù)分析課程大作業(yè)或者想拿真實(shí)業(yè)務(wù)場景練手的人。它在省事的同時(shí)也留了幾個(gè)坑比如假數(shù)據(jù)口徑、中文字體、時(shí)間排序這些我后面會(huì)一條條講到。2. 數(shù)據(jù)底子與選型先弄清楚三個(gè) CSV 和兩組 Notebook 的分工2.1 文件清單里每一份是干什么的解壓之后你會(huì)看到七樣?xùn)|西別急著打開 notebook 開跑先花兩分鐘搞清楚它們之間的關(guān)系。我按自己的習(xí)慣把它們分成三層原始層是fake_accident_data.csv它是模擬出來的事故原始記錄字段里帶省份、時(shí)間、天氣、事故類型、傷亡人數(shù)這些信息用來模擬一張未經(jīng)處理的事故登記表中間層是preprocessed_accident_data.csv和preprocessed_data.csv這是清洗之后的結(jié)果你會(huì)發(fā)現(xiàn)記錄數(shù)變了、時(shí)間字段變成了標(biāo)準(zhǔn)格式、空值被處理掉了展示層是accident.ipynb、wwa.ipynb和accident.html前兩個(gè)是完整分析過程最后一個(gè)是導(dǎo)出好的可視化報(bào)告瀏覽器打開就能看。主目錄里的main是你跑通整個(gè)流程圖之后生成的中間文件我建議第一次跑先別刪后面調(diào)試要對照它確認(rèn)清洗前后發(fā)生了哪些變化。2.2 為什么選 Pandas Jupyter Matplotlib 這套組合有人會(huì)問都做可視化了為什么不用 Tableau 或者 ECharts 寫個(gè)大屏這里有個(gè)非常實(shí)際的選型理由。畢設(shè)答辯時(shí)老師關(guān)心的不是你的大屏轉(zhuǎn)場動(dòng)畫好不好看而是你處理數(shù)據(jù)的邏輯是否清晰、每一步是不是可解釋。Jupyter Notebook 天然適合這種場景因?yàn)樗选杆伎歼^程」和「結(jié)果圖表」放在同一個(gè)文檔里考官翻到哪一格都能看到你的代碼和輸出。Pandas 負(fù)責(zé)清洗和聚合這是整個(gè)項(xiàng)目最花時(shí)間的地方Matplotlib 和 Seaborn 負(fù)責(zé)出圖雖然默認(rèn)樣式樸素但勝在可控性強(qiáng)每個(gè)坐標(biāo)軸、每個(gè)標(biāo)簽都能手動(dòng)調(diào)??梢暬笃聊翘嘴趴嵝Ч饶愦疝q完想豐富作品集時(shí)再補(bǔ)也不遲。先讀一遍數(shù)據(jù)確認(rèn)這個(gè)數(shù)據(jù)底子長什么樣import pandas as pd acc pd.read_csv(fake_accident_data.csv, encodingutf-8-sig) print(原始形狀, acc.shape) print(acc.dtypes) print(前3行預(yù)覽) print(acc.head(3))這份代碼的核心是解決「未知數(shù)據(jù)的探索」問題。encodingutf-8-sig是我推薦的首選參數(shù)因?yàn)閹ig會(huì)比不帶更穩(wěn)能兼容 Excel 導(dǎo)出的 CSV 在首行添加 BOM 頭的情況shape幫你拿到行數(shù)和列數(shù)dtypes看出每個(gè)字段的類型——這一步一定要做不然你根本不知道日期到底是不是字符串、死亡人數(shù)是不是被讀成了浮點(diǎn)。后面所有清洗動(dòng)作都建立在這三行輸出的基礎(chǔ)上。2.3 字段設(shè)計(jì)對分析維度的影響觀察完數(shù)據(jù)類型之后值得把字段挨個(gè)在心里過一遍因?yàn)檫@決定了你能做哪些維度的分析。我整理了一份字段用途對照表建議你對照自己的數(shù)據(jù)處理邏輯確認(rèn)一遍字段名常見命名類型分析用途datetimeobject → datetime提取月份、小時(shí)做時(shí)間趨勢分析provinceobject省份維度分布橫向條形圖weatherobject天氣與事故類型交叉分析accident_typeobject事故類別計(jì)數(shù)與占比death_count / injury_countint嚴(yán)重程度對比數(shù)值校驗(yàn)road_typeobject道路條件維度字段命名在不同的版本里可能略有差異但核心思路一致時(shí)間字段必須轉(zhuǎn)類型省份、天氣這類文本字段適合分組計(jì)數(shù)傷亡數(shù)字必須有下限校驗(yàn)。理清這層你就知道acc.ipynb里為什么一會(huì)兒 groupby一會(huì)兒畫熱力圖了。3. 數(shù)據(jù)清洗與預(yù)處理把假數(shù)據(jù)變成能說清故事的干凈表3.1 清洗前的狀態(tài)檢查先記錄臟數(shù)據(jù)證據(jù)很多初學(xué)者一上來就dropna()這是最容易翻車的動(dòng)作。因?yàn)槟愀静挥浀迷紨?shù)據(jù)里有多少空值、多少重復(fù)行到后期寫論文時(shí)老師問一句「清洗前后數(shù)據(jù)量變化是多少、為什么變少兩行」你答不上來。我一般會(huì)先做一次狀態(tài)快照import pandas as pd acc pd.read_csv(fake_accident_data.csv, encodingutf-8-sig) # 狀態(tài)快照用于論文中說明清洗前的情況 snapshot { 原始行數(shù): len(acc), 重復(fù)行數(shù): acc.duplicated().sum(), 空值數(shù)量: acc.isnull().sum().sum(), 各列空值: acc.isnull().sum().to_dict(), } print(snapshot)這段代碼實(shí)際上是在做數(shù)據(jù)審計(jì)。duplicated().sum()統(tǒng)計(jì)的是重復(fù)行的總數(shù)isnull().sum().sum()是所有列空值和to_dict()把每列空值數(shù)轉(zhuǎn)換成一個(gè)可讀的字典。建議把輸出的數(shù)字抄到你的實(shí)驗(yàn)記錄里后面寫論文「數(shù)據(jù)來源與預(yù)處理」那一章時(shí)能直接用這也是答辯老師最容易追問的地方。3.2 時(shí)間字段轉(zhuǎn)換字符串日期引發(fā)的連鎖 bug事故數(shù)據(jù)里最典型的坑是時(shí)間列。原始 CSV 里的datetime字段往往長這樣2023-05-12 08:30:00看起來沒什么問題但它是字符串不是時(shí)間類型。字符串狀態(tài)下你沒法dt.hour沒法按月份排序畫出來的折線圖橫坐標(biāo)全是亂的。正確的轉(zhuǎn)換姿勢acc[datetime] pd.to_datetime(acc[datetime], errorscoerce) acc[month] acc[datetime].dt.month acc[hour] acc[datetime].dt.hour # 空值檢查轉(zhuǎn)換失敗的行會(huì)被置為 NaT invalid_time acc[datetime].isna().sum() acc acc.dropna(subset[datetime]) print(f時(shí)間解析失敗{invalid_time} 行已刪除)errorscoerce是這里的核心參數(shù)它的含義是凡是解析不了的時(shí)間值一律轉(zhuǎn)成NaT而不是拋異常中斷程序。這樣你能拿到一個(gè)失敗數(shù)量invalid_time再做定向刪除。dt.month和dt.hour是兩個(gè)最常用的時(shí)間提取操作分別拿到月份和小時(shí)下一步做月度趨勢、24 小時(shí)分布都要靠它們。特別提醒dropna時(shí)一定要加subset參數(shù)只針對時(shí)間列處理別把天氣列或省份列的空值一起刪了——這兩種空的處理邏輯完全不同。3.3 數(shù)值字段的邊界校驗(yàn)負(fù)的死亡人數(shù)必須處理模擬數(shù)據(jù)雖然整體規(guī)律但難免會(huì)有異常值比如死亡人數(shù)為負(fù)數(shù)、受傷人數(shù)遠(yuǎn)大于總記錄數(shù)之類的情況。這類字段如果不做邊界校驗(yàn)畫圖時(shí)會(huì)出現(xiàn)一個(gè)離譜的負(fù)柱答辯時(shí)解釋不清。常見做法是先描述再處理# 邊界描述 print(死亡人數(shù)統(tǒng)計(jì)) print(acc[death_count].describe()) # 規(guī)則清洗死亡人數(shù)和受傷人數(shù)不能為負(fù)數(shù) acc acc[acc[death_count] 0] acc acc[acc[injury_count] 0] acc acc.reset_index(dropTrue) print(清洗后行數(shù), len(acc))describe()會(huì)輸出最小值、最大值、均值等統(tǒng)計(jì)量建議最先看min這一行一旦是負(fù)數(shù)就說明數(shù)據(jù)源有問題。 0的布爾過濾是整段代碼的安全底線reset_index(dropTrue)是清理索引的常規(guī)操作因?yàn)樵诙啻芜^濾之后索引全亂了不重置會(huì)導(dǎo)致后面groupby和畫圖出現(xiàn)「跳行」的偶然問題。3.4 導(dǎo)出預(yù)處理結(jié)果給后續(xù)可視化提供穩(wěn)定輸入清洗最終的產(chǎn)出不是一堆打印語句而是一份干凈的 CSV方便你在acc.ipynb、wwa.ipynb兩個(gè) Notebook 之間反復(fù)讀取不用每次重新執(zhí)行清洗邏輯acc.to_csv(preprocessed_accident_data.csv, indexFalse, encodingutf-8-sig) print(已輸出預(yù)處理數(shù)據(jù)行數(shù), len(acc))indexFalse防止 Pandas 把行號寫進(jìn) CSV 的第一列encodingutf-8-sig保證 Excel 打開時(shí)中文不亂碼。從這里開始你的分析工作流就變成了「讀取預(yù)處理數(shù)據(jù) → 聚合 → 可視化」這一行的穩(wěn)定輸出是你所有圖表的唯一數(shù)據(jù)來源。如果后面發(fā)現(xiàn)某張圖的數(shù)據(jù)不對先回到這一步重新比對別直接在繪圖代碼里打補(bǔ)丁。4. 探索性分析與可視化從聚合結(jié)果到四張核心圖表4.1 省份維度橫向條形圖展示事故數(shù)量分布拿到預(yù)處理數(shù)據(jù)后第一個(gè)值得分析的維度是省份。為什么用橫向條形圖而不是縱向柱狀圖因?yàn)槭》菝Q是中文短的能用 2 個(gè)字長的能用 5 個(gè)字縱向柱狀圖的 x 軸標(biāo)簽一密集遮擋問題就會(huì)讓人頭疼。橫向條形圖能很好地解決這個(gè)問題省份名放在 y 軸讀起來也符合視覺習(xí)慣import pandas as pd import matplotlib.pyplot as plt acc pd.read_csv(preprocessed_accident_data.csv, encodingutf-8-sig) province_cnt acc.groupby(province).size().reset_index(namecounts) province_cnt province_cnt.sort_values(counts, ascendingTrue) fig, ax plt.subplots(figsize(10, 8)) ax.barh(province_cnt[province].tail(10), province_cnt[counts].tail(10)) ax.set_title(事故數(shù)量 Top10 省份) ax.set_xlabel(事故數(shù)量) ax.set_ylabel(省份) plt.tight_layout() plt.savefig(province_top10.png, dpi200, bbox_inchestight) plt.show()groupby(province).size().reset_index(namecounts)是統(tǒng)計(jì)最喜歡用的語法size()表示每個(gè)省份的記錄數(shù)reset_index把分組后的 Series 還原成普通 DataFrame。排序時(shí)我特意用ascendingTrue、畫圖時(shí)取tail(10)這樣排名第一的省份出現(xiàn)在條形圖最上方讀圖最自然。figsize(10, 8)適合 10 條數(shù)據(jù)的橫向條形圖太窄會(huì)顯得標(biāo)簽擁擠保存參數(shù)dpi200夠答辯投影用bbox_inchestight可以防止標(biāo)題被截?cái)唷?.2 時(shí)間維度月度走勢折線圖與坐標(biāo)軸密度控制事故隨時(shí)間的變化趨勢是另一個(gè)必做維度。我用月份聚合畫折線圖效果穩(wěn)定不需要任何額外庫monthly acc.groupby(month).size() fig, ax plt.subplots(figsize(10, 4)) ax.plot(monthly.index, monthly.values, markero, color#C0392B) ax.set_xticks(range(1, 13)) ax.set_xticklabels([f{m}月 for m in range(1, 13)]) ax.set_ylabel(事故數(shù)量) ax.set_title(各月份事故數(shù)量走勢) ax.grid(True, linestyle--, alpha0.3) plt.tight_layout() plt.savefig(monthly_trend.png, dpi200) plt.show()這里有一個(gè)容易踩的細(xì)節(jié)直接用 Pandas 的.plot()也能畫但默認(rèn) x 軸標(biāo)簽常常是「1 2 3 ... 12」這種干巴巴的數(shù)字不專業(yè)。set_xticks和set_xticklabels這兩行的作用就是顯式地指定刻度位置和刻度名稱把 1 變 1 月。很多新手畫時(shí)間圖時(shí)橫坐標(biāo)密集成一團(tuán)毛線原因就是忽略了這兩個(gè)方法。markero是為了在折線上標(biāo)出數(shù)據(jù)點(diǎn)論文中用黑白打印也能看清趨勢。另外grid我習(xí)慣開后加虛線透明樣式能讓讀者更專注看數(shù)據(jù)。4.3 交叉維度天氣與事故類型的熱力圖單維度圖雖然清晰但熱力圖這種交叉分析才是答辯時(shí)的加分項(xiàng)。它能同時(shí)體現(xiàn)兩個(gè)分組變量的關(guān)系比如惡劣天氣下追尾事故是不是明顯增多。Seaborn 的heatmap可以直接吃 Pandas 的透視表import seaborn as sns crosstab pd.crosstab(acc[weather], acc[accident_type]) fig, ax plt.subplots(figsize(8, 6)) sns.heatmap(crosstab, annotTrue, fmtd, cmapYlOrRd, linewidths0.5, linecolorwhite) ax.set_title(天氣狀況與事故類型交叉分析) ax.set_xlabel(事故類型) ax.set_ylabel(天氣狀況) plt.tight_layout() plt.savefig(weather_type_heatmap.png, dpi200) plt.show()pd.crosstab是透視表函數(shù)它生成行是天氣、列是事故類型的計(jì)數(shù)矩陣。annotTrue表示在格子中顯示數(shù)字fmtd表示用整數(shù)格式顯示不然你會(huì)看到1.0這種很業(yè)余的輸出。配色cmapYlOrRd從淺黃到深紅深色自然代表高發(fā)組合。linewidths0.5用于分隔每個(gè)小格子視覺上更加整齊。這個(gè)圖值得多花點(diǎn)時(shí)間觀察有時(shí)候某個(gè)格子的數(shù)值遠(yuǎn)超其他格子那就說明天氣和事故類型之間存在明顯的相關(guān)關(guān)系可以直接寫進(jìn)論文的分析結(jié)論。4.4 多圖組合輸出讓 Notebook 的報(bào)告感更強(qiáng)單張圖保存成 PNG 當(dāng)然沒問題但如果能做到在同一個(gè) Notbook 里分區(qū)域展示報(bào)告感會(huì)強(qiáng)很多。我用subplots做一張 1 行 2 列的組合圖左邊是省份分布、右邊是月度趨勢讓對比更直觀fig, axes plt.subplots(1, 2, figsize(14, 5)) # 左邊月度趨勢 axes[0].plot(monthly.index, monthly.values, markero) axes[0].set_title(月度事故數(shù)量) axes[0].set_xticks(range(1, 13)) # 右邊天氣占比餅圖 weather_cnt acc[weather].value_counts() axes[1].pie(weather_cnt.values, labelsweather_cnt.index, autopct%.1f%%, startangle90) axes[1].set_title(天氣分布占比) plt.tight_layout() plt.savefig(combined_chart.png, dpi200) plt.show()subplots(1, 2)生成左右兩個(gè)子圖返回的axes是一個(gè)包含兩個(gè)坐標(biāo)軸對象的數(shù)組。value_counts()直接統(tǒng)計(jì)天氣字段的類別頻次是畫餅圖前最簡單高效的聚合工具。autopct%.1f%%在餅圖中心顯示保留一位小數(shù)的百分比startangle90讓第一塊扇區(qū)從 12 點(diǎn)方向開始畫符合直覺。這個(gè)組合圖在答辯展示中非常實(shí)用一張 PPT 能容納兩種信息。5. 避坑與排查我在復(fù)現(xiàn)這套項(xiàng)目時(shí)踩過的五個(gè)坑5.1 圖里的中文全部變方塊現(xiàn)象代碼運(yùn)行無報(bào)錯(cuò)但所有標(biāo)題、軸標(biāo)簽的中文都顯示成了無法辨認(rèn)的方框。 原因Matplotlib 默認(rèn)字體庫不包含中文字體這是最常見且最常被忽略的問題。 解決在繪圖代碼前顯式指定中文字體。Windows 下最省事的方式是設(shè)置黑體或微軟雅黑import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [Microsoft YaHei, SimHei] plt.rcParams[axes.unicode_minus] False注意第二行axes.unicode_minus要設(shè)置為False否則坐標(biāo)軸上的負(fù)號會(huì)顯示成一個(gè)小方塊或亂碼。5.2 Notebook 里ImportError: No module named pandas現(xiàn)象雙擊打開acc.ipynb執(zhí)行第一行import pandas as pd就報(bào)錯(cuò)但自己單獨(dú)寫一個(gè) .py 文件又能正常運(yùn)行。 原因電腦上裝了多個(gè) Python 環(huán)境Notebook 的 kernel 指向的不是你安裝了 pandas 的那個(gè)環(huán)境。 解決我一般用 Anaconda 環(huán)境管理。在終端里檢查當(dāng)前環(huán)境conda activate base python -m pip install pandas matplotlib seaborn jupyter python -m ipykernel install --user --name base然后在 Notebook 右上角的 Kernel 菜單中選擇剛才安裝的base環(huán)境。這個(gè)坑在剛接觸 Python 的新手里出現(xiàn)概率極高不是代碼問題是環(huán)境串線問題。5.3 清洗前后行數(shù)對不上找不到原因現(xiàn)象明明只刪了重復(fù)行結(jié)果記錄數(shù)少了上百行仔細(xì)核對代碼也沒發(fā)現(xiàn)哪里多刪除了一片。 原因清洗過程中多次過濾前一步用了isna()判斷是否保留后一步又用dropna()刪掉整個(gè)行幾個(gè)動(dòng)作疊加導(dǎo)致數(shù)據(jù)丟失。 解決把清洗過程分段執(zhí)行每段打印一次行數(shù)并記錄每段刪除的行數(shù)。我通常的做法是加一個(gè)計(jì)數(shù)器字典log {} log[刪除重復(fù)] acc.duplicated().sum() acc acc.drop_duplicates() log[刪除空時(shí)間] acc[datetime].isna().sum() acc acc.dropna(subset[datetime]) print(log)這樣每一步刪掉多少行、是因?yàn)槟膫€(gè)規(guī)則刪掉的全都留痕論文里直接可引用。5.4 導(dǎo)入wwa.ipynb后代碼能跑但導(dǎo)出的 HTML 圖表全部空白現(xiàn)象在 Jupyter 里點(diǎn)File → Download as → HTML生成的網(wǎng)頁打開后圖表區(qū)域是一片空白但代碼輸出區(qū)域還在。 原因這個(gè)是你的瀏覽器緩存或 Notebook 未執(zhí)行完造成的。如果 Notebook 里的圖表是最后一次運(yùn)行后顯示的那么導(dǎo)出時(shí)頁面會(huì)嘗試重新渲染輸出流的圖片數(shù)據(jù)一旦內(nèi)存中的圖像數(shù)據(jù)被回收或 kernel 重啟過HTML 里就丟失了圖。 解決強(qiáng)制從上到下完整執(zhí)行一次所有單元格再導(dǎo)出jupyter nbconvert --to html --execute acc.ipynb --output accident.html--execute參數(shù)的作用是在轉(zhuǎn)換前自動(dòng)重啟 kernel 并按順序執(zhí)行全部單元格這能規(guī)避「沒執(zhí)行完就導(dǎo)出」的問題。5.5 假數(shù)據(jù)分布太“均勻”答辯被追問時(shí)解釋不清楚現(xiàn)象畫出來的省份分布圖特別平均每個(gè)省份的事故數(shù)量幾乎一致不符合真實(shí)業(yè)務(wù)里「東部省份明顯高于西北」的常識。 原因fake_accident_data.csv是模擬數(shù)據(jù)生成時(shí)為了演示方便默認(rèn)均勻分布。它不是真實(shí)統(tǒng)計(jì)年鑒數(shù)據(jù)。 解決最穩(wěn)妥的做法是在論文「數(shù)據(jù)來源」一節(jié)明確寫清「本研究使用模擬數(shù)據(jù)驗(yàn)證方法流程」并在圖表下方加一句腳注。如果你需要做更真實(shí)的分布可以自己手動(dòng)調(diào)整權(quán)重生成一份新數(shù)據(jù)保留舊文件做對照。我的習(xí)慣是往下調(diào)province列的采樣概率用random.choices加weights參數(shù)跑一次就能得到一條更有說服力的長尾分布。6. 從 Notebook 到答辯材料把演示過程做成閉環(huán)6.1 用 nbconvert 輸出一份導(dǎo)師能直接打開的報(bào)告上面已經(jīng)提過基礎(chǔ)的導(dǎo)出命令這里再給一個(gè)自己常用的組合。導(dǎo)出 HTML 只是其中一環(huán)建議把每個(gè) Notebook 的執(zhí)行結(jié)果也保留下來方便在論文附錄里引用jupyter nbconvert --to html --execute acc.ipynb --output accident_report.html jupyter nbconvert --to html --execute wwa.ipynb --output weather_report.html如果導(dǎo)出結(jié)果太大可以加--template classic參數(shù)它會(huì)讓頁面變得比較樸素但不會(huì)丟失任何圖像內(nèi)容。答辯前我會(huì)把這個(gè) HTML 文件放到和preprocessed_accident_data.csv同級的目錄下用瀏覽器在投影上完整走一遍。6.2 給圖表補(bǔ)一個(gè)業(yè)務(wù)可讀的「結(jié)論標(biāo)注」圖像文件本身不會(huì)說話答辯時(shí)老師盯著圖看十秒自己心里得有底。我的習(xí)慣是每張圖保存后在 Notebook 的 Markdown 單元格里寫兩句話這圖為什么存在、結(jié)論是什么。案例寫法如下結(jié)論月度趨勢圖顯示 12 月事故數(shù)量明顯上升。 可能原因冬季天氣復(fù)雜、道路結(jié)冰概率增加。 局限性本數(shù)據(jù)為模擬數(shù)據(jù)趨勢結(jié)論僅在數(shù)據(jù)范圍內(nèi)有效。這種結(jié)構(gòu)的好處是讓整個(gè) Notebook 有「發(fā)現(xiàn)問題 → 解釋問題」的完整鏈路而非圖表羅列。老師翻到任何一張圖都能看到對應(yīng)的文字記錄這會(huì)直接拉高印象分。6.3 自我驗(yàn)證用抽樣與匯總檢查結(jié)果合理性在正式提交前我會(huì)做一次反向校驗(yàn)。具體做法是把清洗后的數(shù)據(jù)按省份分組匯總再手工抽取一個(gè)省份核對明細(xì)記錄數(shù)是否一致check pd.read_csv(preprocessed_accident_data.csv, encodingutf-8-sig) pivot check.groupby(province).size().reset_index(namecounts) # 抽查一個(gè)省份該省明細(xì)行數(shù)應(yīng)等于分組數(shù) sample_province 廣東 detail_count (check[province] sample_province).sum() pivot_count pivot.loc[pivot[province] sample_province, counts].iloc[0] print(f明細(xì)行數(shù){detail_count}分組計(jì)數(shù){pivot_count})這個(gè)驗(yàn)證的意義在于它能排查出清洗階段常見的重復(fù)刪除或索引錯(cuò)位問題。兩個(gè)值相等說明數(shù)據(jù)一致不等請回到上一節(jié)的分段日志去找丟失在哪一步。從那以后我每次交付任何數(shù)據(jù)報(bào)告都會(huì)強(qiáng)制自己走一遍「抽樣 → 匯總 → 對照」的驗(yàn)證流程這個(gè)習(xí)慣幫我擋掉了至少三次數(shù)據(jù)不一致的事故希望也能幫到你。本文還有配套的精品資源點(diǎn)擊獲取