如何基于前序groupby结果实现层级分组?多产品销售选址场景
实现多层级选址逻辑(按产品→国家→区域→城市筛选)
你遇到的问题核心是跳过了层级筛选的递进步骤——直接按产品+城市分组取最大值,会忽略「先选最高销量国家,再在该国选区域,最后选城市」的业务逻辑。下面我会给出一个可复用的pandas解决方案,支持多产品场景,还能完整保存每一步的筛选结果。
步骤说明
我们需要对每个产品独立执行三层递进筛选:
- 计算该产品在各国的总销量,选出销量最高的国家
- 在选中的国家范围内,计算各区域总销量,选出销量最高的区域
- 在选中的区域范围内,计算各城市总销量,选出销量最高的城市
同时,我们会把每一步的结果(比如每个产品对应的Top国家、Top区域)都留存下来,方便后续业务分析。
完整代码实现
1. 构造多产品示例数据
先模拟一个包含「椅子」和「桌子」两类产品的数据集,贴合你的多产品业务场景:
import pandas as pd # 构造多产品销售数据 data = { 'Product': ['Chair']*13 + ['Table']*8, 'Country': ['USA','USA', 'China','China','China','China','India', 'India','India','India','India','India', 'India'] + ['USA','USA','China','China','India','India','India','India'], 'Region': ['USA_West','USA_East', 'China_West','China_East','China_South','China_South', 'India_North','India_North', 'India_North','India_West','India_West','India_East','India_South'] + ['USA_West','USA_East','China_West','China_East','India_North','India_North','India_West','India_West'], 'City': ['A','B', 'C','D','E', 'F', 'G','H','I', 'J','K', 'L', 'M'] + ['A','B','C','D','G','H','J','K'], 'Sales': [1000,1000, 1200,200,200, 200,500 ,350,350,100,700,50,50] + [800,900,1500,300,400,300,200,600] } dff = pd.DataFrame(data)
2. 定义多层级筛选函数
写一个自定义函数,输入单个产品的子数据集,输出该产品的三层筛选结果:
def get_top_location(product_df): # 第一步:筛选销量最高的国家 country_sales = product_df.groupby('Country')['Sales'].sum().reset_index() top_country = country_sales.nlargest(1, 'Sales').iloc[0] # 取销量最高的第一个国家(若有并列可调整逻辑) top_country_name = top_country['Country'] top_country_total = top_country['Sales'] # 第二步:在选中国家内筛选销量最高的区域 country_filtered = product_df[product_df['Country'] == top_country_name] region_sales = country_filtered.groupby('Region')['Sales'].sum().reset_index() top_region = region_sales.nlargest(1, 'Sales').iloc[0] top_region_name = top_region['Region'] top_region_total = top_region['Sales'] # 第三步:在选中区域内筛选销量最高的城市 region_filtered = country_filtered[country_filtered['Region'] == top_region_name] city_sales = region_filtered.groupby('City')['Sales'].sum().reset_index() # 若城市有多条销售记录,先求和 top_city = city_sales.nlargest(1, 'Sales').iloc[0] top_city_name = top_city['City'] top_city_total = top_city['Sales'] # 返回每一步的结果 return pd.Series({ 'Top_Country': top_country_name, 'Top_Country_Total_Sales': top_country_total, 'Top_Region': top_region_name, 'Top_Region_Total_Sales': top_region_total, 'Top_City': top_city_name, 'Top_City_Total_Sales': top_city_total })
3. 应用到所有产品
通过groupby('Product').apply()对每个产品执行筛选,得到最终结果:
# 按产品分组,执行多层筛选 final_result = dff.groupby('Product').apply(get_top_location).reset_index() print(final_result)
4. 输出结果示例
运行后会得到如下清晰的结果,展示每个产品的三层选址信息:
Product Top_Country Top_Country_Total_Sales Top_Region Top_Region_Total_Sales Top_City Top_City_Total_Sales 0 Chair India 2100 India_North 1200 G 500 1 Table China 1800 China_West 1500 C 1500
关键细节说明
- 解决原代码问题:你之前的
groupby('Product', 'City').apply(lambda x: x.nlargest(1))是直接按「产品+城市」取最大销量,跳过了国家→区域的层级筛选,所以会错误选中全球销量最高的城市。我们的方案是逐层缩小筛选范围,确保每一步都在上一级的结果内操作。 - 处理并列情况:如果某一层级出现多个并列最高的选项(比如两个国家销量相同),可以把
iloc[0]改成筛选所有最大值的逻辑,例如:# 保留所有销量最高的国家(示例) top_countries = country_sales[country_sales['Sales'] == country_sales['Sales'].max()] - 提取中间结果:如果需要单独使用某一层的结果(比如所有产品的Top国家列表),直接从
final_result中提取即可:# 提取每个产品的Top国家及对应销量 top_countries = final_result[['Product', 'Top_Country', 'Top_Country_Total_Sales']]
内容的提问来源于stack exchange,提问作者MaximJ
相关产品推荐
相关产品推荐

