🗺️ AI 學習與考證地圖
中級科目二程式實戰 · 分組聚合與排名

總銷售額前三名怎麼抓:
先 groupby 加總、再 nlargest 排名

「總銷售額最高的 3 個品類」拆成三個動作:分組(groupby('category'))、加總(['sales'].sum())、排名取前三(nlargest(3, 'sales'))——缺一不可。本站把四個選項全部真的跑一遍:A 拿到的是類別名排序的前三個(head 不排名)、B 拿到全場最小的三筆單(升冪+單筆雙重錯)、C 的 tail(3) 撈到墊底兩名——只有 D 抓出真正的前三:手機 110000、筆電 105000、平板 60000。加映:平均王是筆電、單筆冠軍是手錶——問題問什麼,就得聚什麼、排什麼

閱讀模式

00題目

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) 等價(實跑逐列相同)。

先點開看:groupby 分堆nlargest 排名head 是位置不是名次

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

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

分組與聚合
groupby 分堆sum 總額平均王 vs 總額王count 筆數
排名家族
nlargest 排名sort_values升冪的預設head/tail 是位置
結構與型別
as_index 開關Series 與 DataFramegroupby 的鍵序聚合鏈的流向
考場的暗器
單筆冠軍陷阱單位錯置SQL 對照題目關鍵字掃描

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

點擊後出現漸進式說明

表格的世界
DataFrame 表格['sales'] 挑欄
鏈的讀法
點點接龍as_index=False 關鍵字引數nlargest(3, 'sales') 的兩個引數
名字與慣例
'category' 字串引數False 布林值

01逐行拆解:正解 D 的三個動作

把 D 拆成三段讀——分組、加總、排名。右上角的「看位置」可以把這一段放回完整程式裡看。

動作一groupby:把 23 筆明細分成六堆
orders.groupby('category', as_index=False)   # 按品類分堆;結果把 category 當一般欄

groupby('category') 把 23 筆訂單按品類分成六堆(實跑:手機 4 筆、筆電 3、平板 3、耳機 5、手錶 2、配件 6)。as_index=False 是個小開關:加總後的結果把 category 當一般欄位(DataFrame),而不是索引——這決定了待會 nlargest 要怎麼寫(05 節顯微鏡伺候)。

相關名詞:groupby 分堆as_index 開關關鍵字引數

動作二['sales'].sum():每堆加總——「總」字的出處
['sales'].sum()   # 只挑 sales 欄、每堆全部相加——六堆變六個總額

['sales'] 指定只聚合這一欄sum() 把每堆加總。實跑六個總額:手機 110000、筆電 105000、平板 60000、手錶 53000、耳機 16000、配件 1800。題目問「銷售額」——sum 是唯一對的動詞:mean 算的是「平均每筆」(平均王是筆電 35000,跟總額王手機是兩張榜)、不聚合的單筆明細更不是總額。

相關名詞:sum 總額平均王 vs 總額王['sales'] 挑欄

動作三nlargest(3, 'sales'):排名取前三大——不是 head
.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 就是死在這裡。

一句話記住本題:總額用 sum、排名用 nlargest——「總銷售額」對應 sum、「最高的 3 個」對應 nlargest(3)。head 是位置、tail 是位置,只有 nlargest(或先降冪排序再 head)是名次

相關名詞:nlargest 排名head/tail 是位置nlargest 的兩個引數

02品類成績單:sum 的榜、mean 的榜、count 的榜

本站實跑資料:6 品類、23 筆明細。同一批訂單,用三種聚合各排一張榜——先看清楚「哪張榜才是題目要的」

互動實驗室:品類成績單總額/平均/筆數——三張榜三個王
本站實跑三個王:總額王=手機 110000(4 筆中價單積少成多);平均王=筆電 35000(單價高但筆數少,總額只排第二);筆數王=配件 6 筆(總額卻墊底 1800)。三張榜的前三名各不相同——「總銷售額最高」只認 sum 的榜:選 mean 的 A 在第一個字就走錯路。

相關名詞:sum 總額平均王 vs 總額王count 筆數

03四選項執行器:每一段程式真的跑給你看

選擇題最狠的驗證法:四段程式全部執行,把各自回傳的表擺出來對質:

互動實驗室:四選項執行器A/B/C/D 各自回傳什麼——全實跑
三個錯法三種病(實跑):A 回傳 [平板、手機、手錶]——那是類別名排序的前三個(head 不排名),而且 mean 根本不是總額;B 回傳 [配件 250、配件 280、配件 300]——sort_values 預設升冪+沒有分組:「最高的品類」變成全場最低的三筆單C 回傳 [筆電、耳機、配件]——tail(3) 抓鍵序的最後三個,撈到全場墊底兩名(耳機 16000、配件 1800)。只有 D:[手機 110000、筆電 105000、平板 60000]。

相關名詞:head/tail 是位置升冪的預設groupby 的鍵序

04排名家族:等價寫法、單筆陷阱、位置的真相

「取前三大」有好幾種寫法、也有好幾種假貨。三件展品(全部實跑):

互動實驗室:排名家族等價寫法/單筆冠軍陷阱/head 與 tail 的真相
單筆冠軍陷阱(實跑):不 groupby 直接 orders.nlargest(3, 'sales') 拿到的是三筆最大的訂單:手錶 48000、筆電 42000、筆電 35000——手錶靠一張 48000 的大單當單筆冠軍,品類總額 53000 卻只排第四;筆電還重複出現兩次。「品類的前三」與「訂單的前三」是兩個問題——先分組聚合,排名才有正確的單位

相關名詞:單筆冠軍陷阱單位錯置sort_values

05as_index 顯微鏡:Series 與 DataFrame 的兩種 nlargest

C 與 D 都寫了 as_index=False——它不是裝飾,它決定 nlargest 的寫法:

互動實驗室:as_index 顯微鏡True 回 Series、False 回 DataFrame——nlargest 兩種簽名
實跑對照:預設(True)的 groupby('category')['sales'].sum()Series——category 是索引、只有一欄數字,取前三寫 nlargest(3)不用欄名);as_index=FalseDataFrame——columns = ['category', 'sales'],取前三要指名 nlargest(3, 'sales')。兩條路實跑同一個答案(手機/筆電/平板)——認得兩種簽名,考題換皮就不慌;D 的寫法(False + 欄名)自我一致,正確。

相關名詞:as_index 開關Series 與 DataFramenlargest 的兩個引數

06考場加碼:關鍵字掃描、SQL 對照

這型題目考的是「中文題幹 → 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 個」
串起系列:「一根條/一個數背後是一句聚合」——第 16 頁的 barplot estimator 就是本頁的 groupby sum 畫成圖;第 17 頁的 query+merge 管「留下誰」、本頁管「誰第一」——科目二資料整形三部曲到此集齊:篩選(17)→ 整形(16)→ 聚合排名(本頁)。而「head 不是排名」與第 13 頁「0.2857 不是 recall」同款:長得像答案的東西,考場上最危險

相關名詞:SQL 對照題目關鍵字掃描聚合鏈的流向

07四個選項收工

Aorders.groupby('category')['sales'].mean().head(3)兩層全錯

第一層:mean 是平均不是總額——平均榜的王是筆電 35000(單價高筆數少),總額榜的王是手機——兩張榜前三名不同。第二層更致命:head(3) 不排名——groupby 完的結果按類別名排(鍵序:平板、手機、手錶…),實跑 A 回傳 [平板、手機、手錶]——「名冊前三個」,跟高低完全無關。

Borders.sort_values('sales').head(3)[['category', 'sales']]升冪+單筆雙重錯

沒有 groupby——單位還是「訂單」不是「品類」;sort_values 預設升冪——head(3) 取的是最小的頭。實跑回傳:[配件 250、配件 280、配件 300]——「總銷售額最高的 3 個品類」變成「全場最便宜的三筆單」,方向與單位雙殺。就算加了 ascending=False 也只是「最大三筆單」(手錶 48000…),依然不是品類總額。

Corders.groupby('category', as_index=False)['sales'].sum().tail(3)加總對了,tail 不是排名

前半段完全正確(分組+加總+as_index=False)——它是最像正解的錯誤。敗在最後一步:tail(3) 拿「表的最後三列」,而這張表按類別名排——實跑回傳 [筆電 105000、耳機 16000、配件 1800]:混進了全場墊底兩名。tail 跟「最高」之間,隔著一次排序的距離。

Dorders.groupby('category', as_index=False)['sales'].sum().nlargest(3, 'sales')正確

三個動作對三個關鍵字:「品類」= 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')   # 分組 → 加總 → 排名

08自我檢測

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

09重點整理

  1. 題目三個關鍵字對三個動作:「品類」= groupby('category')、「總」= sum()、「最高的 3 個」= nlargest(3, 'sales')——正解 D 一條鏈做完。
  2. 正確答案 D:實跑 手機 110000、筆電 105000、平板 60000——與 sort_values('sales', ascending=False).head(3) 逐列相同(equals True)。
  3. head/tail 是位置、nlargest 是名次:groupby 完的表按類別名排(實跑鍵序:平板、手機、手錶、筆電、耳機、配件)——位置與銷售額無關。
  4. A 的兩層錯(實跑):mean 是平均不是總額(平均王筆電 35000 ≠ 總額王手機);head(3) 拿到鍵序前三個 [平板、手機、手錶]——不是任何排名。
  5. B 的雙重錯(實跑):沒分組(單位是訂單不是品類)+ sort_values 預設升冪——回傳全場最小三筆單 [配件 250、280、300]。
  6. C 的一步之遙(實跑):分組加總全對,tail(3) 卻拿鍵序最後三個 [筆電、耳機、配件]——混進墊底兩名;它是「最像正解的錯誤」。
  7. 單筆冠軍陷阱(實跑)orders.nlargest(3,'sales')(沒 groupby)= [手錶 48000、筆電 42000、筆電 35000]——手錶單筆冠軍、品類總額只排第四;先聚合,排名才有正確單位。
  8. 三張榜三個王(實跑):總額王手機(積少成多)、平均王筆電(單價高)、筆數王配件(總額墊底)——聚合動詞決定答案。
  9. as_index 顯微鏡:預設 True 回 Series(nlargest(3) 不用欄名);False 回 DataFrame(nlargest(3, 'sales') 指名欄)——兩條路同答案,簽名不同。
  10. 等價寫法清單nlargest(3,'sales') ≡ 降冪排序+head(3) ≡ Series 版 .sum().nlargest(3)——認得全家,換皮不慌。
  11. SQL 對照:GROUP BY category + ORDER BY SUM(sales) DESC + LIMIT 3——同一題的兩種方言。
  12. 考場口訣總額用 sum、排名用 nlargest;head 是位置、tail 是位置,只有 nlargest 是名次
完整程式碼