in_sample_months = 48
df_2009, _ = tbtf.split_in_out_sample(crsp, '2009-12-31', in_sample_months)
df_2023, _ = tbtf.split_in_out_sample(crsp, '2023-12-31', in_sample_months)
def plot_median_fit(df_in_sample, n=10, state=10, ax=None):
all_obs = []
for date, group in df_in_sample[df_in_sample['state'] == state].groupby('date'):
g = group.sort_values('mktcap_lag', ascending=False).head(n).copy()
if len(g) < n: continue
g = g.sort_values('mktcap_lag')
g['rank'] = np.arange(1, n + 1)
g['capshare'] = g['mktcap_lag'] / g['mktcap_lag'].sum()
all_obs.append(g[['rank', 'capshare']])
df_all = pd.concat(all_obs, ignore_index=True)
df_median = df_all.groupby('rank')['capshare'].median().reset_index()
if ax is None:
fig, ax = plt.subplots(figsize=(8, 5))
ax.scatter(df_all['rank'], df_all['capshare'], alpha=0.4, label='Observed', color='gray')
ax.step(df_median['rank'], df_median['capshare'], where='mid', linewidth=2.5, color='blue', label='Median Capshare')
ax.set_xlabel("Rank (1 = Smallest, 10 = Largest)")
ax.set_ylabel("Capital Share")
ax.set_xticks(np.arange(1, n + 1))
ax.legend()
ax.grid(True)
return ax
def fit_and_plot_zipf(df_in_sample, n=10, m=3, state=10, ax=None, color='teal'):
all_obs = []
for date, group in df_in_sample[df_in_sample['state'] == state].groupby('date'):
g = group.sort_values('mktcap_lag', ascending=False).head(n).copy()
if len(g) < n: continue
g = g.sort_values('mktcap_lag')
g['rank'] = np.arange(1, n + 1)
g['capshare'] = g['mktcap_lag'] / g['mktcap_lag'].sum()
all_obs.append(g[['rank', 'capshare']])
df_all = pd.concat(all_obs, ignore_index=True)
median_shares = df_all.groupby('rank')['capshare'].median()
s = (median_shares / median_shares.sum()).sort_index(ascending=False).values
C_m = s[:m].sum()
def obj(alpha):
h_m = np.sum(np.arange(1, m + 1) ** (-alpha))
h_n = np.sum(np.arange(1, n + 1) ** (-alpha))
return (h_m / h_n) - C_m
res = root_scalar(obj, bracket=[0.001, 5.0], method='brentq')
alpha_hat = res.root
ranks = np.arange(1, n + 1)
k = n - ranks + 1
w_zipf = (k ** (-alpha_hat)) / np.sum(k ** (-alpha_hat))
if ax is None:
fig, ax = plt.subplots(figsize=(8, 5))
ax.scatter(df_all['rank'], df_all['capshare'], alpha=0.4, label='Observed', color='gray')
ax.step(ranks, w_zipf, where='mid', linewidth=2.5, color=color, label=f'Zipf Fit ($\\hat{{\\alpha}}={alpha_hat:.3f}, C_{m}={C_m:.3f}$)')
ax.scatter(ranks, w_zipf, color=color, s=35, zorder=3)
ax.set_xlabel("Rank (1 = Smallest, 10 = Largest)")
ax.set_ylabel("Capital Weight")
ax.set_xticks(ranks)
ax.grid(True, linestyle='--', alpha=0.6)
ax.legend()
return ax, alpha_hat, C_m
fig, axes = plt.subplots(4, 2, figsize=(14, 20))
# 1. Parametric: Exponential Fit
tbtf.plot_exponential_fit(df_2009, n=10, state=10, ax=axes[0, 0])
axes[0, 0].set_title("Pre-2010: Exponential Fit (Snapshot 2009-12-31)")
tbtf.plot_exponential_fit(df_2023, n=10, state=10, ax=axes[0, 1])
axes[0, 1].set_title("Post-2010: Exponential Fit (Snapshot 2023-12-31)")
# 2. Nonparametric: Median-Based Fit
plot_median_fit(df_2009, n=10, state=10, ax=axes[1, 0])
axes[1, 0].set_title("Pre-2010: Median-Based Capshare (Snapshot 2009-12-31)")
plot_median_fit(df_2023, n=10, state=10, ax=axes[1, 1])
axes[1, 1].set_title("Post-2010: Median-Based Capshare (Snapshot 2023-12-31)")
# 3. Semi-Parametric: Zipf Fit (m = 1)
_, a_pre_m1, _ = fit_and_plot_zipf(df_2009, n=10, m=1, state=10, ax=axes[2, 0], color='seagreen')
axes[2, 0].set_title(f"Pre-2010: Zipf Fit with $m=1$ ($\\hat{{\\alpha}}={a_pre_m1:.3f}$)")
_, a_post_m1, _ = fit_and_plot_zipf(df_2023, n=10, m=1, state=10, ax=axes[2, 1], color='seagreen')
axes[2, 1].set_title(f"Post-2010: Zipf Fit with $m=1$ ($\\hat{{\\alpha}}={a_post_m1:.3f}$)")
# 4. Semi-Parametric: Zipf Fit (m = 3)
_, a_pre_m3, _ = fit_and_plot_zipf(df_2009, n=10, m=3, state=10, ax=axes[3, 0], color='darkcyan')
axes[3, 0].set_title(f"Pre-2010: Zipf Fit with $m=3$ ($\\hat{{\\alpha}}={a_pre_m3:.3f}$)")
_, a_post_m3, _ = fit_and_plot_zipf(df_2023, n=10, m=3, state=10, ax=axes[3, 1], color='darkcyan')
axes[3, 1].set_title(f"Post-2010: Zipf Fit with $m=3$ ($\\hat{{\\alpha}}={a_post_m3:.3f}$)")
plt.tight_layout()
plt.show()