导入数据¶
In [1]:
import pandas as pd
c0m0full = pd.read_csv(r'D:\论文\最后一波一鼓作气\数据\c0m0full.csv')
c1m1full = pd.read_csv(r'D:\论文\最后一波一鼓作气\数据\c1m1full.csv')
hsf15full = pd.read_csv(r'D:\论文\最后一波一鼓作气\数据\hsf15full.csv')
hsf18full = pd.read_csv(r'D:\论文\最后一波一鼓作气\数据\hsf18full.csv')
city_gender_age_premium_ratio_district15 = pd.read_csv(r'D:\论文\最后一波一鼓作气\数据\city_gender_age_premium_ratio_district15.csv')
In [2]:
#删除城市样本
c1m1full = c1m1full[c1m1full['urban_nbs'] != 'Urban']
#确保15年未整合,18年整合了
c1m1full = c1m1full[(c1m1full['policyintergration2015']==0.0) & (c1m1full['policyintergration2018']==1.0)]
c1m1= c1m1full[['ID', 'c1','m1']]
#删除城市样本
c0m0full = c0m0full[c0m0full['urban_nbs'] != 'Urban']
#确保15年未整合,18年整合了
c0m0full = c0m0full[(c0m0full['policyintergration2015']==0.0) & (c0m0full['policyintergration2018']==1.0)]
c0m0= c0m0full[['ID', 'c0','m0']]
#删除城市样本
hsf15full = hsf15full[hsf15full['urban_nbs'] != 'Urban']
#确保15年未整合,18年整合了
hsf15full = hsf15full[(hsf15full['policyintergration2015']==0.0) & (hsf15full['policyintergration2018']==1.0)]
hsf15= hsf15full[['ID', 'hsf15']]
#删除城市样本
hsf18full = hsf18full[hsf18full['urban_nbs'] != 'Urban']
#确保15年未整合,18年整合了
hsf18full = hsf18full[(hsf18full['policyintergration2015']==0.0) & (hsf18full['policyintergration2018']==1.0)]
hsf18= hsf18full[['ID', 'hsf18']]
最优化方法¶
consumption-based:合并数据¶
In [3]:
data = pd.merge(c0m0, c1m1full,on="ID", how="inner")
data
Out[3]:
| ID | c0 | m0 | householdID | communityID | c1 | m1 | gender | age | marriage | ... | premium2018 | r0 | r1 | r0adjust | r1adjust | policyintergration2015 | policyintergration2018 | district | GDPgrowthrate | urban_nbs | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 64033321002 | 112.216 | 60.0 | 640333210 | 640333 | 123.670 | 0.0 | 0.0 | 59.0 | 1.0 | ... | 180.0 | 0.6167 | 0.700 | 0.544192 | 0.660903 | 0.0 | 1.0 | east | 0.118005 | Rural |
| 1 | 64033327002 | 1029.200 | 6000.0 | 640333270 | 640333 | 1054.764 | 21000.0 | 0.0 | 62.0 | 1.0 | ... | 180.0 | 0.6167 | 0.700 | 0.544192 | 0.660903 | 0.0 | 1.0 | east | 0.118005 | Rural |
| 2 | 64033325001 | 1062.400 | 3000.0 | 640333250 | 640333 | 78.020 | 100.0 | 1.0 | 66.0 | 1.0 | ... | 180.0 | 0.6167 | 0.700 | 0.544192 | 0.660903 | 0.0 | 1.0 | east | 0.118005 | Rural |
| 3 | 64033322001 | 592.620 | 2000.0 | 640333220 | 640333 | 859.050 | 17050.0 | 1.0 | 63.0 | 1.0 | ... | 180.0 | 0.6167 | 0.700 | 0.544192 | 0.660903 | 0.0 | 1.0 | east | 0.118005 | Rural |
| 4 | 64033330002 | 2058.400 | 2000.0 | 640333300 | 640333 | 4025.500 | 2000.0 | 1.0 | 59.0 | 1.0 | ... | 180.0 | 0.6167 | 0.700 | 0.544192 | 0.660903 | 0.0 | 1.0 | east | 0.118005 | Rural |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 3882 | 89676104001 | 2315.700 | 840.0 | 896761040 | 896761 | 891.420 | 8000.0 | 1.0 | 61.0 | 1.0 | ... | 220.0 | 0.6500 | 0.725 | 0.624462 | 0.685108 | 0.0 | 1.0 | west | 0.284050 | Rural |
| 3883 | 89676114002 | 1935.145 | 300.0 | 896761140 | 896761 | 49.800 | 0.0 | 0.0 | 56.0 | 0.0 | ... | 220.0 | 0.6500 | 0.725 | 0.624462 | 0.685108 | 0.0 | 1.0 | west | 0.284050 | Rural |
| 3884 | 89676118001 | 2466.096 | 1000.0 | 896761180 | 896761 | 661.095 | 3000.0 | 0.0 | 73.0 | 0.0 | ... | 220.0 | 0.6500 | 0.725 | 0.624462 | 0.685108 | 0.0 | 1.0 | west | 0.284050 | Rural |
| 3885 | 89676115001 | 10721.940 | 800.0 | 896761150 | 896761 | 11638.260 | 2000.0 | 1.0 | 55.0 | 1.0 | ... | 220.0 | 0.6500 | 0.725 | 0.624462 | 0.685108 | 0.0 | 1.0 | west | 0.284050 | Rural |
| 3886 | 89676124001 | 268.422 | 500.0 | 896761240 | 896761 | 313.242 | 101.0 | 1.0 | 69.0 | 0.0 | ... | 220.0 | 0.6500 | 0.725 | 0.624462 | 0.685108 | 0.0 | 1.0 | west | 0.284050 | Rural |
3887 rows × 26 columns
In [4]:
#最优化方法——消费计算(表5consumption based平衡面板)
import pandas as pd
import numpy as np
# 计算 E(c0^(-sigma)) 和 E(c1^(-sigma))
E_c0_inv2 = (data['c0']**(-3)).mean()
E_c1_inv2 = (data['c1']**(-3)).mean()
# 计算协方差
cov_c0_inv2 = np.cov(data['c0']**(-3) / E_c0_inv2, (data['r0'] - data['r1']) * data['m0'] + data['premium2015'] - data['premium2018'])[0, 1]
cov_c1_inv2 = np.cov(data['c1']**(-3) / E_c1_inv2, (data['r0'] - data['r1']) * data['m1'] + data['premium2015'] - data['premium2018'])[0, 1]
gamma612=abs(city_gender_age_premium_ratio_district15['premium2015'].mean() - city_gender_age_premium_ratio_district15['premium2018'].mean()) + abs(0.5 * (city_gender_age_premium_ratio_district15['r0'].mean() - city_gender_age_premium_ratio_district15['r1'].mean()) * (c0m0['m0'].mean() + c1m1['m1'].mean())) + 0.5 * cov_c0_inv2 + 0.5 * cov_c1_inv2
float(gamma612)
Out[4]:
990.1055666990669
In [6]:
#异质性男性 混合截面
#最优化方法——消费计算
datamale=data[data['gender'] == 1]
sigamamale = 2.6
import pandas as pd
import numpy as np
# 计算 E(c0^(-sigma)) 和 E(c1^(-sigma))
E_c0_inv2 = (datamale['c0']**(-sigamamale)).mean()
E_c1_inv2 = (datamale['c1']**(-sigamamale)).mean()
# 计算协方差
cov_c0_inv2 = np.cov(datamale['c0']**(-sigamamale) / E_c0_inv2, (datamale['r0'] - datamale['r1']) * datamale['m0'] + datamale['premium2015'] - datamale['premium2018'])[0, 1]
cov_c1_inv2 = np.cov(datamale['c1']**(-sigamamale) / E_c1_inv2, (datamale['r0'] - datamale['r1']) * datamale['m1'] + datamale['premium2015'] - datamale['premium2018'])[0, 1]
gamma622=abs(city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 1]['premium2015'].mean() - city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 1]['premium2018'].mean()) + abs(0.5 * (city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 1]['r0'].mean() - city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 1]['r1'].mean()) * (c0m0full[c0m0full['gender'] == 1]['m0'].mean() + c1m1full[c1m1full['gender'] == 1]['m1'].mean())) + 0.5 * cov_c0_inv2 + 0.5 * cov_c1_inv2
float(gamma622)
Out[6]:
902.9352554350473
In [7]:
#异质性女性 混合截面
#最优化方法——消费计算
datafemale=data[data['gender'] == 0]
sigamafemale = 3.4
import pandas as pd
import numpy as np
# 计算 E(c0^(-sigma)) 和 E(c1^(-sigma))
E_c0_inv2 = (datafemale['c0']**(-sigamafemale)).mean()
E_c1_inv2 = (datafemale['c1']**(-sigamafemale)).mean()
# 计算协方差
cov_c0_inv2 = np.cov(datafemale['c0']**(-sigamafemale) / E_c0_inv2, (datafemale['r0'] - datafemale['r1']) * datafemale['m0'] + datafemale['premium2015'] - datafemale['premium2018'])[0, 1]
cov_c1_inv2 = np.cov(datafemale['c1']**(-sigamafemale) / E_c1_inv2, (datafemale['r0'] - datafemale['r1']) * datafemale['m1'] + datafemale['premium2015'] - datafemale['premium2018'])[0, 1]
gamma632=abs(city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 0]['premium2015'].mean() - city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 0]['premium2018'].mean()) + abs(0.5 * (city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 0]['r0'].mean() - city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 0]['r1'].mean()) * (c0m0full[c0m0full['gender'] == 0]['m0'].mean() + c1m1full[c1m1full['gender'] == 0]['m1'].mean())) + 0.5 * cov_c0_inv2 + 0.5 * cov_c1_inv2
float(gamma632)
Out[7]:
1067.1098313519278
In [8]:
import numpy as np
import pandas as pd
# ========= 小工具 =========
def safe_filter(df, cond_fn):
"""对 df 应用条件;若缺列或异常则返回原 df(不筛选)"""
try:
mask = cond_fn(df)
if isinstance(mask, pd.Series) and len(mask) == len(df):
return df.loc[mask]
except Exception:
pass
return df
def safe_cov(x, y):
"""协方差(忽略 NaN/Inf,样本<2 返回0)"""
z = pd.concat([x, y], axis=1).replace([np.inf, -np.inf], np.nan).dropna()
if len(z) >= 2:
return float(np.cov(z.iloc[:, 0], z.iloc[:, 1], ddof=1)[0, 1])
return 0.0
def compute_gamma_sigma(data_sub, city_sub, m0_sub, m1_sub, sigma):
"""
可变 σ 的 consumption-based γ:
E_c0 = E[c0^(1-σ)], E_c1 = E[c1^(1-σ)]
cov0 = Cov( c0^(1-σ)/E_c0, (r0-r1)*m0 + p15 - p18 )
cov1 = Cov( c1^(1-σ)/E_c1, (r0-r1)*m1 + p15 - p18 )
γ = |Δpremium| + |0.5*Δr*(E[m0]+E[m1])| + 0.5*cov0 + 0.5*cov1
"""
# 转数值
c0 = pd.to_numeric(data_sub["c0"], errors="coerce")
c1 = pd.to_numeric(data_sub["c1"], errors="coerce")
r0 = pd.to_numeric(data_sub["r0"], errors="coerce")
r1 = pd.to_numeric(data_sub["r1"], errors="coerce")
m0 = pd.to_numeric(data_sub["m0"], errors="coerce")
m1 = pd.to_numeric(data_sub["m1"], errors="coerce")
p15 = pd.to_numeric(data_sub["premium2015"], errors="coerce")
p18 = pd.to_numeric(data_sub["premium2018"], errors="coerce")
power = -float(sigma)
Ec0 = (c0 ** power).mean()
Ec1 = (c1 ** power).mean()
cov0 = cov1 = 0.0
if pd.notna(Ec0) and Ec0 != 0:
x0 = (c0 ** power) / Ec0
y0 = (r0 - r1) * m0 + (p15 - p18)
cov0 = safe_cov(x0, y0)
if pd.notna(Ec1) and Ec1 != 0:
x1 = (c1 ** power) / Ec1
y1 = (r0 - r1) * m1 + (p15 - p18)
cov1 = safe_cov(x1, y1)
delta_premium = city_sub["premium2015"].mean() - city_sub["premium2018"].mean()
delta_r = city_sub["r0"].mean() - city_sub["r1"].mean()
avg_m = m0_sub["m0"].mean() + m1_sub["m1"].mean()
gamma = abs(delta_premium) + abs(0.5 * delta_r * avg_m) + 0.5 * cov0 + 0.5 * cov1
return float(gamma)
# ========= 条件 =========
conds = {
2: lambda d: d["gender"].eq(1), # 男
3: lambda d: d["gender"].eq(0), # 女
4: lambda d: d["marriage"].eq(1), # marriage=1
5: lambda d: d["marriage"].eq(0), # marriage=0
6: lambda d: d["kids15"].eq(1), # kids15=1
7: lambda d: d["kids15"].eq(0), # kids15=0
8: lambda d: d["age"] < 59, # age<59
9: lambda d: d["age"].between(60, 79, inclusive="both"), # 60~79
10: lambda d: d["age"] >= 80, # 80+
11: lambda d: d["district"].astype(str).str.lower().eq("east"), # east
12: lambda d: d["district"].astype(str).str.lower().eq("middle"), # middle
13: lambda d: d["district"].astype(str).str.lower().eq("west"), # west
14: lambda d: d["hsf15"] > 40, # hsf15>40
15: lambda d: d["hsf15"].between(25, 40, inclusive="both"), # 25~40
16: lambda d: d["hsf15"] < 25, # <25
17: lambda d: d["ic15"] > 35000, # ic15>35000
18: lambda d: d["ic15"].between(5000, 35000, inclusive="both"), # 5000~35000
19: lambda d: d["ic15"] < 5000, # <5000
20: lambda d: d["educationrevised"].isin([6,7,8,9,10,11]), # 教育 6-11
21: lambda d: d["educationrevised"].eq(5), # 教育 5
22: lambda d: d["educationrevised"].isin([1,2,3,4]), # 教育 1-4
}
# ========= 每个异质性的 σ(按你给的表逐一对应到上面编号) =========
sigma_map = {
2: 2.6, # 男
3: 3.4, # 女
4: 3.5, # marriage=1
5: 2.7, # marriage=0
6: 3.5, # kids15=1
7: 2.7, # kids15=0
8: 3, # <59
9: 3.4, # 60-79
10: 3.8, # 80+
11: 2.8, # east
12: 3.0, # middle
13: 3.5, # west
14: 2.7, # hsf >40(较好)
15: 3.0, # 25~40(中等)
16: 3.6, # <25(较差)
17: 2.6, # ic15>35000(高收入)
18: 3.0, # 5000~35000(中等)
19: 3.6, # <5000(低收入)
20: 2.7, # 教育较高 6-11
21: 3.0, # 教育中等 5
22: 3.5, # 教育较低 1-4
}
# ========= 批量计算:gamma522 … gamma5222 =========
_results_sigma = {}
for idx, cond_fn in conds.items():
# 对四张表同步条件筛选(缺列的表会自动跳过筛选)
data_sub = safe_filter(data, cond_fn)
city_sub = safe_filter(city_gender_age_premium_ratio_district15, cond_fn)
m0_sub = safe_filter(c0m0full, cond_fn)
m1_sub = safe_filter(c1m1full, cond_fn)
name = f"gamma6{idx}2" # 末尾 2:variable-σ consumption-based
sigma_val = sigma_map[idx]
_results_sigma[name] = compute_gamma_sigma(data_sub, city_sub, m0_sub, m1_sub, sigma=sigma_val)
# 可选:升级为同名变量
globals().update(_results_sigma)
# 打印核对
for idx in range(2, 23):
key = f"gamma6{idx}2"
print(f"{key} = {_results_sigma.get(key, np.nan)}")
gamma622 = 902.9352554350473 gamma632 = 1067.1098313519278 gamma642 = 1050.9426558608586 gamma652 = 596.7759341076646 gamma662 = 971.2950776914951 gamma672 = 492.99059878044284 gamma682 = 718.0145948778675 gamma692 = 1057.180207506433 gamma6102 = 1029.6870246503818 gamma6112 = 1160.3733928272022 gamma6122 = 1029.4207535732694 gamma6132 = 786.5319316944588 gamma6142 = 922.5255131568467 gamma6152 = 1062.9499268159977 gamma6162 = 930.1571850219226 gamma6172 = 948.1517245884293 gamma6182 = 678.3323074360065 gamma6192 = 1101.8930582384658 gamma6202 = 1177.406057002558 gamma6212 = 850.1571184651061 gamma6222 = 954.236391277999
health-based:合并数据¶
In [9]:
dataa = pd.merge(c0m0, c1m1full,on="ID", how="inner")
dataa
Out[9]:
| ID | c0 | m0 | householdID | communityID | c1 | m1 | gender | age | marriage | ... | premium2018 | r0 | r1 | r0adjust | r1adjust | policyintergration2015 | policyintergration2018 | district | GDPgrowthrate | urban_nbs | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 64033321002 | 112.216 | 60.0 | 640333210 | 640333 | 123.670 | 0.0 | 0.0 | 59.0 | 1.0 | ... | 180.0 | 0.6167 | 0.700 | 0.544192 | 0.660903 | 0.0 | 1.0 | east | 0.118005 | Rural |
| 1 | 64033327002 | 1029.200 | 6000.0 | 640333270 | 640333 | 1054.764 | 21000.0 | 0.0 | 62.0 | 1.0 | ... | 180.0 | 0.6167 | 0.700 | 0.544192 | 0.660903 | 0.0 | 1.0 | east | 0.118005 | Rural |
| 2 | 64033325001 | 1062.400 | 3000.0 | 640333250 | 640333 | 78.020 | 100.0 | 1.0 | 66.0 | 1.0 | ... | 180.0 | 0.6167 | 0.700 | 0.544192 | 0.660903 | 0.0 | 1.0 | east | 0.118005 | Rural |
| 3 | 64033322001 | 592.620 | 2000.0 | 640333220 | 640333 | 859.050 | 17050.0 | 1.0 | 63.0 | 1.0 | ... | 180.0 | 0.6167 | 0.700 | 0.544192 | 0.660903 | 0.0 | 1.0 | east | 0.118005 | Rural |
| 4 | 64033330002 | 2058.400 | 2000.0 | 640333300 | 640333 | 4025.500 | 2000.0 | 1.0 | 59.0 | 1.0 | ... | 180.0 | 0.6167 | 0.700 | 0.544192 | 0.660903 | 0.0 | 1.0 | east | 0.118005 | Rural |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 3882 | 89676104001 | 2315.700 | 840.0 | 896761040 | 896761 | 891.420 | 8000.0 | 1.0 | 61.0 | 1.0 | ... | 220.0 | 0.6500 | 0.725 | 0.624462 | 0.685108 | 0.0 | 1.0 | west | 0.284050 | Rural |
| 3883 | 89676114002 | 1935.145 | 300.0 | 896761140 | 896761 | 49.800 | 0.0 | 0.0 | 56.0 | 0.0 | ... | 220.0 | 0.6500 | 0.725 | 0.624462 | 0.685108 | 0.0 | 1.0 | west | 0.284050 | Rural |
| 3884 | 89676118001 | 2466.096 | 1000.0 | 896761180 | 896761 | 661.095 | 3000.0 | 0.0 | 73.0 | 0.0 | ... | 220.0 | 0.6500 | 0.725 | 0.624462 | 0.685108 | 0.0 | 1.0 | west | 0.284050 | Rural |
| 3885 | 89676115001 | 10721.940 | 800.0 | 896761150 | 896761 | 11638.260 | 2000.0 | 1.0 | 55.0 | 1.0 | ... | 220.0 | 0.6500 | 0.725 | 0.624462 | 0.685108 | 0.0 | 1.0 | west | 0.284050 | Rural |
| 3886 | 89676124001 | 268.422 | 500.0 | 896761240 | 896761 | 313.242 | 101.0 | 1.0 | 69.0 | 0.0 | ... | 220.0 | 0.6500 | 0.725 | 0.624462 | 0.685108 | 0.0 | 1.0 | west | 0.284050 | Rural |
3887 rows × 26 columns
In [10]:
#计算dh/dm 15
import pandas as pd
import statsmodels.api as sm
e1 = pd.merge(c0m0,hsf15,on="ID",how="inner")
e1= e1[['m0','hsf15']].copy()
# 删除包含 NaN 或 inf 的行
e1= e1.replace([np.inf, -np.inf], np.nan).dropna()
# 删除包含 0 的行
e1 = e1[(e1['hsf15']!=0) & (e1['m0']!=0)]
# 自变量(X)和因变量(Y)
X = e1['m0']
Y = e1['hsf15']
# 在 X 中添加常数项,以便进行 OLS 回归
X = sm.add_constant(X)
# 拟合 OLS 回归模型
model = sm.OLS(Y, X).fit()
# 输出回归结果
print(model.summary())
# 提取回归系数
coefficients = model.params
# 保存特定自变量的回归系数
h_m15 = coefficients['m0']
h_m15
OLS Regression Results
==============================================================================
Dep. Variable: hsf15 R-squared: 0.000
Model: OLS Adj. R-squared: 0.000
Method: Least Squares F-statistic: 1.297
Date: Mon, 29 Dec 2025 Prob (F-statistic): 0.255
Time: 17:43:16 Log-Likelihood: -11963.
No. Observations: 3113 AIC: 2.393e+04
Df Residuals: 3111 BIC: 2.394e+04
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 33.6007 0.216 155.587 0.000 33.177 34.024
m0 -1.706e-05 1.5e-05 -1.139 0.255 -4.64e-05 1.23e-05
==============================================================================
Omnibus: 41.096 Durbin-Watson: 1.849
Prob(Omnibus): 0.000 Jarque-Bera (JB): 32.348
Skew: -0.167 Prob(JB): 9.46e-08
Kurtosis: 2.629 Cond. No. 1.54e+04
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.54e+04. This might indicate that there are
strong multicollinearity or other numerical problems.
Out[10]:
np.float64(-1.7062284276591698e-05)
In [12]:
#计算dh/dm 18
import pandas as pd
import statsmodels.api as sm
f1 = pd.merge(c1m1,hsf18,on="ID",how="inner")
f1= f1[['m1','hsf18']].copy()
# 删除包含 NaN 或 inf 的行
f1= f1.replace([np.inf, -np.inf], np.nan).dropna()
# 删除包含 0 的行
f1 = f1[(f1['hsf18']!=0) & (f1['m1']!=0)]
# 自变量(X)和因变量(Y)
X = f1['m1']
Y = f1['hsf18']
# 在 X 中添加常数项,以便进行 OLS 回归
X = sm.add_constant(X)
# 拟合 OLS 回归模型
model = sm.OLS(Y, X).fit()
# 输出回归结果
print(model.summary())
# 提取回归系数
coefficients = model.params
# 保存特定自变量的回归系数
h_m18 = coefficients['m1']
h_m18
OLS Regression Results
==============================================================================
Dep. Variable: hsf18 R-squared: 0.000
Model: OLS Adj. R-squared: 0.000
Method: Least Squares F-statistic: 1.579
Date: Mon, 29 Dec 2025 Prob (F-statistic): 0.209
Time: 17:43:42 Log-Likelihood: -26371.
No. Observations: 5630 AIC: 5.275e+04
Df Residuals: 5628 BIC: 5.276e+04
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 51.5258 0.359 143.352 0.000 50.821 52.230
m1 -1.359e-05 1.08e-05 -1.257 0.209 -3.48e-05 7.61e-06
==============================================================================
Omnibus: 14923.644 Durbin-Watson: 1.748
Prob(Omnibus): 0.000 Jarque-Bera (JB): 441.401
Skew: -0.235 Prob(JB): 1.42e-96
Kurtosis: 1.711 Cond. No. 3.42e+04
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 3.42e+04. This might indicate that there are
strong multicollinearity or other numerical problems.
Out[12]:
np.float64(-1.3590936773055398e-05)
In [13]:
#最优化方法——健康计算
import pandas as pd
import numpy as np
# 计算 E(c0^(-sigma)) 和 E(c1^(-sigma))
E_c0_inv2 = (dataa['c0']**(-3)).mean()
E_c1_inv2 = (dataa['c1']**(-3)).mean()
# 计算协方差
cov_c0_inv2 = np.cov((0.019743 * h_m15)/ (E_c0_inv2 * dataa['r0']), (dataa['r0'] - dataa['r1']) * dataa['m0'] + dataa['premium2015'] - dataa['premium2018'])[0, 1]
cov_c1_inv2 = np.cov((0.019743 * h_m18)/ (E_c1_inv2 * dataa['r1']), (dataa['r0'] - dataa['r1']) * dataa['m1'] + dataa['premium2015'] - dataa['premium2018'])[0, 1]
gamma613=abs(city_gender_age_premium_ratio_district15['premium2015'].mean() - city_gender_age_premium_ratio_district15['premium2018'].mean()) + abs(0.5 * (city_gender_age_premium_ratio_district15['r0'].mean() - city_gender_age_premium_ratio_district15['r1'].mean()) * (c0m0['m0'].mean() + c1m1['m1'].mean())) + 0.5 * cov_c0_inv2 + 0.5 * cov_c1_inv2
float(gamma613)
Out[13]:
785.5178011684857
In [14]:
#表五健康based异质性—男性
dataamale=dataa[dataa['gender'] == 1]
sigamamale = 2.6
import pandas as pd
import numpy as np
# 计算 E(c0^(-sigma)) 和 E(c1^(-sigma))
E_c0_inv2 = (dataamale['c0']**(-sigamamale)).mean()
E_c1_inv2 = (dataamale['c1']**(-sigamamale)).mean()
# 计算协方差
cov_c0_inv2 = np.cov((0.019743 * h_m15)/ (E_c0_inv2 * dataamale['r0']), (dataamale['r0'] - dataamale['r1']) * dataamale['m0'] + dataamale['premium2015'] - dataamale['premium2018'])[0, 1]
cov_c1_inv2 = np.cov((0.019743 * h_m18)/ (E_c1_inv2 * dataamale['r1']), (dataamale['r0'] - dataamale['r1']) * dataamale['m1'] + dataamale['premium2015'] - dataamale['premium2018'])[0, 1]
gamma623=abs(city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 1]['premium2015'].mean() - city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 1]['premium2018'].mean()) + abs(0.5 * (city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 1]['r0'].mean() - city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 1]['r1'].mean()) * (c0m0full[c0m0full['gender'] == 1]['m0'].mean() + c1m1full[c1m1full['gender'] == 1]['m1'].mean())) + 0.5 * cov_c0_inv2 + 0.5 * cov_c1_inv2
float(gamma623)
Out[14]:
776.5922244975103
In [15]:
#表五健康based异质性—女性
dataafemale=dataa[dataa['gender'] == 0]
sigamafemale = 3.4
import pandas as pd
import numpy as np
# 计算 E(c0^(-sigma)) 和 E(c1^(-sigma))
E_c0_inv2 = (dataafemale['c0']**(-sigamafemale)).mean()
E_c1_inv2 = (dataafemale['c1']**(-sigamafemale)).mean()
# 计算协方差
cov_c0_inv2 = np.cov((0.019743 * h_m15)/ (E_c0_inv2 * dataafemale['r0']), (dataafemale['r0'] - dataafemale['r1']) * dataafemale['m0'] + dataafemale['premium2015'] - dataafemale['premium2018'])[0, 1]
cov_c1_inv2 = np.cov((0.019743 * h_m18)/ (E_c1_inv2 * dataafemale['r1']), (dataafemale['r0'] - dataafemale['r1']) * dataafemale['m1'] + dataafemale['premium2015'] - dataafemale['premium2018'])[0, 1]
gamma633=abs(city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 0]['premium2015'].mean() - city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 0]['premium2018'].mean()) + abs(0.5 * (city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 0]['r0'].mean() - city_gender_age_premium_ratio_district15[city_gender_age_premium_ratio_district15['gender'] == 0]['r1'].mean()) * (c0m0full[c0m0full['gender'] == 0]['m0'].mean() + c1m1full[c1m1full['gender'] == 0]['m1'].mean())) + 0.5 * cov_c0_inv2 + 0.5 * cov_c1_inv2
float(gamma633)
Out[15]:
869.2566681696519
In [17]:
import numpy as np
import pandas as pd
# ===== 常量 =====
phi_tilde = 0.019743 # 俺的 Φ~
# ===== 工具函数 =====
def safe_filter(df, cond_fn):
"""对 df 应用条件;若缺列/异常则返回原 df(不筛选)"""
try:
mask = cond_fn(df)
if isinstance(mask, pd.Series) and len(mask) == len(df):
return df.loc[mask]
except Exception:
pass
return df
def safe_cov(x, y):
"""样本协方差(忽略 NaN/Inf;样本<2 返回 0)"""
z = pd.concat([x, y], axis=1).replace([np.inf, -np.inf], np.nan).dropna()
if len(z) >= 2:
return float(np.cov(z.iloc[:, 0], z.iloc[:, 1], ddof=1)[0, 1])
return 0.0
def _align_health_for_subset(dataa_full, data_sub, h_full, id_col="ID"):
"""
将全样本 h_m15/h_m18 与 data_sub 对齐:
- 若 h_full 是 Series 且索引=dataa_full.index,则按 index 对齐
- 若 h_full 的索引是 ID,则按 ID 对齐
- 若是 array/list,则先包成 Series(index=dataa_full.index) 再对齐
"""
if isinstance(h_full, pd.Series):
if h_full.index.equals(dataa_full.index):
return h_full.loc[data_sub.index]
if id_col in data_sub.columns and h_full.index.isin(data_sub[id_col]).any():
s = h_full.reindex(data_sub[id_col])
s.index = data_sub.index
return s
try:
return h_full.loc[data_sub.index]
except Exception:
return pd.Series(np.nan, index=data_sub.index)
# array-like
try:
base = pd.Series(h_full, index=dataa_full.index)
return base.loc[data_sub.index]
except Exception:
return pd.Series(np.nan, index=data_sub.index)
def compute_gamma_health_sigma(dataa_full, data_sub, city_sub, m0_sub, m1_sub, sigma, h_m15, h_m18):
"""
可变 σ 的 health-based γ:
Ec0 = E[c0^(1-σ)], Ec1 = E[c1^(1-σ)]
cov0 = Cov( (φ*h_m15)/(Ec0 * r0), (r0-r1)*m0 + p15 - p18 )
cov1 = Cov( (φ*h_m18)/(Ec1 * r1), (r0-r1)*m1 + p15 - p18 )
γ = |Δpremium| + |0.5*Δr*(E[m0]+E[m1])| + 0.5*(cov0+cov1)
"""
# 数值列
c0 = pd.to_numeric(data_sub["c0"], errors="coerce")
c1 = pd.to_numeric(data_sub["c1"], errors="coerce")
r0 = pd.to_numeric(data_sub["r0"], errors="coerce")
r1 = pd.to_numeric(data_sub["r1"], errors="coerce")
m0 = pd.to_numeric(data_sub["m0"], errors="coerce")
m1 = pd.to_numeric(data_sub["m1"], errors="coerce")
p15 = pd.to_numeric(data_sub["premium2015"], errors="coerce")
p18 = pd.to_numeric(data_sub["premium2018"], errors="coerce")
# 子样本对应的 h_m15 / h_m18
h15 = _align_health_for_subset(dataa_full, data_sub, h_m15)
h18 = _align_health_for_subset(dataa_full, data_sub, h_m18)
power = - float(sigma)
Ec0 = (c0 ** power).mean()
Ec1 = (c1 ** power).mean()
cov0 = cov1 = 0.0
if pd.notna(Ec0) and Ec0 != 0:
a0 = (phi_tilde * h15) / (Ec0 * r0)
y0 = (r0 - r1) * m0 + (p15 - p18)
cov0 = safe_cov(a0, y0)
if pd.notna(Ec1) and Ec1 != 0:
a1 = (phi_tilde * h18) / (Ec1 * r1)
y1 = (r0 - r1) * m1 + (p15 - p18)
cov1 = safe_cov(a1, y1)
delta_premium = city_sub["premium2015"].mean() - city_sub["premium2018"].mean()
delta_r = city_sub["r0"].mean() - city_sub["r1"].mean()
avg_m = m0_sub["m0"].mean() + m1_sub["m1"].mean()
gamma = abs(delta_premium) + abs(0.5 * delta_r * avg_m) + 0.5 * cov0 + 0.5 * cov1
return float(gamma)
# ===== 异质性条件(2~22)=====
conds = {
2: lambda d: d["gender"].eq(1), # 男
3: lambda d: d["gender"].eq(0), # 女
4: lambda d: d["marriage"].eq(1), # marriage=1
5: lambda d: d["marriage"].eq(0), # marriage=0
6: lambda d: d["kids15"].eq(1), # kids15=1
7: lambda d: d["kids15"].eq(0), # kids15=0
8: lambda d: d["age"] < 59, # age<59
9: lambda d: d["age"].between(60, 79, inclusive="both"), # 60~79
10: lambda d: d["age"] >= 80, # 80+
11: lambda d: d["district"].astype(str).str.lower().eq("east"), # east
12: lambda d: d["district"].astype(str).str.lower().eq("middle"), # middle
13: lambda d: d["district"].astype(str).str.lower().eq("west"), # west
14: lambda d: d["hsf15"] > 40, # hsf15>40(较好)
15: lambda d: d["hsf15"].between(25, 40, inclusive="both"), # 25~40(中等)
16: lambda d: d["hsf15"] < 25, # hsf15<25(较差)
17: lambda d: d["ic15"] > 35000, # 高收入
18: lambda d: d["ic15"].between(5000, 35000, inclusive="both"), # 中等收入
19: lambda d: d["ic15"] < 5000, # 低收入
20: lambda d: d["educationrevised"].isin([6,7,8,9,10,11]), # 教育较高
21: lambda d: d["educationrevised"].eq(5), # 教育中等
22: lambda d: d["educationrevised"].isin([1,2,3,4]), # 教育较低
}
# ===== 每个异质性的 σ(按上面编号对应)=====
sigma_map = {
2: 2.6, # 男
3: 3.4, # 女
4: 3.5, # marriage=1
5: 2.7, # marriage=0
6: 3.5, # kids15=1
7: 2.7, # kids15=0
8: 3.0, # age<59
9: 3.4, # 60~79
10: 3.8, # 80+
11: 2.8, # east
12: 3.0, # middle
13: 3.5, # west
14: 2.7, # hsf>40(较好)
15: 3.0, # 25~40(中等)
16: 3.6, # hsf<25(较差)
17: 2.6, # ic15>35000(高)
18: 3.0, # 5000~35000(中)
19: 3.6, # ic15<5000(低)
20: 2.7, # 教育 6-11(高)
21: 3.0, # 教育 5(中)
22: 3.5, # 教育 1-4(低)
}
# ===== 批量计算:gamma523 … gamma5223 =====
_results_hsigma = {}
for idx, cond_fn in conds.items():
# 四张表用相同条件尽量筛选(某表缺列会自动跳过筛选)
data_sub = safe_filter(dataa, cond_fn) # 注意:此处按你的示例用 dataa
city_sub = safe_filter(city_gender_age_premium_ratio_district15, cond_fn)
m0_sub = safe_filter(c0m0full, cond_fn)
m1_sub = safe_filter(c1m1full, cond_fn)
sigma_val = sigma_map[idx]
name = f"gamma6{idx}3" # 末尾 3:health-based, variable-σ(表五)
_results_hsigma[name] = compute_gamma_health_sigma(
dataa_full=dataa, data_sub=data_sub, city_sub=city_sub,
m0_sub=m0_sub, m1_sub=m1_sub,
sigma=sigma_val, h_m15=h_m15, h_m18=h_m18
)
# 可选:注册为同名变量
globals().update(_results_hsigma)
# 查看结果
for idx in range(2, 23):
key = f"gamma6{idx}3"
print(f"{key} = {_results_hsigma.get(key, np.nan)}")
gamma623 = 776.5922244975103 gamma633 = 869.2566681696519 gamma643 = 1049.678067564448 gamma653 = 538.1049259183139 gamma663 = 946.4030858557934 gamma673 = 411.78051735029624 gamma683 = 750.5854229039102 gamma693 = 879.3586982958574 gamma6103 = 1486.1325505333025 gamma6113 = 722.467543112902 gamma6123 = 798.5608830865662 gamma6133 = 866.4365313067555 gamma6143 = 689.710125804213 gamma6153 = 883.6557425223073 gamma6163 = 1010.2931552555069 gamma6173 = 704.0986785348732 gamma6183 = 649.4122164122365 gamma6193 = 1106.586027238685 gamma6203 = 762.3787116927722 gamma6213 = 917.4985634120095 gamma6223 = 888.0143974958814
用完全信息法求解¶
In [18]:
import numpy as np
import pandas as pd
# 参数
sigma = 3.0
phi_tilde = 0.019743
# 取各列的均值(忽略缺失)
c0_bar = pd.to_numeric(c0m0["c0"], errors="coerce").mean(skipna=True)
c1_bar = pd.to_numeric(c1m1["c1"], errors="coerce").mean(skipna=True)
h0_bar = pd.to_numeric(hsf15["hsf15"], errors="coerce").mean(skipna=True)
h1_bar = pd.to_numeric(hsf18["hsf18"], errors="coerce").mean(skipna=True)
B_bar = (c0_bar**(1 - sigma)) + (1 - sigma) * phi_tilde * (h0_bar - h1_bar)
cons1_bar = B_bar**(1 / (1 - sigma))
gamma611 = c1_bar - cons1_bar
print(gamma611)
1957.6372848184362
In [19]:
#异质性计算男性
import numpy as np
import pandas as pd
# 参数
sigmamale = 2.6
phi_tilde = 0.019743
# 取各列的均值(忽略缺失)
c0_bar = pd.to_numeric(c0m0full[c0m0full['gender'] == 1]["c0"], errors="coerce").mean(skipna=True)
c1_bar = pd.to_numeric(c1m1full[c1m1full['gender'] == 1]["c1"], errors="coerce").mean(skipna=True)
h0_bar = pd.to_numeric(hsf15full[hsf15full['gender'] == 1]["hsf15"], errors="coerce").mean(skipna=True)
h1_bar = pd.to_numeric(hsf18full[hsf18full['gender'] == 1]["hsf18"], errors="coerce").mean(skipna=True)
B_bar = (c0_bar**(1 - sigmamale)) + (1 - sigmamale) * phi_tilde * (h0_bar - h1_bar)
cons1_bar = B_bar**(1 / (1 - sigmamale))
gamma621 = c1_bar - cons1_bar
print(gamma621)
1947.6318667646037
In [20]:
#异质性计算女性
import numpy as np
import pandas as pd
# 参数
sigmafemale = 3.4
phi_tilde = 0.019743
# 取各列的均值(忽略缺失)
c0_bar = pd.to_numeric(c0m0full[c0m0full['gender'] == 0]["c0"], errors="coerce").mean(skipna=True)
c1_bar = pd.to_numeric(c1m1full[c1m1full['gender'] == 0]["c1"], errors="coerce").mean(skipna=True)
h0_bar = pd.to_numeric(hsf15full[hsf15full['gender'] == 0]["hsf15"], errors="coerce").mean(skipna=True)
h1_bar = pd.to_numeric(hsf18full[hsf18full['gender'] == 0]["hsf18"], errors="coerce").mean(skipna=True)
B_bar = (c0_bar**(1 - sigmafemale)) + (1 - sigmafemale) * phi_tilde * (h0_bar - h1_bar)
cons1_bar = B_bar**(1 / (1 - sigmafemale))
gamma631 = c1_bar - cons1_bar
print(gamma631)
1967.4996646535765
In [21]:
import numpy as np
import pandas as pd
# ========= 参数 =========
phi_tilde = 0.019743
# ========= 条件 =========
conds = {
2: lambda d: d["gender"].eq(1), # 男
3: lambda d: d["gender"].eq(0), # 女
4: lambda d: d["marriage"].eq(1), # marriage=1
5: lambda d: d["marriage"].eq(0), # marriage=0
6: lambda d: d["kids15"].eq(1), # kids15=1
7: lambda d: d["kids15"].eq(0), # kids15=0
8: lambda d: d["age"] < 59, # age<59
9: lambda d: d["age"].between(60, 79, inclusive="both"), # 60~79
10: lambda d: d["age"] >= 80, # 80+
11: lambda d: d["district"].astype(str).str.lower().eq("east"), # east
12: lambda d: d["district"].astype(str).str.lower().eq("middle"), # middle
13: lambda d: d["district"].astype(str).str.lower().eq("west"), # west
14: lambda d: d["hsf15"] > 40, # hsf15>40(较好)
15: lambda d: d["hsf15"].between(25, 40, inclusive="both"), # 25~40(中等)
16: lambda d: d["hsf15"] < 25, # hsf15<25(较差)
17: lambda d: d["ic15"] > 35000, # 高收入
18: lambda d: d["ic15"].between(5000, 35000, inclusive="both"), # 中等收入
19: lambda d: d["ic15"] < 5000, # 低收入
20: lambda d: d["educationrevised"].isin([6,7,8,9,10,11]), # 教育较高
21: lambda d: d["educationrevised"].eq(5), # 教育中等
22: lambda d: d["educationrevised"].isin([1,2,3,4]), # 教育较低
}
# ========= 每个异质性的 σ =========
sigma_map = {
2: 2.6, # 男
3: 3.4, # 女
4: 3.5, # marriage=1
5: 2.7, # marriage=0
6: 3.5, # kids15=1
7: 2.7, # kids15=0
8: 3.0, # <59
9: 3.4, # 60~79
10: 3.8, # 80+
11: 2.8, # east
12: 3.0, # middle
13: 3.5, # west
14: 2.7, # hsf>40(较好)
15: 3.0, # 25~40(中等)
16: 3.6, # hsf<25(较差)
17: 2.6, # ic15>35000(高)
18: 3.0, # 5000~35000(中)
19: 3.6, # ic15<5000(低)
20: 2.7, # 教育 6-11(高)
21: 3.0, # 教育 5(中)
22: 3.5, # 教育 1-4(低)
}
# ========= 工具函数 =========
def safe_filter(df: pd.DataFrame, cond_fn):
"""对 df 应用 cond_fn;若 df 缺少所需列或条件异常,则返回原 df(不筛选)"""
try:
m = cond_fn(df)
if isinstance(m, pd.Series) and len(m) == len(df):
return df.loc[m]
except Exception:
pass
return df
def get_mean_after_filter(df: pd.DataFrame, value_col: str, cond_fn):
"""在 df 上按 cond_fn 过滤后,计算 value_col 的均值(忽略缺失);列不存在则返回 NaN。"""
if value_col not in df.columns:
return np.nan
sub = safe_filter(df, cond_fn)
return pd.to_numeric(sub[value_col], errors="coerce").mean(skipna=True)
def gamma_means_health_variable_sigma(cond_fn, sigma):
"""
均值法 + 可变 σ 的 health 口径:
B_bar = c0_bar^(1-σ) + (1-σ)*φ~*(h0_bar - h1_bar)
cons1_bar = B_bar^(1/(1-σ))
γ = c1_bar - cons1_bar
"""
c0_bar = get_mean_after_filter(c0m0full, "c0", cond_fn)
c1_bar = get_mean_after_filter(c1m1full, "c1", cond_fn)
h0_bar = get_mean_after_filter(hsf15full,"hsf15", cond_fn)
h1_bar = get_mean_after_filter(hsf18full,"hsf18", cond_fn)
# 任一均值缺失则返回 NaN
if any(pd.isna([c0_bar, c1_bar, h0_bar, h1_bar])):
return float("nan")
power = 1.0 - float(sigma)
# 基数必须为正数以避免无效幂运算
if c0_bar <= 0:
return float("nan")
B_bar = (c0_bar ** power) + power * phi_tilde * (h0_bar - h1_bar)
# B_bar 必须为正
if not (pd.notna(B_bar) and B_bar > 0):
return float("nan")
cons1_bar = B_bar ** (1.0 / power)
gamma_val = c1_bar - cons1_bar
return float(gamma_val)
# ========= 批量计算:gamma521 … gamma5221 =========
_results = {}
for idx, cond_fn in conds.items():
name = f"gamma6{idx}1" # 末尾 1 表示 means-based(这一套方法)
_results[name] = gamma_means_health_variable_sigma(cond_fn, sigma_map[idx])
# 可选:注册为同名全局变量
globals().update(_results)
# 打印核对
for idx in range(2, 23):
key = f"gamma6{idx}1"
print(f"{key} = {_results.get(key, np.nan)}")
gamma621 = 1947.6318667646037 gamma631 = 1967.4996646535765 gamma641 = 2003.907238499924 gamma651 = 1598.153811347043 gamma661 = 1936.7420051917632 gamma671 = 858.3458943928096 gamma681 = 2471.089904631486 gamma691 = 1453.909956502523 gamma6101 = 1443.1797426164674 gamma6111 = 2301.306714874565 gamma6121 = 2007.2892570366184 gamma6131 = 1618.6196541981144 gamma6141 = 2357.731717374896 gamma6151 = 1880.577649456202 gamma6161 = 1625.372828161619 gamma6171 = 2582.5649757671076 gamma6181 = 2070.0142885375976 gamma6191 = 1855.9965630067936 gamma6201 = 2768.3301722122346 gamma6211 = 2298.024387545422 gamma6221 = 1737.3035332483175
In [22]:
# -*- coding: utf-8 -*-
import pandas as pd
# 1) 行索引与数据
rows = [
"全样本",
"男性","女性",
"有配偶","无配偶",
"有子女","无子女",
"小于59 岁","60 岁—79 岁","80 岁及以上",
"东部","中部","西部",
"健康状况较好","健康状况中等","健康状况较差",
"较高收入","中等收入","较低收入",
"教育程度较高","教育程度中等","教育程度较低",
]
data = [
[gamma611, gamma612, gamma613],
[gamma621, gamma622, gamma623],
[gamma631, gamma632, gamma633],
[gamma641, gamma642, gamma643],
[gamma651, gamma652, gamma653],
[gamma661, gamma662, gamma663],
[gamma671, gamma672, gamma673],
[gamma681, gamma682, gamma683],
[gamma691, gamma692, gamma693],
[gamma6101, gamma6102, gamma6103],
[gamma6111, gamma6112, gamma6113],
[gamma6121, gamma6122, gamma6123],
[gamma6131, gamma6132, gamma6133],
[gamma6141, gamma6142, gamma6143],
[gamma6151, gamma6152, gamma6153],
[gamma6161, gamma6162, gamma6163],
[gamma6171, gamma6172, gamma6173],
[gamma6181, gamma6182, gamma6183],
[gamma6191, gamma6192, gamma6193],
[gamma6201, gamma6202, gamma6203],
[gamma6211, gamma6212, gamma6213],
[gamma6221, gamma6222, gamma6223],
]
# 2) 多级列索引
cols = pd.MultiIndex.from_tuples([
("完全信息方法",""),
("最优化方法","仅假设效用函数\n的消费部分"),
("最优化方法","仅假设效用函数\n的健康部分"),
])
df = pd.DataFrame(data, index=rows, columns=cols)
# 3) 分组起始行(加粗横线)
group_starts = {
"男性", # 性别组
"有配偶", # 婚姻组
"有子女", # 子女组
"45 岁—59 岁", # 年龄组
"东部", # 地区组
"健康状况较好", # 健康组
"较高收入", # 收入组
"教育程度较高" # 教育组
}
def row_borders(row):
label = row.name
if label in group_starts:
return ['border-top: 2px solid #4a4a4a'] * len(row)
return [''] * len(row)
# 4) 样式与展示
styler = (
df.style
.set_table_styles([
{'selector': 'th.col_heading.level0',
'props': [('font-weight', '700'),
('border-bottom','1px solid #4a4a4a')]},
{'selector': 'th.col_heading.level1',
'props': [('font-weight', '700')]},
{'selector': 'th.row_heading',
'props': [('font-weight', '700')]},
{'selector': 'table',
'props': [('border-collapse','collapse'),
('font-family','-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,PingFang SC,Helvetica,Arial')]}
])
.format(precision=0)
.set_properties(**{
'text-align': 'center',
'padding': '6px',
'border':'1px solid #a0a0a0'
})
.apply(row_borders, axis=1)
)
# 在 Jupyter 中显示
styler
# (可选)导出为 HTML 文件
# with open("表格_完全信息与最优化方法.html", "w", encoding="utf-8") as f:
# f.write(styler.to_html())
Out[22]:
| 完全信息方法 | 最优化方法 | ||
|---|---|---|---|
| 仅假设效用函数 的消费部分 | 仅假设效用函数 的健康部分 | ||
| 全样本 | 1958 | 990 | 786 |
| 男性 | 1948 | 903 | 777 |
| 女性 | 1967 | 1067 | 869 |
| 有配偶 | 2004 | 1051 | 1050 |
| 无配偶 | 1598 | 597 | 538 |
| 有子女 | 1937 | 971 | 946 |
| 无子女 | 858 | 493 | 412 |
| 小于59 岁 | 2471 | 718 | 751 |
| 60 岁—79 岁 | 1454 | 1057 | 879 |
| 80 岁及以上 | 1443 | 1030 | 1486 |
| 东部 | 2301 | 1160 | 722 |
| 中部 | 2007 | 1029 | 799 |
| 西部 | 1619 | 787 | 866 |
| 健康状况较好 | 2358 | 923 | 690 |
| 健康状况中等 | 1881 | 1063 | 884 |
| 健康状况较差 | 1625 | 930 | 1010 |
| 较高收入 | 2583 | 948 | 704 |
| 中等收入 | 2070 | 678 | 649 |
| 较低收入 | 1856 | 1102 | 1107 |
| 教育程度较高 | 2768 | 1177 | 762 |
| 教育程度中等 | 2298 | 850 | 917 |
| 教育程度较低 | 1737 | 954 | 888 |