「總銷售額最高的 3 個品類」拆成三個動作:分組(groupby('category'))、加總(['sales'].sum())、排名取前三(nlargest(3, 'sales'))——缺一不可。本站把四個選項全部真的跑一遍:A 拿到的是類別名排序的前三個(head 不排名)、B 拿到全場最小的三筆單(升冪+單筆雙重錯)、C 的 tail(3) 撈到墊底兩名——只有 D 抓出真正的前三:手機 110000、筆電 105000、平板 60000。加映:平均王是筆電、單筆冠軍是手錶——問題問什麼,就得聚什麼、排什麼。
orders 有 category 與 sales 欄位。若要取得「總銷售額最高的 3 個品類」,下列 pandas 程式何者正確?
# orders 每列是一筆訂單明細 # 欄位:category, sales # A. orders.groupby('category')['sales'].mean().head(3) # 平均?head? # B. orders.sort_values('sales').head(3)[['category', 'sales']] # 沒分組?升冪? # C. orders.groupby('category', as_index=False)['sales'].sum().tail(3) # 加總對了,tail? # D. orders.groupby('category', as_index=False)['sales'].sum().nlargest(3, 'sales') # 分組、加總、取前三大
全校 23 張考卷、6 個班,要頒「總分最高的三個班」。正確流程:先把考卷按班分堆(groupby)、每堆加總(sum)、最後按總分排名取前三(nlargest)——三步缺一不可。
四個選項就是四種頒獎方式:D 照規矩來;A 算了「平均分」還照班級名冊順序抄前三個班(head 不是排名,是「名冊上最前面的」);B 根本沒分班,直接找出全校分數最低的三張考卷(sort_values 預設升冪、head 取頭);C 加總做對了,卻照名冊抄最後三個班——tail 也不是排名。head 與 tail 拿的是「位置」,nlargest 拿的才是「名次」。
sum()——mean 是平均、每筆明細是單筆,都不是總額。② groupby 完的結果按類別名排序(實跑鍵序:平板、手機、手錶、筆電、耳機、配件)——所以 head(3)/tail(3) 拿到的是「名冊位置」,跟銷售額無關。③ nlargest(3, 'sales') = 按 sales 排名取前三大——與 sort_values('sales', ascending=False).head(3) 等價(實跑逐列相同)。點擊後出現漸進式說明:白話說明 → 說清楚一點 → 常見錯誤與考點。
點擊後出現漸進式說明。
把 D 拆成三段讀——分組、加總、排名。右上角的「看位置」可以把這一段放回完整程式裡看。
orders.groupby('category', as_index=False) # 按品類分堆;結果把 category 當一般欄
groupby('category') 把 23 筆訂單按品類分成六堆(實跑:手機 4 筆、筆電 3、平板 3、耳機 5、手錶 2、配件 6)。as_index=False 是個小開關:加總後的結果把 category 當一般欄位(DataFrame),而不是索引——這決定了待會 nlargest 要怎麼寫(05 節顯微鏡伺候)。
['sales'].sum() # 只挑 sales 欄、每堆全部相加——六堆變六個總額
['sales'] 指定只聚合這一欄;sum() 把每堆加總。實跑六個總額:手機 110000、筆電 105000、平板 60000、手錶 53000、耳機 16000、配件 1800。題目問「總銷售額」——sum 是唯一對的動詞:mean 算的是「平均每筆」(平均王是筆電 35000,跟總額王手機是兩張榜)、不聚合的單筆明細更不是總額。
.nlargest(3, 'sales') # 按 sales 由大到小取 3 列——「最高」在這裡實現
nlargest(3, 'sales') = 按 sales 欄排名取前三大。實跑結果:手機 110000、筆電 105000、平板 60000——與 sort_values('sales', ascending=False).head(3) 逐列相同(實跑 equals True)。關鍵區別:head/tail 拿「位置」(表的前幾列、後幾列),nlargest 拿「名次」——而 groupby 完的表是按類別名排的(鍵序:平板、手機、手錶、筆電、耳機、配件),位置與銷售額毫無關係——A 與 C 就是死在這裡。
本站實跑資料:6 品類、23 筆明細。同一批訂單,用三種聚合各排一張榜——先看清楚「哪張榜才是題目要的」:
選擇題最狠的驗證法:四段程式全部執行,把各自回傳的表擺出來對質:
「取前三大」有好幾種寫法、也有好幾種假貨。三件展品(全部實跑):
orders.nlargest(3, 'sales') 拿到的是三筆最大的訂單:手錶 48000、筆電 42000、筆電 35000——手錶靠一張 48000 的大單當單筆冠軍,品類總額 53000 卻只排第四;筆電還重複出現兩次。「品類的前三」與「訂單的前三」是兩個問題——先分組聚合,排名才有正確的單位。C 與 D 都寫了 as_index=False——它不是裝飾,它決定 nlargest 的寫法:
groupby('category')['sales'].sum() 回 Series——category 是索引、只有一欄數字,取前三寫 nlargest(3)(不用欄名);as_index=False 回 DataFrame——columns = ['category', 'sales'],取前三要指名 nlargest(3, 'sales')。兩條路實跑同一個答案(手機/筆電/平板)——認得兩種簽名,考題換皮就不慌;D 的寫法(False + 欄名)自我一致,正確。這型題目考的是「中文題幹 → pandas 動詞」的翻譯。掃描表一次備齊:
| 題幹關鍵字 | 翻譯成 pandas | 選錯的下場(本題實跑) |
|---|---|---|
| 「總」銷售額 | sum() | 用 mean → 平均榜(王是筆電,不是手機) |
| 「品類」 | groupby('category') | 不分組 → 單位變「訂單」(B、單筆陷阱) |
| 「最高的 3 個」 | nlargest(3, ...) 或降冪排序+head(3) | head/tail 直接上 → 拿到鍵序位置(A、C) |
-- 同一件事的 SQL 寫法 SELECT category, SUM(sales) AS total # 分組加總 FROM orders # 訂單明細表 GROUP BY category # 「品類」 ORDER BY total DESC # 「最高」=降冪 LIMIT 3 # 「3 個」
第一層:mean 是平均不是總額——平均榜的王是筆電 35000(單價高筆數少),總額榜的王是手機——兩張榜前三名不同。第二層更致命:head(3) 不排名——groupby 完的結果按類別名排(鍵序:平板、手機、手錶…),實跑 A 回傳 [平板、手機、手錶]——「名冊前三個」,跟高低完全無關。
沒有 groupby——單位還是「訂單」不是「品類」;sort_values 預設升冪——head(3) 取的是最小的頭。實跑回傳:[配件 250、配件 280、配件 300]——「總銷售額最高的 3 個品類」變成「全場最便宜的三筆單」,方向與單位雙殺。就算加了 ascending=False 也只是「最大三筆單」(手錶 48000…),依然不是品類總額。
前半段完全正確(分組+加總+as_index=False)——它是最像正解的錯誤。敗在最後一步:tail(3) 拿「表的最後三列」,而這張表按類別名排——實跑回傳 [筆電 105000、耳機 16000、配件 1800]:混進了全場墊底兩名。tail 跟「最高」之間,隔著一次排序的距離。
三個動作對三個關鍵字:「品類」= groupby('category')、「總」= sum()、「最高的 3 個」= nlargest(3, 'sales')。實跑答案:手機 110000、筆電 105000、平板 60000——與降冪排序+head(3) 逐列相同(equals True)、與 Series 版 nlargest(3) 同值。總額用 sum、排名用 nlargest——一句話收工。
再看一次四個選項。這次你手上有掃描表了:「總」→ sum、「品類」→ groupby、「最高的 3 個」→ nlargest——head 與 tail 都只是位置。
orders.groupby('category', as_index=False)['sales'].sum().nlargest(3, 'sales') # 分組 → 加總 → 排名
八題,全部都是本題的延伸。答錯會直接告訴你錯在哪。
groupby('category')、「總」= sum()、「最高的 3 個」= nlargest(3, 'sales')——正解 D 一條鏈做完。sort_values('sales', ascending=False).head(3) 逐列相同(equals True)。orders.nlargest(3,'sales')(沒 groupby)= [手錶 48000、筆電 42000、筆電 35000]——手錶單筆冠軍、品類總額只排第四;先聚合,排名才有正確單位。nlargest(3) 不用欄名);False 回 DataFrame(nlargest(3, 'sales') 指名欄)——兩條路同答案,簽名不同。nlargest(3,'sales') ≡ 降冪排序+head(3) ≡ Series 版 .sum().nlargest(3)——認得全家,換皮不慌。「分組聚合+排名取前 N」是中級科目二大數據處理分析與應用的高頻考點,SQL 的 GROUP BY 排行榜題換 pandas 皮。最常見的六種問法:① 給四段程式選「總額最高前 N」(本題——掃關鍵字:總→sum、品類→groupby、最高→nlargest);② 考 head 與 nlargest 的差別(位置 vs 名次——groupby 完按鍵排序);③ 考 sort_values 的預設方向(升冪——取最大要 ascending=False 或 nlargest);④ 考 mean 與 sum 的榜差(平均王 ≠ 總額王);⑤ 考不分組直接排名的單位錯置(單筆前三 ≠ 品類前三);⑥ 考 as_index 與 nlargest 簽名(Series 不用欄名、DataFrame 要指名)。一句口訣:總額用 sum、排名用 nlargest——head 是位置,不是名次。
因為 head 只回傳「表的前三列」——它完全不看數值。而 groupby 聚合完的表有自己的順序:按分組鍵排序(實跑鍵序:平板、手機、手錶、筆電、耳機、配件——中文按字元編碼排)。所以 A 的 mean().head(3) 拿到 [平板、手機、手錶]、C 的 sum().tail(3) 拿到 [筆電、耳機、配件]——都是「名冊位置」不是「成績名次」。head 唯一合法的取前 N 用法:先排序再 head——sort_values('sales', ascending=False).head(3),實跑與 nlargest 逐列相同。記法:head 是位置、nlargest 是名次;沒排序的 head 是抽籤。
預設升冪(ascending=True)——由小到大。所以 B 的 sort_values('sales').head(3) 取的是「最小的頭」:實跑回傳 [配件 250、配件 280、配件 300]。B 總共錯三層:①方向——升冪的 head 是最小;②單位——沒有 groupby,每列還是「一筆訂單」,不是「一個品類」;③語意——就算改成降冪也只是「最大三筆單」(手錶 48000、筆電 42000、筆電 35000——筆電重複出現),依然回答不了「品類總額」的問題。考場動作:看到 sort_values 沒寫 ascending=False,先想「它在找小的」。
本站實跑就是活例:總額榜前三=手機 110000、筆電 105000、平板 60000;平均榜前三=筆電 35000、手機 27500、手錶 26500——兩張榜的王不同、前三名也不同。機制:mean = sum ÷ 筆數——筆數就是槓桿。手機靠 4 筆中價單「積少成多」拿總額王;筆電單價高但只有 3 筆,平均王、總額第二;配件 6 筆全場最多、總額卻墊底 1800。所以聚合動詞不是文字遊戲:「總銷售額」只認 sum;題目若問「平均客單價最高」才輪到 mean——先圈題幹的量詞,再選動詞。
「最大的三筆訂單」——單位是訂單、不是品類。實跑:[手錶 48000、筆電 42000、筆電 35000]——手錶靠一張 48000 的巨單當單筆冠軍,但它的品類總額 53000 只排第四;筆電在榜上重複出現兩次(同品類的兩筆單)。這就是單位錯置:問題問「品類」層級、你在「訂單」層級排名——數字都是真的、答案整個是錯的。防呆流程:先問「排名的單位是什麼」→ 單位不是原始列,就先 groupby 聚合到那個單位,再排名。
差在回傳的容器。預設 True:groupby('category')['sales'].sum() 回 Series——category 變成索引、值只有一欄,取前三寫 nlargest(3)(Series 只有一欄,不用指名)。as_index=False:回 DataFrame——category 是一般欄位(實跑 columns = ['category', 'sales']),nlargest 要指定按哪欄排:nlargest(3, 'sales')。兩條路實跑同答案。什麼時候偏好 False?後續要把 category 當欄位用時(畫圖 hue、再 merge、輸出報表)——不用再 reset_index。考點:題目寫了 as_index=False 又寫 nlargest(3, 'sales')——簽名自我一致,這是 D 正確的完整性檢查。
實跑驗證過的三條路:① 題目的 D:groupby('category', as_index=False)['sales'].sum().nlargest(3, 'sales');② 降冪排序版:...sum().sort_values('sales', ascending=False).head(3)——與 ① 逐列相同(equals True);③ Series 版:groupby('category')['sales'].sum().nlargest(3)——同值。延伸親戚:取最小 N 用 nsmallest;多欄聚合用 agg(total=('sales','sum'), avg=('sales','mean')) 一次算兩張榜;要每組內的前 N 筆(另一種考法)則是 groupby().head(N) 或 sort_values().groupby().head(N)——注意那是「每組取 N 筆明細」,跟本題「取 N 個組」不同題。
SQL 對照逐句翻譯:GROUP BY category(品類)+ SUM(sales)(總)+ ORDER BY SUM(sales) DESC LIMIT 3(最高的 3 個)——nlargest 就是 ORDER BY DESC + LIMIT 的縮寫。系列串接:科目二資料整形三部曲在此集齊——第 17 頁篩選與合併(留下誰)→ 第 16 頁 melt 整形與分組圖(長什麼樣)→ 本頁聚合排名(誰第一);第 16 頁 barplot 的 estimator=sum 就是本頁 groupby sum 的圖形版。手法上,「head 長得像排名但不是」與第 13 頁「0.2857 長得像 recall 但是 precision」同款考點:長得像答案的東西最危險——動詞與分母,永遠先驗明正身。