用 AI 辅助分析历史经济周期:按朝代切片的数据科学实验
一、个性化深度引言
经济学教材上写着“经济危机大约每 10 年一次”,但这基于 20 世纪的工业经济数据。有没有可能从更长的历史维度看经济周期?
我们做了一次实验:将中国从秦汉到明清 2000 多年的经济史数据整理成结构化数据,用统计和机器学习方法分析周期性规律。这不是一个严谨的经济学研究——历史数据的质量远不能和现代统计数据相比。但方法论上有趣的发现是:即使数据充满噪声,一些跨朝代的统计规律仍然浮现出来。见证奇迹的时刻在于:当把朝代更替作为断点做结构性变化检验时,数据自己讲述了比教科书更丰富的故事。
二、个性化原理剖析
历史经济周期分析框架
数据处理中的关键挑战
1. 数据稀疏性
古代经济数据的覆盖度极不均匀。宋以后有相对详细的粮价记录,之前的只能靠《史记》《汉书》中的碎片化信息。处理方法:对稀疏时期使用线性插值,但必须标注插值区间以降低对分析结果的影响权重。
2. 计量单位不一致
唐代用“石”,宋代用“斗”,明代用“两”(白银)。需要在统一单位之前追溯每个朝代的度量衡换算关系。
3. 记录偏差
史书记录偏向“大事件”——大丰收、大饥荒、大规模战争。日常年份的数据反而是缺失的。这种“极端值偏向”会影响均值和方差的估计。
分析方法的选择
频谱分析:将时间序列转换到频域,寻找周期性成分。傅里叶变换 + 小波变换可用于非平稳序列。
结构断点检验:检验时间序列在朝代更替时是否存在结构性变化。Chow Test 或 Bai-Perron 检验。
事件研究法:以重大事件(如变法、战争)为中心,观察前后 N 年的经济指标变化模式。
三、个性化代码实践
import numpy as np
import pandas as pd
from typing import List, Dict, Tuple, Optional
from dataclasses import dataclass
from scipy import signal, stats
from collections import defaultdict
@dataclass
class Dynasty:
"""朝代数据结构"""
name: str
start_year: int
end_year: int
capital: str
notes: str = ""
class HistoricalEconomicAnalyzer:
"""
历史经济周期分析器
重要说明:历史数据的准确性有限
本分析目的是方法探索,结论需谨慎解释
"""
# 设计原因:中国主要朝代时间线
# 数据来源:《中国大百科全书》历史卷
# 朝代起止年份在学界有不同观点,此处采用通用分类
DYNASTIES = [
Dynasty("秦", -221, -206, "咸阳"),
Dynasty("西汉", -206, 8, "长安"),
Dynasty("新", 9, 23, "长安"),
Dynasty("东汉", 25, 220, "洛阳"),
Dynasty("三国", 220, 280, "多都"),
Dynasty("西晋", 265, 316, "洛阳"),
Dynasty("东晋", 317, 420, "建康"),
Dynasty("南北朝", 420, 589, "多都"),
Dynasty("隋", 581, 618, "大兴"),
Dynasty("唐", 618, 907, "长安"),
Dynasty("五代十国", 907, 960, "多都"),
Dynasty("北宋", 960, 1127, "开封"),
Dynasty("南宋", 1127, 1279, "临安"),
Dynasty("元", 1271, 1368, "大都"),
Dynasty("明", 1368, 1644, "北京"),
Dynasty("清", 1644, 1911, "北京"),
]
def __init__(self):
self.data: pd.DataFrame = None
self.results: Dict = {}
def generate_synthetic_data(self) -> pd.DataFrame:
"""
生成模拟历史经济数据
设计原因:真实古代经济数据的获取极为困难
此处用模拟数据展示分析方法框架
"""
np.random.seed(42)
# 时间范围:公元前 200 年到公元 1911 年
years = np.arange(-200, 1912)
n = len(years)
# 基础趋势:长期增长 + 周期成分
trend = 0.00001 * years # 极其缓慢的增长
# 设计原因:40-60 年周期(Kondratiev 波浪的假设)
cycle_60 = 0.3 * np.sin(2 * np.pi * years / 60)
cycle_120 = 0.2 * np.sin(2 * np.pi * years / 120)
# 朝代效应:每个朝代的基线水平略有不同
dynasty_effect = np.zeros(n)
for dyn in self.DYNASTIES:
mask = (years >= dyn.start_year) & (years <= dyn.end_year)
if mask.any():
# 设计原因:每个朝代的经济基线不同
dynasty_effect[mask] = np.random.normal(0, 0.15)
# 随机波动
noise = np.random.normal(0, 0.2, n)
# 合成经济指标(如:人均粮食产量指数)
economic_index = trend + cycle_60 + cycle_120 + dynasty_effect + noise
# 添加一些重大事件的冲击
events = {
-200: -0.5, # 秦末战乱
8: -0.3, # 王莽代汉
184: -0.4, # 黄巾起义
755: -0.6, # 安史之乱
1127: -0.5, # 靖康之变
1644: -0.4, # 明末农民起义
}
for year, shock in events.items():
if year in years:
idx = list(years).index(year)
# 冲击影响持续 5 年
for j in range(5):
if idx + j < n:
economic_index[idx + j] += shock * (0.8 ** j)
df = pd.DataFrame({
"year": years,
"economic_index": economic_index,
})
# 添加朝代标签
df["dynasty"] = "未知"
for dyn in self.DYNASTIES:
mask = (df["year"] >= dyn.start_year) & (df["year"] <= dyn.end_year)
df.loc[mask, "dynasty"] = dyn.name
return df
def spectral_analysis(
self, df: pd.DataFrame, indicator: str = "economic_index"
) -> Dict:
"""
频谱分析:寻找周期成分
设计原因:傅里叶变换将时域信号转为频域
峰值频率对应周期成分
"""
values = df[indicator].dropna().values
# 去趋势(避免趋势信号干扰周期检测)
from scipy.signal import detrend
detrended = detrend(values)
# 傅里叶变换
fft = np.fft.fft(detrended)
freqs = np.fft.fftfreq(len(detrended))
# 只考虑正频率
pos_mask = freqs > 0
freqs_pos = freqs[pos_mask]
power = np.abs(fft[pos_mask]) ** 2
# 找到峰值
from scipy.signal import find_peaks
peaks, properties = find_peaks(
power,
height=np.percentile(power, 95), # 只取最高 5%
distance=5,
)
# 设计原因:频率 → 周期(年)
peak_periods = []
for peak_idx in peaks:
if freqs_pos[peak_idx] > 0:
period = 1 / freqs_pos[peak_idx]
if 10 <= period <= 300: # 只关注 10-300 年的周期
peak_periods.append({
"period_years": round(period, 1),
"frequency": freqs_pos[peak_idx],
"power": power[peak_idx],
})
return {
"peak_periods": sorted(
peak_periods, key=lambda x: x["power"], reverse=True
)[:5], # Top 5
"dominant_period": peak_periods[0]["period_years"] if peak_periods else None,
}
def structural_break_test(
self,
df: pd.DataFrame,
indicator: str = "economic_index",
) -> pd.DataFrame:
"""
结构性变化检验:朝代更替是否为断点
设计原因:如果朝代更替是统计意义上的断点
说明政权变化对经济有实质性影响
"""
values = df[indicator].values
years = df["year"].values
n = len(values)
break_results = []
# 对每个朝代边界做检验
for i, dyn in enumerate(self.DYNASTIES):
# 找到朝代开始年份在数据中的位置
start_idx = np.searchsorted(years, dyn.start_year)
end_idx = np.searchsorted(years, dyn.end_year)
# 设计原因:断点前后至少需要 30 个数据点
if start_idx < 30 or (n – start_idx) < 30:
continue
# 简单版本:比较朝代前后 30 年的均值差异
before = values[max(0, start_idx-30):start_idx]
after = values[start_idx:min(n, start_idx+30)]
if len(before) > 0 and len(after) > 0:
t_stat, p_value = stats.ttest_ind(before, after)
break_results.append({
"dynasty": dyn.name,
"start_year": dyn.start_year,
"mean_before": np.mean(before),
"mean_after": np.mean(after),
"t_statistic": t_stat,
"p_value": p_value,
"significant_0.05": p_value < 0.05,
})
return pd.DataFrame(break_results)
def event_study(
self,
df: pd.DataFrame,
events: Dict[int, str],
window: int = 10,
) -> pd.DataFrame:
"""
事件研究法
设计原因:观测重大事件前后经济指标的变化模式
典型应用:变法、战争、自然灾害的影响评估
"""
all_windows = []
for year, event_name in events.items():
year_idx = df.index[df["year"] == year]
if len(year_idx) == 0:
continue
idx = year_idx[0]
start = max(0, idx – window)
end = min(len(df), idx + window + 1)
event_data = df.iloc[start:end].copy()
event_data["relative_year"] = range(
-min(idx – start, window),
min(end – idx, window + 1),
)
event_data["event"] = event_name
all_windows.append(event_data)
if not all_windows:
return pd.DataFrame()
return pd.concat(all_windows, ignore_index=True)
def run_full_analysis(self) -> Dict:
"""运行完整分析"""
print("=" * 60)
print("历史经济周期分析报告")
print("警告:本分析基于模拟数据,结论不能作为历史研究依据")
print("=" * 60)
# 生成数据
df = self.generate_synthetic_data()
# 1. 频谱分析
print("\\n1. 频谱分析(周期检测):")
spectrum = self.spectral_analysis(df)
print(f" 主导周期:{spectrum['dominant_period']} 年")
for p in spectrum["peak_periods"][:3]:
print(f" – {p['period_years']} 年周期(能量: {p['power']:.2f})")
# 2. 结构性断点检验
print("\\n2. 结构性断点检验(朝代更替):")
breaks = self.structural_break_test(df)
significant = breaks[breaks["significant_0.05"]]
print(f" 显著断点:{len(significant)} / {len(breaks)} 个朝代边界")
for _, row in significant.iterrows():
print(f" – {row['dynasty']}: "
f"均值 {row['mean_before']:.3f} → {row['mean_after']:.3f}"
f" (p={row['p_value']:.4f})")
# 3. 事件研究
print("\\n3. 事件研究(重大事件前后 10 年):")
events = {
-200: "秦统一六国",
755: "安史之乱",
1644: "明清更替",
}
event_data = self.event_study(df, events, window=10)
for event_name in events.values():
e_data = event_data[event_data["event"] == event_name]
if e_data.empty:
continue
before = e_data[e_data["relative_year"] < 0]["economic_index"].mean()
after = e_data[e_data["relative_year"] > 0]["economic_index"].mean()
change_pct = (after – before) / max(abs(before), 1e-8) * 100
print(f" – {event_name}: "
f"事件前后变化 {change_pct:+.1f}%")
return {
"spectrum": spectrum,
"breaks": breaks,
"event_data": event_data,
}
# 运行分析
analyzer = HistoricalEconomicAnalyzer()
results = analyzer.run_full_analysis()
print(f"\\n方法论的局限性:")
print(" 1. 古代经济数据来源有限且存在记录偏差")
print(" 2. 插值填补的数据降低了统计检验效力")
print(" 3. 相关关系不等于因果关系")
print(" 4. 本分析为方法演示,真实研究需要与历史学家合作")
四、个性化边界权衡
| 频谱分析 | 周期规律 | 长序列 200+ | 中(受插值影响) | 寻找周期 |
| 结构断点检验 | 朝代更替影响 | 断点前后 30+ | 中(依赖断点定义) | 政策/制度评估 |
| 事件研究法 | 事件冲击 | 事件前后 5-10 年 | 低(混杂因素多) | 短期影响评估 |
| 面板数据分析 | 地区差异 | 多地数据 30+ | 中 | 区域比较 |
| 机器学习预测 | 模式识别 | 大量标注 | 低(因果混淆) | 辅助假设生成 |
关键权衡:
五、总结
用 AI 和数据科学方法分析历史经济周期,核心价值不在结论而在方法。频谱分析可检测时间序列中的周期成分(40-60 年周期的假设在此框架下可检验),结构断点检验可判断朝代更替是否构成统计意义上的经济断点,事件研究法可观测重大事件的短期冲击模式。数据层面的三大挑战是:稀疏性(需要插值但必须标注不确定性)、单位不一致(需要跨朝代度量衡换算)、记录偏差(史书记录偏好极端事件)。工程上,建议采用多方法交叉验证(不同方法得出相似结论时才认真对待),并与历史学专业知识结合(统计分析不应脱离历史脉络的定性理解)。最终,这类分析的价值是生成可检验的假设,而非得出确定性的历史结论。

![[特殊字符]DeepSeek‑Harness(DSH)小白保姆教程-171主机测评](https://www.171host.com/wp-content/uploads/2026/08/20260816085112-6a817a009aabf-220x150.png)
