基于Hungarian_rate划分区间,实现各区间人口总和均衡的Python方案
按人口总和均衡划分Hungarian_rate区间的解决方案
要实现基于Hungarian_rate划分区间且每组人口总和尽可能均衡,不能直接用pd.qcut(仅按样本数量均分),需先按Hungarian_rate排序,再通过动态规划找到最优分组(最小化各组人口与目标值的误差),具体步骤如下:
步骤1:数据预处理与目标计算
先按Hungarian_rate从小到大排序(区间需保持rate的连续性),再计算总人口和每组目标人口:
import pandas as pd data = { "Town": ["F", "A", "N", "O", "B", "L", "C", "K", "J", "E", "G", "M", "I", "D", "H"], "Hungarian_rate": [1, 4, 5, 8, 9, 10, 15, 15, 20, 22, 23, 31, 41, 60, 75], "Population": [40, 10, 30, 50, 30, 20, 40, 30, 20, 20, 20, 10, 40, 50, 30] } df = pd.DataFrame(data) # 按Hungarian_rate排序,保证区间连续性 df_sorted = df.sort_values('Hungarian_rate').reset_index(drop=True) # 计算总人口与每组目标人口(440/5=88) total_pop = df_sorted['Population'].sum() target_per_group = total_pop / 5
步骤2:动态规划寻找最优分组
通过动态规划计算前i个城镇分成k组的最小误差,回溯得到分组边界:
# 计算人口前缀和,快速获取任意区间的人口总和 prefix_pop = df_sorted['Population'].cumsum().tolist() prefix_pop.insert(0, 0) # prefix_pop[0]=0,prefix_pop[i]代表前i个城镇的人口总和 n = len(df_sorted) k_groups = 5 # 初始化DP数组:dp[i][j] = 前i个城镇分成j组的最小平方误差和 INF = float('inf') dp = [[INF] * (k_groups + 1) for _ in range(n + 1)] dp[0][0] = 0 # 记录分割点,用于回溯分组 split_points = [[0] * (k_groups + 1) for _ in range(n + 1)] # 填充DP数组 for i in range(1, n + 1): for j in range(1, min(k_groups, i) + 1): # 遍历所有可能的前一组分割点 for m in range(j - 1, i): current_sum = prefix_pop[i] - prefix_pop[m] # 计算当前组与目标值的平方误差 error = (current_sum - target_per_group) ** 2 if dp[m][j - 1] + error < dp[i][j]: dp[i][j] = dp[m][j - 1] + error split_points[i][j] = m # 回溯获取分组索引 groups = [] current_idx = n for j in range(k_groups, 0, -1): prev_idx = split_points[current_idx][j] groups.append(list(range(prev_idx, current_idx))) current_idx = prev_idx groups.reverse()
步骤3:标记分组与验证结果
为数据添加分组标签,并验证每组人口总和:
# 为每个城镇分配带区间的分组标签 for idx, group in enumerate(groups, 1): min_rate = df_sorted.loc[group[0], 'Hungarian_rate'] max_rate = df_sorted.loc[group[-1], 'Hungarian_rate'] df_sorted.loc[group, 'Population_Group'] = f"Group {idx} ({min_rate}-{max_rate})" # 查看每组人口总和 group_pop_summary = df_sorted.groupby('Population_Group')['Population'].sum().reset_index() print(group_pop_summary)
最终分组结果
运行后得到的分组及人口总和如下(每组均接近目标值88):
| Population_Group | Population |
|---|---|
| Group 1 (1-5) | 80 |
| Group 2 (8-10) | 100 |
| Group 3 (15-20) | 90 |
| Group 4 (22-41) | 90 |
| Group 5 (60-75) | 80 |
各组人口总和方差极小,既满足人口均衡需求,又保持了Hungarian_rate区间的连续性。
内容的提问来源于stack exchange,提问作者Kristián Ővári
相关产品推荐
相关产品推荐

