697 lines
34 KiB
Python
697 lines
34 KiB
Python
import json
|
||
import os
|
||
from datetime import datetime
|
||
|
||
class YuCeUtil:
|
||
def __init__(self, data_dir, area_name='云南省'):
|
||
"""
|
||
初始化入园人数预测类,指定数据目录和区域名称
|
||
|
||
参数:
|
||
data_dir (str):数据文件所在的目录路径
|
||
area_name (str):要预测的区域名称,默认为'云南省'
|
||
|
||
数据成员说明:
|
||
- area_name:要预测的区域名称
|
||
- birth_data:出生人数数据
|
||
- enrollment_data:入园人数数据(包含城乡分布)
|
||
- urban_rates:城镇化率数据
|
||
- teacher_data:教师数据
|
||
- class_count_data:班级数数据
|
||
- years_with_valid_data:有有效数据的年份组合
|
||
- ratios:出生人数与3年后入园人数的比值列表
|
||
- fixed_ratio:固定比值(用于预测)
|
||
- forecast_results:预测结果字典
|
||
- enrollment_in_school:在园人数计算结果
|
||
- fixed_enrollment_in_school:基于5年平均的固定在园人数
|
||
- urban_enrollment_ratio:城区招生比例字典
|
||
- forecast_urban_rates:预测的城镇化率字典
|
||
- forecast_urban_enrollment:预测的城区招生数字典
|
||
- teacher_gap:教师缺口/富余计算结果
|
||
- degree_gap:学位缺口/富余计算结果
|
||
"""
|
||
self.data_dir = data_dir
|
||
self.area_name = area_name # 新增区域名称参数
|
||
self.birth_data = None # 出生人数数据
|
||
self.enrollment_data = None # 入园人数数据
|
||
self.urban_rates = None # 城镇化率数据
|
||
self.teacher_data = None # 教师数据
|
||
self.class_count_data = None # 班级数数据
|
||
self.years_with_valid_data = [] # 有有效数据的年份
|
||
self.ratios = [] # 出生人数与3年后入园人数的比值
|
||
self.fixed_ratio = 0 # 固定比值
|
||
self.forecast_results = {} # 预测结果
|
||
self.enrollment_in_school = {} # 在园人数计算结果
|
||
self.fixed_enrollment_in_school = 0 # 基于5年平均的固定在园人数
|
||
self.urban_enrollment_ratio = {} # 城区招生比例
|
||
self.forecast_urban_rates = {} # 预测的城镇化率
|
||
self.forecast_urban_enrollment = {} # 预测的城区招生数
|
||
self.teacher_gap = {} # 教师缺口/富余
|
||
self.degree_gap = {} # 学位缺口/富余
|
||
|
||
# 加载数据
|
||
self.load_data()
|
||
|
||
def load_data(self):
|
||
"""
|
||
加载出生人数、入园人数、城镇化率、教师数据和班级数数据
|
||
根据指定的区域名称筛选对应的数据
|
||
"""
|
||
try:
|
||
# 加载出生人数数据和城镇化率
|
||
birth_file = os.path.join(self.data_dir, 'RenKou.json')
|
||
with open(birth_file, 'r', encoding='utf-8') as f:
|
||
population_data = json.load(f)
|
||
|
||
# 查找指定区域的数据
|
||
area_found = False
|
||
for area in population_data:
|
||
if area.get('area_name') == self.area_name:
|
||
self.birth_data = area.get('birth_population', {})
|
||
self.urban_rates = area.get('urbanization_rate', {})
|
||
area_found = True
|
||
break
|
||
|
||
# 显示所有年份的出生人数数据情况
|
||
if area_found:
|
||
print(f"{self.area_name}出生人数数据概览:")
|
||
for year in sorted(self.birth_data.keys()):
|
||
birth_count = self.birth_data.get(year, 0)
|
||
status = "有效" if birth_count > 0 else "无效(0)"
|
||
print(f" {year}年: {birth_count} ({status})")
|
||
else:
|
||
print(f"未找到{self.area_name}的人口数据")
|
||
|
||
# 加载入园人数数据
|
||
enrollment_file = os.path.join(self.data_dir, 'ZhaoShengCount.json')
|
||
with open(enrollment_file, 'r', encoding='utf-8') as f:
|
||
enrollment_data_all = json.load(f)
|
||
|
||
# 查找指定区域的学前教育数据
|
||
area_found = False
|
||
for area in enrollment_data_all:
|
||
if area.get('area_name') == self.area_name:
|
||
preschool_data = area.get('education_data', {}).get('preschool', {})
|
||
# 提取城乡分布数据,并计算真实的total值
|
||
self.enrollment_data = {}
|
||
for year, data in preschool_data.items():
|
||
urban = data.get('urban', 0)
|
||
town = data.get('town', 0)
|
||
rural = data.get('rural', 0)
|
||
# 计算真实的total值,而不是使用文件中可能错误的total
|
||
real_total = urban + town + rural
|
||
self.enrollment_data[year] = {
|
||
'total': real_total,
|
||
'urban': urban,
|
||
'town': town,
|
||
'rural': rural
|
||
}
|
||
area_found = True
|
||
break
|
||
|
||
if not area_found:
|
||
print(f"未找到{self.area_name}的入园人数数据")
|
||
|
||
# 加载教师数据
|
||
teacher_file = os.path.join(self.data_dir, 'TeacherCount.json')
|
||
with open(teacher_file, 'r', encoding='utf-8') as f:
|
||
teacher_data_all = json.load(f)
|
||
|
||
# 查找指定区域的教师数据
|
||
area_found = False
|
||
for area in teacher_data_all:
|
||
if area.get('area_name') == self.area_name:
|
||
self.teacher_data = area.get('preschool_teachers', {})
|
||
# 处理2021-2023年staff数据为0的情况
|
||
for year in ['2021', '2022', '2023']:
|
||
if year in self.teacher_data:
|
||
# 使用前一年的数据进行估算
|
||
prev_year = str(int(year) - 1)
|
||
if prev_year in self.teacher_data:
|
||
self.teacher_data[year]['total_staff'] = self.teacher_data[prev_year].get('total_staff', 0)
|
||
self.teacher_data[year]['urban_staff'] = self.teacher_data[prev_year].get('urban_staff', 0)
|
||
self.teacher_data[year]['town_staff'] = self.teacher_data[prev_year].get('town_staff', 0)
|
||
self.teacher_data[year]['rural_staff'] = self.teacher_data[prev_year].get('rural_staff', 0)
|
||
area_found = True
|
||
break
|
||
|
||
if not area_found:
|
||
print(f"未找到{self.area_name}的教师数据")
|
||
|
||
# 加载班级数数据
|
||
try:
|
||
class_file = os.path.join(self.data_dir, 'ClassCount.json')
|
||
with open(class_file, 'r', encoding='utf-8') as f:
|
||
class_data_all = json.load(f)
|
||
|
||
# 查找指定区域的班级数数据
|
||
area_found = False
|
||
for area in class_data_all:
|
||
if area.get('area_name') == self.area_name:
|
||
# 注意:这里数据结构可能与之前不同
|
||
if 'preschool_classes' in area:
|
||
self.class_count_data = area.get('preschool_classes', {})
|
||
else:
|
||
self.class_count_data = area.get('education_data', {}).get('preschool', {})
|
||
|
||
# 计算班级数的total值
|
||
for year, data in self.class_count_data.items():
|
||
if isinstance(data, dict) and 'urban' in data and 'town' in data and 'rural' in data:
|
||
# 计算真实的total值
|
||
urban = data.get('urban', 0)
|
||
town = data.get('town', 0)
|
||
rural = data.get('rural', 0)
|
||
data['total'] = urban + town + rural
|
||
area_found = True
|
||
break
|
||
|
||
if not area_found:
|
||
print(f"未找到{self.area_name}的班级数数据")
|
||
except Exception as e:
|
||
print(f"加载班级数数据出错: {e}")
|
||
self.class_count_data = {}
|
||
|
||
except Exception as e:
|
||
print(f"加载数据出错: {e}")
|
||
self.birth_data = {}
|
||
self.enrollment_data = {}
|
||
self.urban_rates = {}
|
||
self.teacher_data = {}
|
||
self.class_count_data = {}
|
||
|
||
def calculate_ratios(self):
|
||
"""
|
||
计算出生人数与3年后入园人数的比值
|
||
"""
|
||
if not self.birth_data or not self.enrollment_data:
|
||
print(f"{self.area_name}数据加载不完整,无法计算比值")
|
||
return
|
||
|
||
print(f"\n计算{self.area_name}出生人数与3年后入园人数的比值:")
|
||
# 找出所有可能的年份组合
|
||
for year_str in sorted(self.birth_data.keys()):
|
||
birth_count = self.birth_data.get(year_str, 0)
|
||
# 检查3年后的入园数据是否存在
|
||
three_years_later = str(int(year_str) + 3)
|
||
|
||
if three_years_later in self.enrollment_data:
|
||
# 使用计算出的真实total值
|
||
enrollment_count = self.enrollment_data.get(three_years_later, {}).get('total', 0)
|
||
|
||
if birth_count > 0 and enrollment_count > 0:
|
||
# 两者都有有效数据,计算比值
|
||
ratio = birth_count / enrollment_count
|
||
self.ratios.append(ratio)
|
||
self.years_with_valid_data.append((year_str, three_years_later))
|
||
print(f" {year_str}年出生人数: {birth_count}, {three_years_later}年入园人数: {enrollment_count}, 比值: {ratio:.4f}")
|
||
else:
|
||
# 至少有一个数据无效
|
||
status = []
|
||
if birth_count <= 0:
|
||
status.append(f"{year_str}年出生人数无效")
|
||
if enrollment_count <= 0:
|
||
status.append(f"{three_years_later}年入园人数无效")
|
||
print(f" {year_str}年→{three_years_later}年: {', '.join(status)}")
|
||
else:
|
||
print(f" {year_str}年→{three_years_later}年: 没有找到{three_years_later}年的入园数据")
|
||
|
||
def calculate_fixed_ratio(self):
|
||
"""
|
||
计算固定比值(使用所有可用数据的平均值)
|
||
"""
|
||
if not self.ratios:
|
||
print(f"\n{self.area_name}没有可用的比值数据")
|
||
return
|
||
|
||
# 取所有可用的比值数据计算平均值
|
||
self.fixed_ratio = sum(self.ratios) / len(self.ratios)
|
||
print(f"\n{self.area_name}固定比值({len(self.ratios)}年平均值): {self.fixed_ratio:.4f}")
|
||
|
||
def forecast_enrollment(self):
|
||
"""
|
||
预测未来年份的入园人数
|
||
"""
|
||
if not self.fixed_ratio or self.fixed_ratio <= 0:
|
||
print(f"\n{self.area_name}固定比值无效,无法预测")
|
||
return
|
||
|
||
# 预测未来年份的入园人数
|
||
print(f"\n预测{self.area_name}未来年份入园人数:")
|
||
# 先确定有出生数据的最晚期份
|
||
latest_birth_year = max(int(year) for year in self.birth_data.keys() if self.birth_data[year] > 0)
|
||
max_forecast_year = latest_birth_year + 3
|
||
|
||
# 至少预测到2029年
|
||
for forecast_year in range(2025, 2030):
|
||
# 计算对应的出生年份(预测年份-3)
|
||
birth_year = str(forecast_year - 3)
|
||
|
||
if birth_year in self.birth_data:
|
||
birth_count = self.birth_data.get(birth_year, 0)
|
||
if birth_count > 0:
|
||
# 计算预测的入园人数:出生人数 ÷ 固定比值
|
||
forecasted_enrollment = int(birth_count / self.fixed_ratio)
|
||
self.forecast_results[forecast_year] = forecasted_enrollment
|
||
print(f" {forecast_year}年预测入园人数: {forecasted_enrollment}(基于{birth_year}年出生人数: {birth_count})")
|
||
else:
|
||
print(f" {birth_year}年没有有效出生数据,无法预测{forecast_year}年入园人数")
|
||
else:
|
||
print(f" {birth_year}年没有出生数据,无法预测{forecast_year}年入园人数")
|
||
|
||
def calculate_enrollment_in_school(self):
|
||
"""
|
||
计算在园人数(学前学制3年,在园人数≈前3年入园人数之和)
|
||
"""
|
||
if not self.enrollment_data and not self.forecast_results:
|
||
print(f"\n{self.area_name}没有可用的入园人数数据,无法计算在园人数")
|
||
return
|
||
|
||
print(f"\n计算{self.area_name}在园人数:")
|
||
|
||
# 合并实际入园数据和预测入园数据
|
||
all_enrollment_data = {}
|
||
for year, data in self.enrollment_data.items():
|
||
# 使用计算出的真实total值
|
||
all_enrollment_data[year] = data.get('total', 0)
|
||
for year, count in self.forecast_results.items():
|
||
all_enrollment_data[str(year)] = count
|
||
|
||
# 获取所有可用的年份
|
||
all_years = sorted([int(year) for year in all_enrollment_data.keys()])
|
||
|
||
# 计算每个年份的在园人数(使用前3年入园人数之和)
|
||
for current_year in all_years:
|
||
# 找到前3年
|
||
previous_years = [current_year - 1, current_year - 2, current_year - 3]
|
||
|
||
# 检查这些年份是否有数据且数据有效(大于0)
|
||
valid_years = []
|
||
valid_enrollments = []
|
||
for year in previous_years:
|
||
year_str = str(year)
|
||
if year_str in all_enrollment_data:
|
||
enrollment = all_enrollment_data.get(year_str, 0)
|
||
if enrollment > 0:
|
||
valid_years.append(year)
|
||
valid_enrollments.append(enrollment)
|
||
|
||
if len(valid_years) >= 1:
|
||
# 计算前3年(如有)入园人数之和
|
||
total_enrollment = sum(valid_enrollments)
|
||
self.enrollment_in_school[current_year] = total_enrollment
|
||
|
||
# 显示计算详情
|
||
if len(valid_years) == 3:
|
||
print(f" {current_year}年在园人数: {total_enrollment}(前3年入园人数之和)")
|
||
else:
|
||
available_years_str = ", ".join([str(year) for year in valid_years])
|
||
print(f" {current_year}年在园人数: {total_enrollment}(使用{len(valid_years)}年数据: {available_years_str})")
|
||
else:
|
||
print(f" {current_year}年: 没有足够的有效历史数据计算在园人数")
|
||
|
||
# 计算基于5年入园数平均值的固定在园人数(用于某些预测场景)
|
||
self.calculate_fixed_enrollment_in_school()
|
||
|
||
def calculate_fixed_enrollment_in_school(self):
|
||
"""
|
||
计算基于5年入园数平均值的固定在园人数
|
||
"""
|
||
# 只使用实际的入园数据(不包含预测数据)
|
||
actual_enrollment_data = {year: data.get('total', 0) for year, data in self.enrollment_data.items()}
|
||
|
||
# 获取所有有效实际入园数据的年份
|
||
valid_years = sorted([int(year) for year in actual_enrollment_data.keys() if actual_enrollment_data.get(year, 0) > 0], reverse=True)
|
||
|
||
if len(valid_years) >= 5:
|
||
# 使用最近5年的实际数据
|
||
five_years = valid_years[:5]
|
||
five_year_avg = sum(actual_enrollment_data.get(str(year), 0) for year in five_years) / 5
|
||
self.fixed_enrollment_in_school = int(five_year_avg)
|
||
print(f"\n{self.area_name}基于最近5年入园数平均值的固定在园人数: {self.fixed_enrollment_in_school}(使用{', '.join([str(year) for year in five_years])}年数据)")
|
||
elif len(valid_years) > 0:
|
||
# 数据不足5年,使用所有可用的实际数据
|
||
all_year_avg = sum(actual_enrollment_data.get(str(year), 0) for year in valid_years) / len(valid_years)
|
||
self.fixed_enrollment_in_school = int(all_year_avg)
|
||
print(f"\n{self.area_name}基于所有可用入园数平均值的固定在园人数: {self.fixed_enrollment_in_school}(使用{', '.join([str(year) for year in valid_years])}年数据)")
|
||
else:
|
||
print(f"\n{self.area_name}没有足够的有效入园数据计算固定在园人数")
|
||
|
||
def forecast_urbanization_rate(self):
|
||
"""
|
||
预测未来年份的城镇化率(每年按约1%增长,若数值≥100%则不再增加)
|
||
"""
|
||
if not self.urban_rates:
|
||
print(f"\n{self.area_name}没有可用的城镇化率数据,无法预测")
|
||
return
|
||
|
||
print(f"\n预测未来年份城镇化率:")
|
||
|
||
# 找出最近有城镇化率数据的年份
|
||
valid_urban_years = [int(year) for year in self.urban_rates.keys() if self.urban_rates[year] > 0]
|
||
if not valid_urban_years:
|
||
print(" 没有有效城镇化率数据")
|
||
return
|
||
|
||
latest_urban_year = max(valid_urban_years)
|
||
latest_urban_rate = self.urban_rates.get(str(latest_urban_year), 0)
|
||
|
||
# 预测2025-2029年的城镇化率
|
||
for year in range(2025, 2030):
|
||
if year > latest_urban_year:
|
||
# 每年增长约1%
|
||
next_rate = latest_urban_rate + (year - latest_urban_year) * 1.0
|
||
# 如果超过100%,则不再增加
|
||
next_rate = min(next_rate, 100.0)
|
||
self.forecast_urban_rates[year] = next_rate
|
||
print(f" {year}年预测城镇化率: {next_rate:.2f}%")
|
||
else:
|
||
# 使用已有数据
|
||
existing_rate = self.urban_rates.get(str(year), 0)
|
||
self.forecast_urban_rates[year] = existing_rate
|
||
print(f" {year}年城镇率: {existing_rate:.2f}%")
|
||
|
||
def calculate_urban_enrollment_ratio(self):
|
||
"""
|
||
计算城区招生比例并预测未来年份的城区招生情况
|
||
"""
|
||
if not self.enrollment_data:
|
||
print(f"\n{self.area_name}没有可用的入园人数数据,无法计算城区招生比例")
|
||
return
|
||
|
||
print(f"\n计算城区招生比例:")
|
||
|
||
# 计算历史城区招生比例
|
||
for year_str in sorted(self.enrollment_data.keys()):
|
||
# 使用计算出的真实total值
|
||
total_enrollment = self.enrollment_data.get(year_str, {}).get('total', 0)
|
||
urban_enrollment = self.enrollment_data.get(year_str, {}).get('urban', 0)
|
||
|
||
if total_enrollment > 0:
|
||
urban_ratio = urban_enrollment / total_enrollment
|
||
self.urban_enrollment_ratio[int(year_str)] = urban_ratio
|
||
print(f" {year_str}年城区招生比例: {urban_ratio:.4f}")
|
||
|
||
# 预测未来年份的城区招生比例
|
||
if self.forecast_results and self.forecast_urban_rates:
|
||
# 获取最近有城区招生比例数据的年份
|
||
valid_years = sorted(self.urban_enrollment_ratio.keys())
|
||
if valid_years:
|
||
latest_year = valid_years[-1]
|
||
latest_ratio = self.urban_enrollment_ratio.get(latest_year, 0)
|
||
|
||
# 计算城镇化率年增长
|
||
urban_growth_rate = 1.0 / 2 # 根据需求,城和镇各分0.5%
|
||
|
||
# 预测2025-2029年的城区招生比例
|
||
for forecast_year in range(2025, 2030):
|
||
if forecast_year in self.forecast_results:
|
||
# 计算城区招生数:(前一年城区招生占总招生比例 + 城镇化率年增长÷2)×当年预测总招生数
|
||
previous_year = forecast_year - 1
|
||
previous_ratio = self.urban_enrollment_ratio.get(previous_year, latest_ratio)
|
||
|
||
# 应用城镇化增长调整
|
||
adjusted_ratio = previous_ratio + urban_growth_rate / 100 # 转换为小数
|
||
adjusted_ratio = min(adjusted_ratio, 1.0) # 不超过100%
|
||
|
||
# 保存预测的城区招生比例
|
||
self.urban_enrollment_ratio[forecast_year] = adjusted_ratio
|
||
|
||
# 计算城区招生数
|
||
total_enrollment = self.forecast_results[forecast_year]
|
||
urban_enrollment = int(total_enrollment * adjusted_ratio)
|
||
|
||
# 计算乡镇和农村招生数(假设镇和农村按历史比例分配剩余部分)
|
||
remaining_enrollment = total_enrollment - urban_enrollment
|
||
|
||
# 保存预测的城区招生数
|
||
self.forecast_urban_enrollment[forecast_year] = {
|
||
'total': total_enrollment,
|
||
'urban': urban_enrollment,
|
||
'remaining': remaining_enrollment
|
||
}
|
||
|
||
print(f" {forecast_year}年预测城区招生比例: {adjusted_ratio:.4f},城区招生数: {urban_enrollment}")
|
||
|
||
def calculate_teacher_gap(self):
|
||
"""
|
||
计算教师缺口/富余(学前教职工师生比1:7)
|
||
"""
|
||
if not self.teacher_data or not self.enrollment_in_school:
|
||
print(f"\n{self.area_name}没有足够数据计算教师缺口")
|
||
return
|
||
|
||
print(f"\n计算教师缺口/富余:")
|
||
|
||
# 学前教职工师生比标准
|
||
staff_student_ratio = 7 # 1:7
|
||
|
||
# 计算历史年份教师缺口
|
||
for year_str, data in self.teacher_data.items():
|
||
year = int(year_str)
|
||
if year in self.enrollment_in_school:
|
||
total_staff = data.get('total_staff', 0)
|
||
enrollment_in_school = self.enrollment_in_school[year]
|
||
|
||
if enrollment_in_school > 0:
|
||
# 计算所需教师数
|
||
required_staff = enrollment_in_school / staff_student_ratio
|
||
# 计算缺口/富余(现有教师数-预测教师需求数)
|
||
gap = total_staff - required_staff
|
||
self.teacher_gap[year] = gap
|
||
|
||
status = "富余" if gap >= 0 else "缺口"
|
||
print(f" {year}年在园人数: {enrollment_in_school}, 现有教职工: {total_staff}, 所需教职工: {required_staff:.0f}, {status}: {abs(gap):.0f}人")
|
||
|
||
# 预测未来年份教师缺口
|
||
for year in range(2025, 2030):
|
||
if year in self.enrollment_in_school:
|
||
enrollment_in_school = self.enrollment_in_school[year]
|
||
|
||
if enrollment_in_school > 0:
|
||
# 计算所需教师数
|
||
required_staff = enrollment_in_school / staff_student_ratio
|
||
|
||
# 假设教师数量按与在园人数相同比例增长(简化处理)
|
||
# 找最近的教师数据
|
||
recent_years = [y for y in self.teacher_data.keys() if int(y) < year]
|
||
if recent_years:
|
||
latest_year = max(recent_years)
|
||
latest_staff = self.teacher_data.get(latest_year, {}).get('total_staff', 0)
|
||
latest_enrollment = self.enrollment_in_school.get(int(latest_year), 0)
|
||
|
||
if latest_enrollment > 0:
|
||
# 按比例增长
|
||
projected_staff = latest_staff * (enrollment_in_school / latest_enrollment)
|
||
else:
|
||
projected_staff = required_staff # 保守估计
|
||
else:
|
||
projected_staff = required_staff # 保守估计
|
||
|
||
# 计算缺口/富余
|
||
gap = projected_staff - required_staff
|
||
self.teacher_gap[year] = gap
|
||
|
||
status = "富余" if gap >= 0 else "缺口"
|
||
print(f" {year}年预测在园人数: {enrollment_in_school}, 预计教职工: {projected_staff:.0f}, 所需教职工: {required_staff:.0f}, {status}: {abs(gap):.0f}人")
|
||
|
||
def calculate_degree_gap(self):
|
||
"""
|
||
计算学位缺口/富余(学前班额标准为30人/班)
|
||
"""
|
||
if not self.class_count_data or not self.enrollment_data:
|
||
print(f"\n{self.area_name}没有足够数据计算学位缺口")
|
||
return
|
||
|
||
print(f"\n计算学位缺口/富余:")
|
||
|
||
# 学前班额标准
|
||
class_size_standard = 30 # 每班30人
|
||
|
||
# 计算历史年份学位缺口
|
||
for year_str, class_data in self.class_count_data.items():
|
||
if isinstance(class_data, dict): # 确保class_data是字典类型
|
||
year = int(year_str)
|
||
if year_str in self.enrollment_data:
|
||
# 现有学位数=(当年总班级数÷3)×对应班额标准(学前分3个年级)
|
||
total_classes = class_data.get('total', 0)
|
||
# 使用计算出的真实total值
|
||
enrollment_count = self.enrollment_data.get(year_str, {}).get('total', 0)
|
||
|
||
if total_classes > 0:
|
||
# 计算现有学位数
|
||
available_degrees = (total_classes / 3) * class_size_standard
|
||
# 计算缺口/富余(现有学位数-预测入园数)
|
||
gap = available_degrees - enrollment_count
|
||
self.degree_gap[year] = gap
|
||
|
||
status = "富余" if gap >= 0 else "缺口"
|
||
print(f" {year}年班级数: {total_classes}, 入园人数: {enrollment_count}, 可用学位: {available_degrees:.0f}, {status}: {abs(gap):.0f}个")
|
||
|
||
# 预测未来年份学位缺口
|
||
for year in range(2025, 2030):
|
||
if year in self.forecast_results:
|
||
enrollment_count = self.forecast_results[year]
|
||
|
||
# 假设班级数量按与入园人数相同比例增长(简化处理)
|
||
# 找最近的班级数据
|
||
recent_years = [y for y in self.class_count_data.keys() if int(y) < year]
|
||
if recent_years:
|
||
latest_year = max(recent_years)
|
||
latest_classes_data = self.class_count_data.get(latest_year, {})
|
||
# 确保latest_classes_data是字典类型
|
||
if isinstance(latest_classes_data, dict):
|
||
latest_classes = latest_classes_data.get('total', 0)
|
||
latest_enrollment = self.enrollment_data.get(latest_year, {}).get('total', 0)
|
||
|
||
if latest_enrollment > 0:
|
||
# 按比例增长
|
||
projected_classes = latest_classes * (enrollment_count / latest_enrollment)
|
||
else:
|
||
# 按标准班级数计算
|
||
projected_classes = enrollment_count / class_size_standard * 3 # 考虑3个年级
|
||
else:
|
||
projected_classes = 0
|
||
else:
|
||
# 按标准班级数计算
|
||
projected_classes = enrollment_count / class_size_standard * 3 # 考虑3个年级
|
||
|
||
# 计算可用学位
|
||
available_degrees = (projected_classes / 3) * class_size_standard
|
||
|
||
# 计算缺口/富余
|
||
gap = available_degrees - enrollment_count
|
||
self.degree_gap[year] = gap
|
||
|
||
status = "富余" if gap >= 0 else "缺口"
|
||
print(f" {year}年预测班级数: {projected_classes:.0f}, 入园人数: {enrollment_count}, 可用学位: {available_degrees:.0f}, {status}: {abs(gap):.0f}个")
|
||
|
||
def run_forecast(self):
|
||
"""
|
||
运行完整的预测流程,依次执行各个计算步骤并输出结果摘要
|
||
"""
|
||
print(f"===== {self.area_name}入园人数预测系统 ======")
|
||
|
||
# 检查数据完整性
|
||
print("\n1. 数据完整性检查:")
|
||
if not self.birth_data or not self.enrollment_data:
|
||
print(" 数据加载不完整,无法进行预测")
|
||
return
|
||
|
||
# 计算比值
|
||
print("\n2. 计算出生人数与3年后入园人数的比值:")
|
||
self.calculate_ratios()
|
||
|
||
# 计算固定比值
|
||
print("\n3. 计算固定比值:")
|
||
self.calculate_fixed_ratio()
|
||
|
||
# 预测未来入园人数
|
||
print("\n4. 预测未来年份入园人数:")
|
||
self.forecast_enrollment()
|
||
|
||
# 计算在园人数
|
||
print("\n5. 计算在园人数:")
|
||
self.calculate_enrollment_in_school()
|
||
|
||
# 预测城镇化率
|
||
print("\n6. 预测城镇化率:")
|
||
self.forecast_urbanization_rate()
|
||
|
||
# 计算城区招生比例
|
||
print("\n7. 计算城区招生比例:")
|
||
self.calculate_urban_enrollment_ratio()
|
||
|
||
# 计算教师缺口/富余
|
||
print("\n8. 计算教师缺口/富余:")
|
||
self.calculate_teacher_gap()
|
||
|
||
# 计算学位缺口/富余
|
||
print("\n9. 计算学位缺口/富余:")
|
||
self.calculate_degree_gap()
|
||
|
||
# 输出最终预测结果摘要
|
||
print(f"\n===== {self.area_name}预测结果摘要 =====")
|
||
|
||
# 1. 预测入园人数摘要
|
||
if self.forecast_results:
|
||
print("\n预测入园人数:")
|
||
for year, count in sorted(self.forecast_results.items()):
|
||
print(f"{year}年: {count}人")
|
||
else:
|
||
print("\n预测入园人数:")
|
||
print("没有生成任何预测结果")
|
||
|
||
# 2. 在园人数摘要
|
||
if self.enrollment_in_school:
|
||
print("\n在园人数(基于前3年入园人数之和):")
|
||
for year, count in sorted(self.enrollment_in_school.items()):
|
||
print(f"{year}年: {count}人")
|
||
else:
|
||
print("\n在园人数:")
|
||
print("没有计算任何在园人数数据")
|
||
|
||
# 3. 固定在园人数摘要
|
||
if self.fixed_enrollment_in_school > 0:
|
||
print(f"\n固定在园人数(基于平均值):{self.fixed_enrollment_in_school}人")
|
||
|
||
# 4. 预测城镇化率摘要
|
||
if self.forecast_urban_rates:
|
||
print("\n预测城镇化率:")
|
||
for year, rate in sorted(self.forecast_urban_rates.items()):
|
||
if year >= 2025: # 只显示预测数据
|
||
print(f"{year}年: {rate:.2f}%")
|
||
|
||
# 5. 预测城区招生比例和数量摘要
|
||
if self.forecast_urban_enrollment:
|
||
print("\n预测城区招生情况:")
|
||
for year, data in sorted(self.forecast_urban_enrollment.items()):
|
||
ratio = self.urban_enrollment_ratio.get(year, 0)
|
||
print(f"{year}年: 比例{ratio:.2%}, 城区{data.get('urban', 0)}人, 总{data.get('total', 0)}人")
|
||
|
||
# 6. 教师缺口/富余摘要
|
||
if self.teacher_gap:
|
||
print("\n教师缺口/富余(仅显示2022年后数据):")
|
||
for year, gap in sorted(self.teacher_gap.items()):
|
||
if year >= 2022:
|
||
status = "富余" if gap >= 0 else "缺口"
|
||
print(f"{year}年: {status}{abs(gap):.0f}人")
|
||
|
||
# 7. 学位缺口/富余摘要
|
||
if self.degree_gap:
|
||
print("\n学位缺口/富余(仅显示2022年后数据):")
|
||
for year, gap in sorted(self.degree_gap.items()):
|
||
if year >= 2022:
|
||
status = "富余" if gap >= 0 else "缺口"
|
||
print(f"{year}年: {status}{abs(gap):.0f}个")
|
||
|
||
if __name__ == "__main__":
|
||
# 设置数据目录路径
|
||
data_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../Data')
|
||
|
||
# 支持选择不同区域进行预测
|
||
# 默认预测云南省,也可以修改为其他区域如"昆明市"、"五华区"等
|
||
print("===== 学前教育数据预测系统 ====")
|
||
print("请选择要预测的区域(默认:云南省):")
|
||
print("1. 云南省")
|
||
print("2. 昆明市")
|
||
print("3. 其他区域")
|
||
|
||
choice = input("请输入选项(1-3): ")
|
||
|
||
if choice == '1':
|
||
area = '云南省'
|
||
elif choice == '2':
|
||
area = '昆明市'
|
||
elif choice == '3':
|
||
area = input("请输入区域名称: ")
|
||
else:
|
||
print("输入无效,默认使用云南省")
|
||
area = '云南省'
|
||
|
||
print(f"\n正在预测{area}的学前教育数据...")
|
||
|
||
# 创建预测实例并运行预测
|
||
forecast = YuCeUtil(data_directory, area)
|
||
forecast.run_forecast()
|
||
|