Skip to content

frac_nodemog module

FRAC estimation on macro-BLP, without demographics

frac_nodemog_estimate(frac_data, degree_Z=2, degree_X1=2)

Estimate FRAC parameters without demographics using two-stage least squares.

Parameters:

Name Type Description Default
frac_data FracNoDemogData

Data container with regressors, instruments, and simulated or empirical shares.

required
degree_Z int

Degree of polynomial expansion for instruments. Default is 2.

2
degree_X1 int

Degree of polynomial expansion for exogenous regressors in X1. Default is 2.

2

Returns:

Name Type Description
TwoArrays TwoArrays

Tuple (betas_est, sigmas_est) with fixed and random coefficient

TwoArrays

estimates, respectively.

Source code in frac_blp/frac_nodemog.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
def frac_nodemog_estimate(
    frac_data: FracNoDemogData,
    degree_Z: int = 2,
    degree_X1: int = 2,
) -> TwoArrays:
    """
    Estimate FRAC parameters without demographics using two-stage least squares.

    Args:
        frac_data (FracNoDemogData): Data container with regressors, instruments, and
            simulated or empirical shares.
        degree_Z (int): Degree of polynomial expansion for instruments. Default is 2.
        degree_X1 (int): Degree of polynomial expansion for exogenous regressors in X1.
            Default is 2.

    Returns:
        TwoArrays: Tuple ``(betas_est, sigmas_est)`` with fixed and random coefficient
        estimates, respectively.
    """
    X1_exo = frac_data.X1_exo
    X1, X2 = frac_data.X1.astype(np.float64), frac_data.X2.astype(np.float64)
    J = frac_data.J
    Z = frac_data.Z
    names_X1 = frac_data.names_X1
    names_X2 = frac_data.names_X2
    shares = frac_data.shares
    K, y = make_K_and_y(X2, shares, J)
    K = K.astype(np.float64)
    y = y.astype(np.float64)
    n_X1 = X1.shape[1]
    n_X2 = X2.shape[1]

    # combine exogenous regressors and instruments
    Z_full = make_Z_full(Z, X1_exo, degree_Z=degree_Z, degree_X1=degree_X1).astype(
        np.float64
    )

    # project on the full set of instruments
    y_hat, _, r2_y = proj_Z_full(y.reshape((frac_data.n_obs, 1)), Z_full)
    K_hat, _, r2_K = proj_Z_full(K, Z_full)
    X1_hat, _, r2_X1 = proj_Z_full(X1, Z_full)

    # breakpoint()
    print_stars(
        f"The first stage R2s of projecting on the full set of {Z_full.shape[1]} instruments are:"
    )
    print(f"    for y: {r2_y[0]:.3f}")
    for ix in range(n_X1):
        print(f"     for {names_X1[ix]}: {r2_X1[ix]:.3f}")
    for ix in range(n_X2):
        print(f"     for K_{names_X2[ix]}: {r2_K[ix]:.3f}")
    print("\n")

    # run the second stage
    RHS_proj = np.column_stack((X1_hat, K_hat))
    betas_sigmas_est = spla.lstsq(RHS_proj, y_hat[:, 0])[0]
    betas_est = betas_sigmas_est[:n_X1]
    sigmas_squared_est = betas_sigmas_est[n_X1:]
    if np.min(sigmas_squared_est) < 0.0:
        print_stars("\n The variance estimates are")
        print(sigmas_squared_est)
        bs_error_abort("We have a negative variance estimate!")
    sigmas_est = np.sqrt(sigmas_squared_est)

    print_stars("The final estimates are:")
    for i in range(len(names_X1)):
        print(f"   beta1_{names_X1[i]}: {betas_est[i]:.3f}")
    for i in range(len(names_X2)):
        print(f"   sigma_{names_X2[i]}: {sigmas_est[i]:.3f}")
    return betas_est, sigmas_est