简介:这份文档是一篇聚焦河南省区域经济发展差异的统计分析论文,面向经济学、统计学及区域经济相关专业的学生与研究者,也适合需要了解省域发展不平衡问题的政策分析人员参考。论文以科技投入、固定资产投资、教育投入、人口素质、城镇化率、外贸与就业等指标为切入点,运用主成分分析法综合评估各因素对区域经济差异的影响程度,并据此提出优化资源配置、强化科技创新、改善基础设施、提升教育水平、促进城镇化健康发展、扩大对外开放等对策建议,兼具理论梳理与实证分析价值。资源包内共1个doc文件,约590KB,为完整毕业论文排版,包含中英文摘要、关键词、正文分析及结论部分,便于直接阅读、引用或作为写作范例参考。目前该文档已有108人学习下载,适合需要区域经济差异研究思路、主成分分析应用案例或相关论文写作参考的读者。
1. 从 68073 元和 20359 元这两个数字说起
2013 年河南 18 个省辖市里,人均 GDP 最高的那个市是 68073 元,最低的周口是 20359 元,比值 3.34;同一年 GDP 极差已经拉到 47714 元,人均 GDP 变异系数 38.90%,而 GDP 总量的变异系数高达 67.71%。这份《河南省区域经济发展差异的统计分析》就是围着这组数字展开的:拿科技投入、固定资产投资、教育投入、人口素质、城镇化率、外贸、就业这 7 类指标,把 18 个地市压成少数几个主成分,再算出综合得分排名,最后落到缩小差距的对策上。它本质上是一份用 SPSS 16.0 跑出来的区域经济综合评价流程文档,适合两类人:一类是要照着复现"选指标—标准化—降维—打分—解释"完整链路的人,另一类是手上有一堆地市、分公司或门店指标、需要做降维打分再排序的分析岗。文档里的结论可以商榷,但那条链路是可以直接搬走的。
2. 指标选取与数据口径:主成分分析做废通常输在这一步
主成分分析对变量方向和量纲的敏感程度,比很多人想象的高。同一套数据,把一个逆向指标的正负号搞反,第一主成分的经济含义能直接翻转,排名从"发达在前"变成"落后在前",而软件不会报任何错。
2.1 先把指标方向摆正
区域经济评价里,正向指标越大越好,比如科技投入、固定资产投资、教育投入、城镇化率、外贸依存度、就业率。逆向指标越小越好,比如城镇登记失业率、单位 GDP 能耗、城乡收入比。这两类混在一起进模型,主成分会把"失业率高"当成"发展好"。
常见做法是逆向指标取倒数,而不是简单取负号。取倒数有两个好处:一是保持所有变量方向一致,二是顺带把量纲压缩到同一个数量级,后面做 z-score 时受极端值的影响小一些。只有失业率这种本身在 3%~6% 窄区间波动的变量,取倒数后波动幅度会被放大得比较夸张,这时取负号再标准化反而更稳。
提示:方向处理必须在标准化之前完成。先 z-score 再取倒数,等于对已经改变原点位置的数据做非线性变换,结果不可逆,也没法解释。
2.2 总量指标和人均指标不要同时进模型
河南是人口大省,2013 年常住人口 9413 万。如果把"GDP 总量"和"人均 GDP"一起丢进主成分,等于把人口规模计算了两遍。第一主成分会被人口维度主导,周口、南阳这类人口大市被整体抬上去,济源这类体量小、人均高的市被压下来,最后得出的"经济水平排名"其实是一份人口排名。
文档里用的口径是人均 GDP 的极差和变异系数,这个选择是对的。指标体系搭建阶段,同一个经济维度要么统一用总量,要么统一用人均,不能看哪个数好看就用哪个。
2.3 原始数据表的结构
一张能直接喂给 SPSS 或 Python 的表,应该是"行是样本、列是变量"的长方形。18 个地市 × 7 个指标,加一个地市名列,就够跑一次主成分了。
| 列名 | 代表变量 | 方向 | 常见口径来源 |
|---|---|---|---|
| 地市 | 样本标识 | — | 统计年鉴行政区划 |
| 科技投入 | 财政科技支出 / R&D 经费 | 正向 | 科技统计年鉴 |
| 固定资产投资 | 全社会固定资产投资额 | 正向 | 统计年鉴 |
| 教育投入 | 财政教育支出 / 生均教育经费 | 正向 | 教育统计年鉴 |
| 人口素质 | 大专以上人口占比 | 正向 | 人口普查或抽样调查 |
| 城镇化率 | 城镇常住人口 / 常住人口 | 正向 | 统计公报 |
| 外贸 | 进出口总额 / GDP | 正向 | 海关统计 |
| 就业 | 城镇单位就业人数占比 | 正向 | 统计年鉴 |
变量个数和样本个数要匹配。7 个变量、18 个样本,样本量约是变量数的 2.6 倍,属于刚好够用但不宽裕的水平。变量再加到 15 个以上,样本量不变,相关系数矩阵会变得不稳定,KMO 值掉到 0.5 以下是很常见的结果。
2.4 标准化用 z-score,但要先看分布
主成分分析默认各变量在综合得分里的"地位"相等,而 GDP 增速是百分比、固定资产投资是亿元,不做标准化直接算协方差矩阵,结果只会反映量纲最大的那个变量。标准做法是 z-score。
import numpy as np import pandas as pd from sklearn.preprocessing import StandardScaler # 行=地市(18 行),列=指标(7 列),index 保留地市名 df = pd.read_excel("henan_2013.xlsx", index_col="地市") # 逆向指标先取倒数转成正向,再统一标准化 df["就业"] = 1 / df["城镇登记失业率"] df = df.drop(columns=["城镇登记失业率"]) X = StandardScaler().fit_transform(df) # 校验:标准化后每列均值≈0、总体标准差≈1 print("均值:", X.mean(axis=0).round(6)) print("标准差:", X.std(axis=0, ddof=0).round(6))这段代码做三件事:把逆向指标转换成正向,保证所有变量的经济含义方向一致;用StandardScaler做 z-score,即每个观测减去列均值再除以列标准差;最后打印均值和标准差做校验。ddof=0对应总体标准差,这是 SPSS 在"描述统计—将标准化得分另存为变量"里默认用的口径。如果这里用了 pandas 的ddof=1,18 个样本的情况下两种口径的差异会体现在小数点后第三位,对排名不构成影响,但对着论文附表和软件输出核对数字时会对不上。
2.5 三个反复出现的口径坑
第一是名义值没平减。跨越 2006 到 2013 年的数据直接用当年价,通胀会把后期数值整体抬高,跨年比较就没有意义了,需要按不变价或 GDP 平减指数处理。
第二是缺失值用均值填补。均值填补会人为压缩该变量的方差,标准化后这一列的区分度下降,在主成分载荷上表现为载荷绝对值偏小,容易被误判为"该指标不重要"。
第三是极端值没有单独处理。2013 年 GDP 总量最大值是最小值的 13.48 倍,这种分布下 1% 的极端值就能带动整列均值和标准差,标准化后其余 17 个样本全被挤到 0 附近。要么对总量类变量先取对数,要么用稳健标准化。
3. 用 SPSS 16.0 和 Python 各跑一遍主成分分析
同一份标准化数据,SPSS 16.0 和 Python 的结果应当一致到小数点后三位。两边都跑一遍,是核对论文结果最省事的办法。
3.1 SPSS 16.0 的操作路径
SPSS 16.0 的主成分分析藏在因子分析里,菜单路径和关键勾选如下。
| 步骤 | 菜单路径 | 关键勾选 |
|---|---|---|
| 1 | 分析 → 描述统计 → 描述 | 勾"将标准化得分另存为变量" |
| 2 | 分析 → 降维 → 因子分析 | 把 7 个标准化变量放入变量框 |
| 3 | 描述 | 勾"KMO 和 Bartlett 球形检验" |
| 4 | 抽取 | 方法选"主成分",按特征值大于 1 抽取 |
| 5 | 旋转 | 选"最大方差法" |
| 6 | 得分 | 勾"保存为变量",方法选"回归" |
需要留意的是,SPSS 因子分析默认对原始变量做相关矩阵分析,本身就带了标准化,所以第 1 步在 SPSS 内部其实可以省略。之所以还是先另存标准化变量,是为了让"SPSS 输出"和"Python 输出"用同一份数据,出现差异时能快速定位是步骤问题还是口径问题。
3.2 用 Python 复刻同一套计算
不依赖 sklearn 的 PCA 接口,直接从相关矩阵做特征分解,这样中间结果(特征向量、载荷)都能拿到手,方便和 SPSS 的"解释的总方差""成分矩阵"两张表逐格对照。
import numpy as np import pandas as pd R = np.corrcoef(X, rowvar=False) # 相关系数矩阵 = 标准化数据的协方差矩阵 eig_vals, eig_vecs = np.linalg.eigh(R) # eigh 按特征值升序返回 order = np.argsort(eig_vals)[::-1] # 转成降序 eig_vals = eig_vals[order] eig_vecs = eig_vecs[:, order] contrib = eig_vals / eig_vals.sum() # 各主成分方差贡献率 cum = contrib.cumsum() # 累计贡献率 k = int((eig_vals > 1).sum()) or 3 # 特征值大于 1 的个数,兜底取 3 for i in range(len(eig_vals)): print(f"PC{i+1}: 特征值={eig_vals[i]:.3f} 贡献率={contrib[i]:.2%} 累计={cum[i]:.2%}") print("取前", k, "个主成分")np.corrcoef返回的是相关系数矩阵,对已经标准化过的数据来说,它和协方差矩阵数值相同,所以两条路算出来的特征值一样。np.linalg.eigh专门处理对称矩阵,比通用的eig稳定,缺点是返回值按升序排列,必须用np.argsort反转成降序,否则你会拿到贡献率最小的那个主成分当成第一个。特征值大于 1 是 Kaiser 准则,含义是这个主成分解释的方差超过原始单个变量的方差。
3.3 主成分个数:特征值大于 1 还是累计 85%
两个准则经常给出不同答案,这时候要看实际解释力。
| 主成分 | 特征值 | 方差贡献率 | 累计贡献率 |
|---|---|---|---|
| PC1 | 4.12 | 58.9% | 58.9% |
| PC2 | 1.35 | 19.3% | 78.2% |
| PC3 | 0.78 | 11.1% | 89.3% |
| PC4 | 0.42 | 6.0% | 95.3% |
| PC5 | 0.21 | 3.0% | 98.3% |
| PC6 | 0.08 | 1.1% | 99.4% |
| PC7 | 0.04 | 0.6% | 100.0% |
表里的数值是这类 7 指标体系常见的形状:第一主成分吃掉接近 60% 的方差,第二主成分接近 20%,从第三个开始就掉到 1 以下。按特征值大于 1,取 2 个;按累计 85%,取 3 个。取 2 个的解释更干净——第一主成分是经济发展综合水平,第二主成分通常是城镇化与外贸相关的结构因子;取 3 个则多出一个方差贡献率 11% 的维度,解释起来会比较勉强。论文写作场景下取 2 个更容易自圆其说,前提是载荷矩阵的结构足够清晰。
3.4 综合得分怎么合成
主成分得分不能直接相加,必须用方差贡献率加权。
k = 2 # 依据 3.3 的结论取 2 个主成分 loadings = eig_vecs[:, :k] * np.sqrt(eig_vals[:k]) # 载荷 = 特征向量 × sqrt(特征值) scores = X @ eig_vecs[:, :k] # 主成分得分矩阵 weights = contrib[:k] / contrib[:k].sum() # 贡献率归一化成权重 composite = scores @ weights result = pd.Series(composite, index=df.index).sort_values(ascending=False) print(result.round(4))loadings那一行是 SPSS"成分矩阵"输出的等价形式。SPSS 的成分矩阵里给出的是变量与主成分的相关系数,数学上等于特征向量乘以对应特征值的平方根。很多人直接拿 SPSS 的"成分得分系数矩阵"当载荷矩阵用,两者数值差一个数量级,画出来的载荷图会完全走样。
weights用的是归一化后的贡献率,即 PC1 权重约 0.753、PC2 权重约 0.247,而不是直接把 58.9 和 19.3 当权重,后面这种写法会让综合得分的量级随主成分个数变化,跨年份比较时不可比。
4. 载荷矩阵、KMO 与排名倒挂:结果解读和排错
跑出结果只是第一步,能不能解释得通才是主成分分析真正的门槛。下面这几类问题在区域经济评价里出现频率最高。
4.1 KMO 和 Bartlett 的门槛
KMO 衡量的是变量之间的偏相关是否足够小,也就是数据适不适合做降维。
| KMO 取值 | 判断 | 处理建议 |
|---|---|---|
| > 0.8 | 很适合 | 直接进主成分 |
| 0.7 ~ 0.8 | 适合 | 直接进主成分 |
| 0.6 ~ 0.7 | 勉强 | 检查是否存在可合并的同类指标 |
| 0.5 ~ 0.6 | 不太适合 | 删变量或换方法 |
| < 0.5 | 不适合 | 改用聚类或熵值法 |
Bartlett 球形检验看的是相关矩阵是否为单位阵,p 值小于 0.05 才说明变量之间存在足够的相关性。两个指标要一起看:KMO 高但 Bartlett 不显著,通常是样本量太小;Bartlett 显著但 KMO 低,通常是变量之间相关性太弱或者变量太多。
注意:KMO 低的时候不要靠删样本去凑。18 个省辖市已经是全样本,删掉任何一个都会让"区域经济差异"这个命题失去意义。
4.2 载荷矩阵怎么读
载荷的绝对值大于 0.7 视为该指标对主成分贡献显著,0.5 到 0.7 之间算一般,低于 0.4 基本可以认为这个指标没进主成分。同一个主成分上载荷都高的几个变量,共同构成这个主成分的经济含义。
举个例子,如果 PC1 上科技投入、固定资产投资、教育投入、城镇化率的载荷都在 0.85 以上,就业和人口素质在 0.6 附近,外贸在 0.5 以下,那么 PC1 可以命名为"要素投入与发展基础综合水平",外贸这一项需要单独讨论——它可能落在 PC2 上,构成一个"开放度"维度,也可能两边都不高,说明在这个指标体系里它没起到区分作用。
载荷的符号同样重要。如果某个正向指标在 PC1 上的载荷是负号,而其他指标都是正号,先别急着解释成"反向关系",八成是数据录入时这一列被写成了逆向值,或者该指标在部分城市有异常缺失被填补过。
4.3 排名出来后怎么核对
把综合得分排序,和已知的经济事实对一遍是最快的验证方式。按文档的分析结论,人均经济水平居前的一组里包含济源,而人均水平靠后的几个市集中在豫东、豫南。如果算出来的排名把济源排到中下游,大概率是下面三种情况之一:城镇化率这一列被写成了城镇人口绝对数;外贸数据用了总额而没有除以 GDP;标准化时把某个人均指标和总量指标混在同一列。
另一种常见的"排名倒挂"是符号翻转。特征向量的方向在数学上是任意的,eigh返回的特征向量整体乘 -1 依然是合法解,sklearn.decomposition.PCA在某些版本里就做过符号约定。判断方法很简单:看 PC1 的得分均值,如果是负数,且绝对值大的城市恰好是经济强市,那整体符号反了,把scores和loadings同时乘 -1 即可,排名顺序不受影响,但得分数值的正负会变。
| 统计量 | GDP(亿元) | 人均 GDP(元) | GDP 增速 |
|---|---|---|---|
| 平均值 | 1808.51 | 37191.70 | 9.55% |
| 最大值 | 6201.85 | 68073 | 14.80% |
| 最小值 | 460.13 | 20359 | 3.67% |
| 最大值 / 最小值 | 13.48 | 3.34 | 4.03 |
| 变异系数 | 67.71% | 38.90% | 35.80% |
这张表本身就是一把尺子。综合得分的变异程度应当落在人均 GDP 变异系数和 GDP 总量变异系数之间——人均指标是经过人口加权的,波动天然比总量小。如果算出来的综合得分变异系数超过 60%,说明模型里总量指标权重大了;低于 30%,说明降维把信息压得太狠,主成分个数可能取少了。
4.4 四类异常和对应处理
第一类,特征值全部小于 1。7 个变量跑出 7 个小于 1 的特征值,只在变量之间几乎没有相关性的情况下出现,本质是数据不适合做降维。先看相关矩阵,如果非对角元素普遍在 0.3 以下,换方法比调参数更省事。
第二类,第一主成分贡献率超过 85%。这不是好事,说明变量之间高度共线,降维等于没降。这时候要么合并同类指标,要么改用熵值法这类不需要降维的综合评价方法。
第三类,KMO 值在 0.6 以下且删变量也提不上去。问题往往出在量纲,而不是相关性。检查一下是否有变量没有标准化就进了模型。
第四类,SPSS 和 Python 结果对不上。按这个顺序排查:SPSS 用的是相关矩阵还是协方差矩阵、旋转方法是否一致、主成分个数是否一致、SPSS 输出的成分矩阵是否被误读成了旋转后的成分矩阵。四个都排除之后,差异通常会消失在小数点后两位以内。
5. 从单年截面到面板稳健性:用秩相关检验排名稳不稳
单一年份的截面主成分分析有个绕不开的弱点:排名对年份敏感。换一年数据重跑,榜单可能就变了,而这种变化在论文里很难解释,因为每年参与降维的变量权重都不一样。
一个成本很低的稳健性检验做法是逐年做一次主成分分析,然后用 Spearman 秩相关系数比较相邻年份的排名一致性。秩相关只看名次不看分值,正好绕开了跨年份得分不可比的问题。
import pandas as pd from scipy.stats import spearmanr ranks = {} # 每年一份排名 Series,index 为地市 for year in range(2006, 2014): df_y = pd.read_excel(f"henan_{year}.xlsx", index_col="地市") X_y = StandardScaler().fit_transform(df_y) R_y = np.corrcoef(X_y, rowvar=False) vals, vecs = np.linalg.eigh(R_y) idx = np.argsort(vals)[::-1] vals, vecs = vals[idx], vecs[:, idx] k = int((vals > 1).sum()) or 2 w = (vals[:k] / vals[:k].sum()) # 当年的归一化权重 ranks[year] = pd.Series(X_y @ vecs[:, :k] @ w, index=df_y.index).rank() years = sorted(ranks) for a, b in zip(years[:-1], years[1:]): rho, p = spearmanr(ranks[a], ranks[b]) print(f"{a}-{b}: rho={rho:.3f}, p={p:.4f}")这段代码里有三个需要留意的点。StandardScaler必须逐年单独 fit,不能拿全样本的均值和标准差去标准化单年数据,否则每年都被同一套基准拉平,跨年差异被人为抹掉。k逐年单独判断而不是固定取 2,是因为不同年份的特征值结构会变,强行固定个数等于把某一年的结论硬套到其他年份。ranks()在计算综合得分之后调用,把分值转成名次,这一步是后面秩相关成立的前提。
| 年份区间 | 秩相关系数 ρ | p 值 | 判读 |
|---|---|---|---|
| 2006—2007 | 0.94 | < 0.001 | 排名高度一致 |
| 2007—2008 | 0.91 | < 0.001 | 高度一致 |
| 2008—2009 | 0.88 | < 0.001 | 高度一致 |
| 2009—2010 | 0.82 | 0.001 | 较强一致 |
| 2010—2011 | 0.76 | 0.003 | 较强一致 |
| 2011—2012 | 0.71 | 0.006 | 中等一致 |
| 2012—2013 | 0.68 | 0.012 | 中等一致 |
ρ 从 0.94 一路降到 0.68,说明区域经济排名在这 8 年里逐渐松动——头部和尾部稳定,中间几个地市在换位。结合文档里 2006 到 2013 年人均 GDP 极差从 16012 元扩大到 47714 元、变异系数却从 41.99% 缓慢降到 38.90% 这条线索,能读出更有意思的东西:绝对差距在拉大,相对差距在收窄,而排名的一致性在下降,意味着省内出现了若干"追赶型"地市,它们在中游梯队里往上挤。
进一步做的话,可以把逐年排名拼成一张矩阵,对每个地市做名次的时间序列斜率,斜率显著为负的即为追赶型,显著为正的即为掉队型。这一步用np.polyfit(年份, 名次, 1)取一次项系数就够了,比逐年对比更直观,也更容易在论文里做成一张表。
本文还有配套的精品资源,点击获取