🗺️ AI 學習與考證地圖
中級科目二程式實戰 · 資料整形與視覺化

melt 融寬成長、estimator 加總:
合計看是持平,分通路看是大翻轉

每月多筆週紀錄的寬表,兩行程式變成一張分通路長條圖。本站實跑:寬表 (12, 3) 經 melt 融成長表 (24, 3),barplot 的六根條高度與 groupby(['month','channel']).sum() 一字不差(讀 ax.patches 逐根對帳)——web 450 → 600 → 780、store 780 → 620 → 450。而如果照選項 A 把兩通路相加:月合計 1230/1220/1230,幾乎一條水平線——通路大翻轉被整個藏住。這頁還埋一個版本考點:題目標「seaborn >= 0.12」,考的就是 errorbar=None 這個新 API

閱讀模式

00題目

df 每月可能有多列紀錄,欄位為 month、web、store。使用 seaborn 0.12 以上版本時,下列程式產生的圖最合理的描述為何?

long = df.melt(id_vars='month',                    # month 當「身分欄」原地保留
               value_vars=['web', 'store'],       # 這兩欄要「融」進同一欄
               var_name='channel', value_name='sales')  # 舊欄名進 channel、數值進 sales
sns.barplot(data=long, x='month', y='sales',        # 長條圖:x 軸月份、y 軸銷售
            hue='channel', estimator=sum, errorbar=None)  # 顏色分通路;同組加總;不畫誤差線

先說:月報表與流水帳

同一堆銷售紀錄有兩種記法。寬表像月報表:每列一筆紀錄、web 與 store 各佔一欄——人看很舒服。長表像收銀機流水帳:每列只記一件事——「幾月、哪個通路、多少錢」,通路變成欄位裡的而不是欄位的名字

seaborn 這類繪圖工具偏愛流水帳,理由很實際:你想「顏色照通路分」,長表只要一句 hue='channel'——因為「通路」就躺在一個欄位裡可以指名;寬表的通路藏在欄名裡,工具沒辦法指認。所以這題的兩行程式是視覺化的標準流程:先 melt 融寬成長,再把欄位名交給 x/y/hue

三個先立好的事實: melt 把 web、store 兩欄融成「channel+sales」兩欄——每列原紀錄拆成兩列(實跑 12 列 → 24 列)。 barplot聚合圖:同一「月份 × 通路」組的很多筆資料,會被 estimator 揉成一根條——本題 estimator=sum = 組內加總。 題目標「seaborn >= 0.12」不是裝飾——errorbar=None 是 0.12 起的新寫法(舊版寫 ci=None)。

先點開看:melt 融欄寬表與長表estimator 聚合器

不熟資料處理名詞?你需要先認識下列名詞

點擊後出現漸進式說明:白話說明 → 說清楚一點 → 常見錯誤與考點。

整形四件套
melt 融欄寬表與長表id_vars 身分欄value_vars 融誰
命名與整潔
var_name 與 value_nametidy data 整潔資料pivot:melt 的反向每月多列紀錄
barplot 的零件
barplot 聚合長條hue 分色estimator 聚合器預設是平均
版本與陷阱
errorbar=None舊寫法 ci=None合計的假象corr 與熱圖(D 在講的)

不熟 Python?你需要先認識下列名詞

點擊後出現漸進式說明

表格的世界
DataFrame 表格欄位 columndf.melt 方法
參數的寫法
['web','store'] 清單'month' 字串引數關鍵字引數
名字與慣例
= 指派sns 慣例縮寫

01逐行拆解:melt 三行、barplot 兩行

五行,一行一行走完。右上角的「看位置」可以把這一行放回完整程式裡看。

第 1 行melt 開工:month 當身分欄
long = df.melt(id_vars='month',   # 開始融表:month 原地保留、不被融

melt(融化)是寬表變長表的工具。id_vars='month' 指定身分欄:這欄是每筆紀錄的「身分證」,融表過程原地保留、跟著每一列走。結果存進變數 long——待會 barplot 吃的就是它。

相關名詞:melt 融欄id_vars 身分欄= 指派

第 2 行value_vars:點名要融的兩欄
               value_vars=['web', 'store'],   # 這兩欄要被「融」進同一欄

清單點名 web 與 store——它們的欄名會變成新欄位裡的數值會集中到另一欄。這就是融表的本體:原本一列同時記兩個通路,融完每列原紀錄拆成兩列(web 一列、store 一列)——本站實跑:寬表 (12, 3) 融完變長表 (24, 3)

相關名詞:value_vars 融誰['web','store'] 清單寬表與長表

第 3 行幫新欄取名:channel 與 sales
               var_name='channel', value_name='sales')   # 舊欄名進 channel、數值進 sales

var_name 幫「裝舊欄名的欄」取名(不寫預設叫 variable)、value_name 幫「裝數值的欄」取名(預設叫 value)。取好名字的長表三欄:month / channel / sales——實跑前四列:(1, web, 120)、(1, web, 95)、(1, web, 130)、(1, web, 105)。取名不是裝飾:下一行 barplot 要用這些名字指認欄位——hue='channel' 能寫,是因為這裡取了 channel。

相關名詞:var_name 與 value_nametidy data 整潔資料字串引數

第 4 行barplot 開畫:x 月份、y 銷售
sns.barplot(data=long, x='month', y='sales',   # 資料吃長表;x 軸月份、y 軸銷售

sns.barplot聚合長條圖——它不是把 24 筆資料畫 24 個東西,而是把「同一組」的資料揉成一根條data=long 指定吃剛融好的長表;x='month' 讓月份當類別軸(實跑 x 軸刻度 1、2、3);y='sales' 是要被聚合的數值。這也是選項 B 陣亡的地方:畫每一筆原始資料的是 scatterplot/stripplot,不是 barplot

相關名詞:barplot 聚合長條seaborn類別軸

第 5 行hue 分通路、estimator=sum 加總、errorbar=None
            hue='channel', estimator=sum, errorbar=None)   # 顏色分通路;同組全部加總;不畫誤差線

三個參數三件事。 hue='channel':每個月份底下分兩根不同顏色的條(實跑圖例:web、store)——「分通路」的來源。 estimator=sum:同一「月份 × 通路」組內的多筆紀錄全部加總成條高——不寫的話預設取平均(實跑:450 會變 112.5)。 errorbar=None:關掉預設的誤差線——這是 seaborn 0.12 起的新寫法,舊版寫 ci=None,題目特別標版本就是在考這個。

一句話記住本題:melt 融寬成長 → 月份 × 通路分組 → estimator=sum 組內加總 → hue 分色畫長條——選項 C 的每個字,就是這五行的白話翻譯。

相關名詞:hue 分色estimator 聚合器errorbar=None

02melt 變形記:12 列怎麼變 24 列

本站實跑資料:3 個月、每月 4 筆週紀錄——正是題目說的「每月可能有多列紀錄」。按兩顆按鈕,看同一批資料的兩種長相:

互動實驗室:melt 變形器寬表 (12, 3) ↔ 長表 (24, 3)
本站實跑:寬表 (12, 3)df.melt(...) → 長表 (24, 3),欄位 month / channel / sales。第一筆紀錄(1 月、web 120、store 200)被拆成兩列:(1, web, 120)(1, store, 200)——通路從「欄名」搬進「欄值」,這正是 seaborn 能用 hue='channel' 指認它的原因。

相關名詞:melt 融欄tidy datapivot:melt 的反向

03六根長條的來源:estimator=sum 就是 groupby 加總

barplot 拿到長表後做的事,等價於一句 pandas:long.groupby(['month','channel'])['sales'].sum()。本站直接讀圖上六根條的高度(ax.patches)跟 groupby 對帳:

互動實驗室:六根長條的來源estimator=sum vs 預設 mean——同一張圖兩種高度
web(圖例第 1 項)store(圖例第 2 項)
本站實跑對帳:題目寫法畫出 6 根條,高度由 ax.patches 讀出、排序後與 groupby 加總一字不差[450, 450, 600, 620, 780, 780]——web 450 → 600 → 780(成長)、store 780 → 620 → 450(衰退)。把 estimator=sum 拿掉:六根高度變成組內平均 [112.5, 112.5, 150, 155, 195, 195],而且多出 6 條誤差線(errorbar 預設開啟)——「加總」與「不畫誤差線」都是題目親手指定的。加碼:estimator 寫 sum'sum'np.sum 三種形式實跑同值

相關名詞:estimator 聚合器groupby 分組預設是平均

04合計的假象:選項 A 的世界會看丟什麼

選項 A 說「把 web 與 store 相加成單一折線,不區分通路」。先不論折線與長條之別——把通路加起來,這份資料會發生一件慘案

互動實驗室:合計的假象同一批資料——合計視角 vs 分通路視角
本站實跑:月合計 1230 → 1220 → 1230——三根幾乎等高,一句話總結就是「業績平穩」。但分通路一看:web 450 → 780 翻了 1.73 倍、store 780 → 450 掉了 42%——公司引擎正在整組換掉,合計視角一格都看不到。這就是 hue 分組存在的理由:總量守恆的世界裡,結構才是新聞。順帶補刀:本題程式畫的是長條不是折線——折線是 lineplot 的工作。

相關名詞:合計的假象hue 分色每月多列紀錄

05版本命案:errorbar=None 為什麼要標「>= 0.12」

題目特別寫「使用 seaborn 0.12 以上版本」——不是廢話,是API 分水嶺。三件展品(本站 seaborn 0.13.2 實跑):

互動實驗室:版本命案errorbar=None 的身世,與 estimator 的三種寫法
考點整理:0.12 之前關誤差線寫 ci=None;0.12 起改成 errorbar=None(errorbar 參數還能指定 'ci'、'sd'、'se' 等種類)。本站 0.13.2 實跑舊寫法:圖照畫,但噴 FutureWarning:The `ci` parameter is deprecated. Use `errorbar=None` for the same effect.——「還能跑但已被判死緩」。題目把版本寫進題幹,就是提示你 errorbar=None 是合法的新 API、不是錯字

相關名詞:errorbar=None舊寫法 ci=None0.12 分水嶺

06考場加碼:B 與 D 的一秒判死,和一句等價 pandas

剩下兩個選項用實跑數字補刀,順便學一招對帳技巧:

選項的主張那其實是誰的工作本站實跑補刀
B:每筆原始資料的散佈圖scatterplot/stripplotbarplot 是聚合圖:24 筆進去、只出 6 根條;且 hue='channel' 顏色代表通路,不是月份
D:相關係數矩陣+熱圖df[['web','store']].corr() + sns.heatmap實跑 r = -0.8752(web 升 store 跌,強負相關)——有趣歸有趣,但那是另一段程式

對帳技巧(值得帶走):不確定 barplot 在畫什麼時,自己先算一次等價的 pandas——long.groupby(['month','channel'])['sales'].sum()——再跟圖對。本站更進一步用 ax.patches 把六根條的高度直接讀出來比對:逐根一字不差。圖不再是黑盒子,每根條都有一句 groupby 當它的存在證明

串起系列:「聚合之後才畫圖」跟第 13 頁(macro/weighted 的加權平均)同一個靈魂——圖上的一個數,背後是一句聚合;「合計的假象」跟第 3 頁(accuracy 95% 假象)、第 13 頁(weighted 被多數類拉高)同族——被平均或合計遮住的結構,才是考點。這是科目二視覺化題的標準套路:考你「程式 → 圖」的對應,不是考美感。

相關名詞:散佈圖是誰的工作corr 與熱圖groupby 分組

07四個選項收工

A把 web 與 store 相加成單一折線,且不區分通路圖形與分組全錯

兩刀斃命: barplot長條不是折線(折線是 lineplot); hue='channel' 明明白白區分通路——每月兩根不同色的條(實跑圖例:web、store)。加映慘案:真把兩通路相加,月合計 1230/1220/1230 幾乎持平——web 翻 1.73 倍、store 掉 42% 的大翻轉整個被藏住——這張圖存在的意義就是不讓你這樣看。

B繪出每一筆原始資料的散佈圖,顏色代表月份聚合圖不是散佈圖

barplot聚合圖:實跑 24 筆原始資料進去,圖上只有 6 根條——每根是一組「月份 × 通路」被 estimator 揉出來的總和;想看每一筆原始資料,那是 scatterplotstripplot 的工作。第二刀:顏色由 hue='channel' 決定——代表通路,不是月份;月份在 x 軸。

C先轉成長表,再以月份與通路分組加總 sales,繪製分通路長條正確

每個字都對得上實跑:「先轉成長表」= melt 把 (12, 3) 融成 (24, 3)、通路從欄名搬進 channel 欄;「以月份與通路分組加總」= estimator=sum——六根條高度與 groupby(['month','channel']).sum() 一字不差(450/780、600/620、780/450);「分通路長條」= hue='channel' 每月兩根分色條。melt 融寬成長、estimator 分組加總、hue 分通路——一句話就是這一題

D計算 web 與 store 的相關係數矩陣並畫熱圖完全另一段程式

相關係數矩陣要寫 df[['web','store']].corr()、熱圖要 sns.heatmap——題目程式裡一個都沒出現。本站順手實跑給你看:r = -0.8752(web 節節上升、store 節節下滑,強負相關)——這個數字很有戲,但它不是這兩行程式的產出。考場判法:選項描述的函式根本沒被呼叫,直接出局。

回到題目:現在再作答一次

再看一次同兩行程式。這次你知道每個參數各管哪件事了:melt 融寬成長、hue 分通路、estimator=sum 分組加總、errorbar=None 是 0.12 的新 API

long = df.melt(id_vars='month', value_vars=['web', 'store'], ...)   # (12,3) → (24,3)
sns.barplot(..., hue='channel', estimator=sum, errorbar=None)   # 六根條 = groupby sum

08自我檢測

八題,全部都是本題的延伸。答錯會直接告訴你錯在哪。

09重點整理

  1. 五行程式兩件事:前三行 melt 把寬表融成長表(month 身分欄、web/store 融進 channel/sales);後兩行 barplot 用長表畫分通路長條。
  2. 正確答案 C:先轉成長表,再以月份 × 通路分組加總 sales,繪製分通路長條——三個關鍵詞對應 melt、estimator=sum、hue。
  3. melt 實跑:寬表 (12, 3) → 長表 (24, 3)——每列原紀錄拆成兩列;通路從欄名搬進欄值(channel 欄),seaborn 才能用 hue 指認它。
  4. barplot 是聚合圖:同一「月份 × 通路」組的多筆紀錄被 estimator 揉成一根條——24 筆原始資料進去、只出 6 根條(B 的死因①)。
  5. 六根條的存在證明(實跑):ax.patches 讀出的高度與 groupby(['month','channel'])['sales'].sum() 一字不差——web 450→600→780、store 780→620→450。
  6. estimator 不寫=平均:預設 mean 讓 450 變 112.5,且 errorbar 預設開啟(實跑多出 6 條誤差線)——題目寫 estimator=sum、errorbar=None 是兩個主動選擇
  7. 版本考點:0.12 前關誤差線寫 ci=None、0.12 起改 errorbar=None——本站 0.13.2 實跑舊寫法仍可跑但噴 FutureWarning;題幹標「>= 0.12」就是在提示新 API。
  8. A 的死因:barplot 畫長條非折線;hue 明明白白分通路;且合計視角實跑 1230/1220/1230 幾乎持平——把 web 翻 1.73 倍、store 掉 42% 的結構翻轉整個藏住
  9. B 的死因:聚合圖 ≠ 散佈圖(每筆一點是 scatterplot/stripplot);顏色代表通路不是月份——月份在 x 軸。
  10. D 的死因:相關係數要 df[['web','store']].corr()(實跑 r=-0.8752)+sns.heatmap——題目程式一個都沒呼叫。
  11. 對帳技巧:看不懂聚合圖就自己寫等價 groupby 對一次——圖上的每個數,背後都該有一句 pandas 當存在證明
  12. 考場口訣melt 融寬成長、hue 分通路、estimator=sum 分組加總;barplot 是聚合圖——幾組就幾根條
完整程式碼