2025统计建模

摘要: Intro 统计建模大赛实际上是无心插柳柳成荫,本来我们打算以统计建模为练手项目,为后面三次数学建模校赛打基础,但由于种种原因(拖延症),在第一次校赛结束后我们才开始了建模工作。 与数学建模不同的是,统计建模不提供题目,要求自行选题,自行寻找数据,自行建模。看似给了很大的发挥空间,实际却恰恰相反,我们如同无头苍蝇,单单针对如何选题就讨论了四五天,且没有任何进展。 最开始的选题是城市文化与旅游方面, …

Intro

统计建模大赛实际上是无心插柳柳成荫,本来我们打算以统计建模为练手项目,为后面三次数学建模校赛打基础,但由于种种原因(拖延症),在第一次校赛结束后我们才开始了建模工作。

与数学建模不同的是,统计建模不提供题目,要求自行选题,自行寻找数据,自行建模。看似给了很大的发挥空间,实际却恰恰相反,我们如同无头苍蝇,单单针对如何选题就讨论了四五天,且没有任何进展。

最开始的选题是城市文化与旅游方面,但考虑到我们并不具备大规模爬虫爬取数据的能力,最终放弃了这个选题;最后临近截止日期时,我们决定用主办方提供的数据库中的现成数据来思考题目,结合相关政策与新闻热点,最终敲定了“绿色发展与城镇化相协调”这类型的选题。

最终定题为“城镇化与绿色发展的动态耦合:基于双指数体系的“宜居家园”建设评估”,摘要如下:

2025年《政府工作报告》中指出,要加快发展绿色低碳经济,积极推进美丽中国先行区建设。国务院印发的《新时代的中国绿色发展》白皮书,全面总结了党的十八大以来我国推进绿色发展的理念、实践和成效,强调要“建设生态宜居美丽家园”。建设生态宜居美丽城市,关系着人民的生活幸福指数,体现以人民为中心的发展理念。为响应此战略要求,全面、准确地评估“美丽家园”的建设进程,并对未来进一步发展进行预测,可以为政策制定、资金配置等提供切实的科学依据,为全面推进美丽城市建设提供行动指引,助力美丽中国建设。

在过去的研究中,评估城市建设水平往往以传统的经济和城镇化水平等指标为主,不能有效协调生态、社会服务、城镇化等指数的动态联系。在生态宜居美丽家园建设思想的指导下,本研究构建了城市化指数(UI)绿色指数(GI)的双指数评价体系,旨在量化评估全国各省级行政区“生态宜居美丽家园”建设进程。其中,城市化程度反映基础设施与公共服务水平,而绿色指数反映了生态环境质量与资源利用效率。本文采用熵权法对基础设施、空间扩展等客观指标赋权,构建城市化指数(UI);确定污染治理、生态建设等主观指标的权重,形成绿色指数(GI)。运用K-means聚类揭示区域发展差异:东部省份平均协调度(0.72)显著高于中西部(0.41),其中浙江省以0.85位列全国首位。据此提出“动态财政补偿机制”与“省级绿色基建负面清单”政策建议,为统筹城镇化与生态保护提供科学依据。

这样一套“赶工”出的作品最终居然获得了校级二等奖和省(直辖市)级三等奖,着实令人以外,所以在比赛结束后我认为有必要对其进行复盘与分析,总结一些经验。

理论分析

创新点

本文采用改进的熵权法,引入PCA主成分分析、Logistic处理、趋势因子,更加全面动态地构建评价指标。通过K-means聚类揭示各个指标间的关系。

研究方法如图image-20250621164433411

指标选取

为了使最终指数能够尽可能覆盖城市化发展的各个方面,选取如下指标:

城镇化指数(UI)指标选取

维度 指标名称(单位) 选择理由
人口集聚 人口密度(人/ km²) 直接反映城市人口承载强度和集聚效应
基础设施 供水管道密度(城建区km/km²) 衡量市政管网覆盖能力
人均道路面积(m²/人) 表征交通基础设施完善度
土地利用 城市建设用地面积(km²) 反映城市空间扩展程度
经济投入 固定资产投资额(亿元) 体现城市建设资本投入强度
公共设施 道路照明灯数(盏) 表征城市公共照明服务能力

表2 绿色指数(GI)指标选取

维度 指标名称(单位) 选择理由
绿化空间 绿化覆盖率(%) 衡量绿化总量
人均公园绿地面积 反映服务可及性
污染治理 污水处理率(%) 住建部"城市黑臭水体治理攻坚战"核心指标
生活垃圾无害化处理率(%)
资源循环 污水再生率(%) 直接体现水资源可持续利用水平
清洁能源 燃气普及率(%) 表征清洁能源替代传统燃煤进程

代码

下面代码展示了论文的核心算法,详细功能在注释中已经给出

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
from sklearn.impute import SimpleImputer
from prophet import Prophet
import matplotlib.pyplot as plt
import os
import logging
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置字体
plt.rcParams["axes.unicode_minus"] = False  # 正常显示负号

# ================== 配置参数 ==================
DATA_DIR = './province_data/'    # 原始数据存放目录
OUTPUT_DIR = './results_pca/'    # 结果输出目录
PROVINCES = [
    '河北', '山西', '辽宁', '吉林', '黑龙江', '江苏',
    '浙江', '安徽', '福建', '江西', '山东', '河南',
    '湖北', '湖南', '广东', '海南', '四川', '贵州',
    '云南', '陕西', '甘肃', '青海', 
    '内蒙古', '广西', '西藏', '宁夏',
    '新疆'
]

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# ================== 核心函数增强版 ==================
def robust_load_data(province):
    """修正版数据加载与预处理"""
    try:
        file_path = os.path.join(DATA_DIR, f"{province}.csv")
        
        # 加载数据并确保时间排序
        df = pd.read_csv(file_path, parse_dates=['时间'], encoding='utf-8')
        df = df.sort_values('时间')  # 确保时间有序
        
        # 列名标准化处理
        df.columns = [col.split(':')[0].strip().replace(' ', '') for col in df.columns]
        
        # 定义核心指标列
        required_cols = [
            '时间', '人口密度', '供水管道密度', '人均道路面积',
            '城市建设用地面积', '固定资产投资额', '污水处理率',
            '无害化处理率', '人均公园绿地面积', '绿化覆盖率', '污水再生率'
        ]
        existing_cols = [col for col in required_cols if col in df.columns]
        df = df[existing_cols]
        
        # 时间序列线性插值
        numeric_cols = [col for col in existing_cols if col != '时间']
        df[numeric_cols] = df[numeric_cols].interpolate(method='linear', limit_direction='both')
        
        # 处理剩余缺失值
        if df[numeric_cols].isna().sum().sum() > 0:
            imputer = SimpleImputer(strategy='mean')
            df[numeric_cols] = imputer.fit_transform(df[numeric_cols])
            logging.warning(f"{province} 使用均值填充剩余缺失值")
            
        return df
    except Exception as e:
        logging.error(f"加载 {province} 失败: {str(e)}")
        return None

def enhanced_entropy_weights(data, indicators):
    """增强型熵权法计算"""
    try:
        # 标准化处理
        normalized = (data[indicators] - data[indicators].min() + 1e-8) / \
                    (data[indicators].max() - data[indicators].min() + 1e-8)
        
        # 计算熵值
        p = normalized / (normalized.sum(axis=0) + 1e-8)
        entropy = (-1 / np.log(len(data))) * (p * np.log(p + 1e-8)).sum(axis=0)
        
        # 计算权重
        weights = (1 - entropy) / (1 - entropy).sum()
        return weights
    except Exception as e:
        logging.error(f"权重计算失败: {str(e)}")
        raise

def process_province(province):
    """增强版处理流程"""
    try:
        # 1. 加载数据
        df = robust_load_data(province)
        if df is None:
            return None
            
        # 2. PCA处理
        pca_cols = ['人口密度', '城市建设用地面积']
        if all(col in df.columns for col in pca_cols):
            pca = PCA(n_components=1)
            df['人口密度_PCA'] = pca.fit_transform(df[pca_cols])
        else:
            logging.warning(f"{province} 缺少PCA所需列")
            df['人口密度_PCA'] = df.get('人口密度', 0)  # 降级处理
            
        # 3. 定义指标体系
        ui_indicators = ['人口密度_PCA', '供水管道密度', '人均道路面积', '固定资产投资额']
        gci_indicators = ['污水处理率', '无害化处理率', '人均公园绿地面积', '绿化覆盖率']
        
        # 4. 计算权重
        ui_weights = enhanced_entropy_weights(df, ui_indicators)
        gci_weights = enhanced_entropy_weights(df, gci_indicators)
        
        # 5. 计算指数
        def safe_normalize(data, cols):
            return (data[cols] - data[cols].min()) / (data[cols].max() - data[cols].min() + 1e-8)
            
        df['UI'] = (safe_normalize(df, ui_indicators) * ui_weights).sum(axis=1)
        df['GCI'] = (safe_normalize(df, gci_indicators) * gci_weights).sum(axis=1)
        
        # 6. 保存结果
        os.makedirs(os.path.join(OUTPUT_DIR, "results"), exist_ok=True)
        output_path = os.path.join(OUTPUT_DIR, "results", f"{province}_结果.csv")
        df.to_csv(output_path, index=False, encoding='utf-8')
        logging.info(f"{province} 处理成功")
        plt.figure(figsize=(10,6))
        plt.plot(df['时间'], df['UI'], label='UI指数')
        plt.plot(df['时间'], df['GCI'], label='GCI指数')
        plt.title(f'{province}双指数发展趋势')
        plt.legend()
        plt.savefig(os.path.join(OUTPUT_DIR, f'{province}_趋势图.png'))
        return df
        
    except Exception as e:
        logging.error(f"处理 {province} 失败: {str(e)}")
        return None

def enhanced_cluster_analysis():
    """增强版聚类分析"""
    try:
        # 收集数据
        all_data = []
        for p in PROVINCES:
            result_file = os.path.join(OUTPUT_DIR, "results", f"{p}_结果.csv")
            if os.path.exists(result_file):
                df = pd.read_csv(result_file, parse_dates=['时间'])
                latest = df[df['时间'] == df['时间'].max()]
                latest['省份'] = p
                all_data.append(latest)
                
        if not all_data:
            raise ValueError("无有效数据可供分析")
            
        combined = pd.concat(all_data)
        
        # 检查数据质量
        if combined[['UI', 'GCI']].isna().sum().sum() > 0:
            combined = combined.fillna(combined.mean())
            
        # K-Means聚类
        kmeans = KMeans(n_clusters=4, random_state=42)
        combined['类别'] = kmeans.fit_predict(combined[['UI', 'GCI']])
        
        # 可视化
        plt.figure(figsize=(12, 8))
        scatter = plt.scatter(combined['UI'], combined['GCI'], 
                            c=combined['类别'], cmap='tab10', s=100)
        plt.xlabel('城市化指数(UI)', fontsize=14)
        plt.ylabel('绿色城市指数(GCI)', fontsize=14)
        plt.title('各省份发展模式聚类分析', fontsize=16)
        plt.colorbar(scatter).set_label('类别', fontsize=12)
        
        # 标注省份名称
        for i, row in combined.iterrows():
            plt.text(row['UI']+0.01, row['GCI']+0.01, row['省份'], 
                    fontsize=8, alpha=0.7)
                    
        os.makedirs(os.path.join(OUTPUT_DIR, "plots"), exist_ok=True)
        plt.savefig(os.path.join(OUTPUT_DIR, 'plots', '全国聚类分析.png'), dpi=300, bbox_inches='tight')
        plt.close()
        
        # 保存结果
        combined.to_csv(os.path.join(OUTPUT_DIR, 'results', '全国分类结果.csv'), 
                       index=False, encoding='utf-8')
        logging.info("聚类分析完成")
        
    except Exception as e:
        logging.error(f"聚类分析失败: {str(e)}")

# ================== 主程序 ==================
if __name__ == "__main__":
    # 初始化目录
    os.makedirs(OUTPUT_DIR, exist_ok=True)
    
    # 处理所有省份
    for province in PROVINCES:
        process_province(province)
    
    # 执行聚类分析
    enhanced_cluster_analysis()
    
    logging.info("===== 全部处理完成 =====")
    print(f"结果文件路径: {os.path.abspath(OUTPUT_DIR)}")

反思

很明显这次建模吃了选题红利,在建模方法并没有很突出的情况下,凭借着选题优势拿到了这些奖项。在写代码的过程中还出现了一些小插曲,比如对numpy和pandas库不熟悉,导致csv处理困难等等。

我认为在当下这个人工智能高速发展的时代,我们一定要从人工智能中学习到真本事。不能作为人工智能产物的搬运工。在本次比赛中我们借助人工智能完善了代码,但个人能力并没有显著提高,掌握这些代码方法的是AI不是个人。我们应当从AI反馈的结果中学习,形成自己的核心技术。

博客由 Hugo 强力驱动,主题采用由 Jimmy 设计的 Stack ,并由 lamaper 个性化修改。