导入数据¶

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