💰银行账户工资分类统计题解析(SQL + Pandas)
在数据分析和数据处理的实际工作中,经常会遇到「将连续型变量分类并统计」的问题。本篇文章将结合一道 LeetCode 风格的 SQL 题目,详细解析如何用 SQL 和 Pandas 分别实现工资分类统计任务,并分析两种方法的优劣。
🧩题目描述
你有一个关于银行账户的表 Accounts
,包含以下字段:
列名 | 类型 |
---|---|
account_id | int |
income | int |
account_id
是主键,每一行代表一个银行账户的月收入。
你的任务是:
将所有账户按月收入分为三个类别,并统计每类的账户数量。
工资类别定义如下:
- Low Salary:所有工资 严格低于 $20000
- Average Salary:工资 在 $20000 到 $50000 之间(含)
- High Salary:所有工资 严格高于 $50000
❗注意事项:
- 输出必须包含三个类别,即使某一类的账户数量为 0。
- 输出顺序不限。
🧠解题分析
这是一个典型的「分组统计」问题,难点主要在于:
- 如何根据
income
的值划分类别。 - 如何保证所有三类都出现在输出中(即使某类为 0)。
- 如何高效、简洁地实现这一逻辑。
我们可以使用 SQL 的 CASE WHEN
、LEFT JOIN
等语法来构造逻辑分组。Pandas 中可以使用 cut()
函数来划分区间,再进行分组汇总。
🛠️解题方法
方法一:使用 SQL 实现(适用于 MySQL)
SELECT
category,
COUNT(a.account_id) AS accounts_count
FROM (
SELECT 'Low Salary' AS category
UNION ALL
SELECT 'Average Salary'
UNION ALL
SELECT 'High Salary'
) AS categories
LEFT JOIN Accounts a
ON (category = 'Low Salary' AND income < 20000)
OR (category = 'Average Salary' AND income BETWEEN 20000 AND 50000)
OR (category = 'High Salary' AND income > 50000)
GROUP BY category;
✅ 解读:
- 构造了一个 包含三个工资类别的临时表
categories
。 - 通过
LEFT JOIN
将账户与对应类别进行匹配。 - 使用
COUNT()
汇总每个类别的账户数。 - 即使某个类别中没有匹配项,依然会显示出来,数量为
0
。
替代写法(MySQL 8.0+,使用 CTE):
WITH categories AS (
SELECT 'Low Salary' AS category
UNION ALL
SELECT 'Average Salary'
UNION ALL
SELECT 'High Salary'
)
SELECT
c.category,
COUNT(a.account_id) AS accounts_count
FROM categories c
LEFT JOIN Accounts a
ON (c.category = 'Low Salary' AND income < 20000)
OR (c.category = 'Average Salary' AND income BETWEEN 20000 AND 50000)
OR (c.category = 'High Salary' AND income > 50000)
GROUP BY c.category;
方法二:使用 Pandas 实现
如果你在做数据分析而非数据库查询,Pandas 提供了同样优雅的解法:
import pandas as pd
# 假设 accounts 是读取来的 DataFrame
accounts['category'] = pd.cut(
accounts['income'],
bins=[-float('inf'), 20000, 50000, float('inf')],
labels=['Low Salary', 'Average Salary', 'High Salary'],
right=False # 区间左闭右开:满足 <20000, [20000, 50000], >50000
)
# 分组统计
result = accounts.groupby('category').size().reindex(
['Low Salary', 'Average Salary', 'High Salary'],
fill_value=0
).reset_index(name='accounts_count')
✅ 解读:
pd.cut()
用于对income
按区间分组。groupby().size()
获取每组数量。- 使用
reindex()
确保所有类别都存在,填充缺失类别为 0。
📊示例说明
假设原始表 Accounts
如下:
account_id | income |
---|---|
1 | 10000 |
2 | 20000 |
3 | 30000 |
4 | 60000 |
期望输出:
category | accounts_count |
---|---|
Low Salary | 1 |
Average Salary | 2 |
High Salary | 1 |
⚖️方法对比分析
比较维度 | SQL 方法 | Pandas 方法 |
---|---|---|
使用场景 | 数据库查询,适用于后端开发或数据工程任务 | 本地数据分析,适用于数据分析/建模阶段 |
分类方式 | LEFT JOIN + 条件匹配 | pd.cut() 划分区间 |
保证全类输出 | 使用 UNION ALL 构造类别表 + LEFT JOIN | 使用 reindex() 明确补齐缺失类别 |
简洁性 | 相对更冗长 | 更简洁、直观 |
可扩展性 | 适合在 SQL 管道中集成 | 适合进一步结合可视化、模型训练等任务 |
🏁结语
本题的核心考点在于「分类映射 + 分组计数 + 保证完整类别输出」。无论是使用 SQL 还是 Pandas,理解背后的逻辑都是最重要的。在实际开发中,选择哪种方法应根据你所处的工作流程、数据规模和任务需求来定。
掌握这种技巧,不仅可以处理工资类问题,也适用于用户分群、商品定价区间分析、成绩等级划分等各种业务场景。