예제 #1
0
 def objectiveFuncMPC(center,spread):
     '''
     Objective function of the beta-dist estimation, similar to cstwMPC.
     Minimizes the distance between simulated and actual mean semiannual
     MPCs by wealth quintile.
     
     Parameters
     ----------
     center : float
         Mean of distribution of discount factor.
     spread : float
         Half width of span of discount factor.
         
     Returns
     -------
     distance : float
         Distance between simulated and actual moments.
     '''
     DiscFacSet = approxUniform(N=TypeCount,bot=center-spread,top=center+spread)[1]
     for j in range(TypeCount):
         Agents[j](DiscFac = DiscFacSet[j])
         
     multiThreadCommands(Agents,['solve()','initializeSim()','simulate()'])
     aLvl_sim = np.concatenate([agent.aLvlNow for agent in Agents])
     MPC_sim = np.concatenate([agent.MPCnow for agent in Agents])
     
     MPC_alt = 1. - (1. - MPC_sim)**2
     
     MPC_by_aLvl = calcSubpopAvg(MPC_alt,aLvl_sim,cutoffs)
     
     moments_sim = MPC_by_aLvl
     moments_diff = moments_sim - moments_data
     moments_diff[1:] *= 1 # Rescale Lorenz shares
     distance = np.sqrt(np.dot(moments_diff,moments_diff))
     
     print('Tried center=' + str(center) + ', spread=' + str(spread) + ', got distance=' + str(distance))
     print(moments_sim)
     return distance
def runRoszypalSchlaffmanExperiment(CorrAct, CorrPcvd, DiscFac_center, DiscFac_spread, numTypes, simPeriods):
    '''
    Solve and simulate a consumer type who misperceives the extent of serial correlation
    of persistent shocks to income.
    
    Parameters
    ----------
    CorrAct : float
        Serial correlation coefficient for *actual* persistent income.
    CorrPcvd : float
        List or array of *perceived* persistent income serial correlation
    DiscFac_center : float
        A measure of centrality for the distribution of the beta parameter, DiscFac.
    DiscFac_spread : float
        A measure of spread or diffusion for the distribution of the beta parameter.
    numTypes: int
        Number of different types of agents (distributed using DiscFac_center and DiscFac_spread)
    simPeriods: int
        Number of periods to simulate before calculating distributions

    Returns
    -------
    AggWealthRatio: float
        Ratio of Aggregate wealth to income.
    Lorenz: numpy.array
        A list of two 1D array representing the Lorenz curve for assets in the most recent simulated period.
    Gini: float
        Gini coefficient for assets in the most recent simulated period.
    Avg_MPC: numpy.array
        Average marginal propensity to consume by income quintile in the latest simulated period.
    
    '''     
    
    # Make a dictionary to construct our consumer type
    ThisDict = copy(BaselineDict)
    ThisDict['PrstIncCorr'] = CorrAct
    
    # Make a N=numTypes point approximation to a uniform distribution of DiscFac
    DiscFac_list = approxUniform(N=numTypes,bot=DiscFac_center-DiscFac_spread,top=DiscFac_center+DiscFac_spread)[1]
    
    type_list = []
    # Make a PersistentShockConsumerTypeX for each value of beta saved in DiscFac_list
    for i in range(len(DiscFac_list)):    
        ThisDict['DiscFac'] = DiscFac_list[i]    
        ThisType = PersistentShockConsumerTypeX(**ThisDict)
              
        # Make the consumer *believe* he will face a different level of persistence
        ThisType.PrstIncCorr = CorrPcvd
        ThisType.updatepLvlNextFunc() # *thinks* E[p_{t+1}] as a function of p_t is different than it is
    
        # Solve the consumer's problem with *perceived* persistence 
        ThisType.solve()
    
        # Make the consumer type experience the true level of persistence during simulation
        ThisType.PrstIncCorr = CorrAct
        ThisType.updatepLvlNextFunc()
    
        # Simulate the agents for many periods
        ThisType.T_sim = simPeriods
        #ThisType.track_vars = ['cLvlNow','aLvlNow','pLvlNow','MPCnow']
        ThisType.initializeSim()
        ThisType.simulate()
        type_list.append(ThisType)
    
    # Get the most recent simulated values of X = cLvlNow, MPCnow, aLvlNow, pLvlNow for all types   
    cLvl_all = np.concatenate([ThisType.cLvlNow for ThisType in type_list])
    aLvl_all = np.concatenate([ThisType.aLvlNow for ThisType in type_list])
    MPC_all = np.concatenate([ThisType.MPCnow for ThisType in type_list])
    pLvl_all = np.concatenate([ThisType.pLvlNow for ThisType in type_list])
    
    # The ratio of aggregate assets over the income
    AggWealthRatio = np.mean(aLvl_all) / np.mean(pLvl_all)

    # first 1D array: Create points in the range (0,1)
    wealth_percentile = np.linspace(0.001,0.999,201)

    # second 1D array: Compute Lorenz shares for the created points
    Lorenz_init = getLorenzShares(aLvl_all, percentiles=wealth_percentile)

    # Stick 0 and 1 at the boundaries of both arrays to make it inclusive on the range [0,1]
    Lorenz_init = np.concatenate([[0],Lorenz_init,[1]])
    wealth_percentile = np.concatenate([[0],wealth_percentile,[1]])
    
    # Create a list of wealth_percentile 1D array and Lorenz Shares 1D array
    Lorenz  = np.stack((wealth_percentile, Lorenz_init))

    # Compute the Gini coefficient
    Gini = 1.0 - 2.0*np.mean(Lorenz_init[1])
    
    # Compute the average MPC by income quintile in the latest simulated period
    Avg_MPC = calcSubpopAvg(MPC_all, pLvl_all, cutoffs=[(0.0,0.2), (0.2,0.4),  (0.4,0.6), (0.6,0.8), (0.8,1.0)])
    
    return AggWealthRatio, Lorenz, Gini, Avg_MPC
예제 #3
0
    def calcStats(self, aLvlNow, pLvlNow, MPCnow, lIncomeLvl, EmpNow, t_age,
                  LorenzBool, ManyStatsBool):
        '''
        Calculate various statistics about the current population in the economy.
        
        Parameters
        ----------
        aLvlNow : [np.array]
            Arrays with end-of-period assets, listed by each ConsumerType in self.agents.
        pLvlNow : [np.array]
            Arrays with permanent income levels, listed by each ConsumerType in self.agents.
        MPCnow : [np.array]
            Arrays with marginal propensity to consume, listed by each ConsumerType in self.agents.
        lIncomeLvl : [np.array]
            Arrays with labor income levels, listed by each ConsumerType in self.agents.
        EmpNow : [np.array]
            Arrays with employment states: True if employed, False otherwise.
        t_age : [np.array]
            Arrays with periods elapsed since model entry, listed by each ConsumerType in self.agents.
        LorenzBool: bool
            Indicator for whether the Lorenz target points should be calculated.  Usually False,
            only True when DiscFac has been identified for a particular nabla.
        ManyStatsBool: bool
            Indicator for whether a lot of statistics for tables should be calculated. Usually False,
            only True when parameters have been estimated and we want values for tables.
            
        Returns
        -------
        None
        '''
        # Combine inputs into single arrays
        aLvl = np.hstack(aLvlNow)
        pLvl = np.hstack(pLvlNow)
        age = np.hstack(t_age)
        IncLvl = np.hstack(lIncomeLvl)
        Emp = np.hstack(EmpNow)

        # Calculate the capital to income ratio in the economy
        CohortWeight = self.PopGroFac**(-age)
        CapAgg = np.sum(aLvl * CohortWeight)
        IncAgg = np.sum(IncLvl * CohortWeight)
        KtoYnow = CapAgg / IncAgg
        self.KtoYnow = KtoYnow

        # Store Lorenz data if requested
        self.LorenzLong = np.nan
        if LorenzBool:
            order = np.argsort(aLvl)
            aLvl = aLvl[order]
            CohortWeight = CohortWeight[order]
            wealth_shares = getLorenzShares(aLvl,
                                            weights=CohortWeight,
                                            percentiles=self.LorenzPercentiles,
                                            presorted=True)
            self.Lorenz = wealth_shares
            if ManyStatsBool:
                self.LorenzLong = getLorenzShares(aLvl,
                                                  weights=CohortWeight,
                                                  percentiles=np.arange(
                                                      0.01, 1.0, 0.01),
                                                  presorted=True)
        else:
            self.Lorenz = np.nan  # Store nothing if we don't want Lorenz data

        # Calculate a whole bunch of statistics if requested
        if ManyStatsBool:
            # Reshape other inputs
            MPC = np.hstack(MPCnow)

            # Sort other data items if aLvl and CohortWeight were sorted
            if LorenzBool:
                pLvl = pLvl[order]
                MPC = MPC[order]
                IncLvl = IncLvl[order]
                age = age[order]
                Emp = Emp[order]
            aNrm = aLvl / pLvl  # Normalized assets (wealth ratio)

            # Calculate overall population MPC and by subpopulations
            # MPC_cf_BPP is the MPC that is comparable with the empirical estimation method
            MPC_cf_BPP = 1.0 - 0.25 * ((1.0 - MPC) + (1.0 - MPC)**2 +
                                       (1.0 - MPC)**3 + (1.0 - MPC)**4)
            self.MPCall = np.sum(
                MPC_cf_BPP * CohortWeight) / np.sum(CohortWeight)
            employed = Emp
            unemployed = np.logical_not(employed)
            self.MPCbyWealthRatio = calcSubpopAvg(MPC_cf_BPP, aNrm,
                                                  self.cutoffs, CohortWeight)
            self.MPCbyIncome = calcSubpopAvg(MPC_cf_BPP, IncLvl, self.cutoffs,
                                             CohortWeight)

            # Calculate the wealth quintile distribution of "hand to mouth" consumers
            quintile_cuts = getPercentiles(aLvl,
                                           weights=CohortWeight,
                                           percentiles=[0.2, 0.4, 0.6, 0.8])
            wealth_quintiles = np.ones(aLvl.size, dtype=int)
            wealth_quintiles[aLvl > quintile_cuts[0]] = 2
            wealth_quintiles[aLvl > quintile_cuts[1]] = 3
            wealth_quintiles[aLvl > quintile_cuts[2]] = 4
            wealth_quintiles[aLvl > quintile_cuts[3]] = 5
            MPC_cutoff = getPercentiles(
                MPC_cf_BPP, weights=CohortWeight, percentiles=[
                    2.0 / 3.0
                ])  # Looking at consumers with MPCs in the top 1/3
            these = MPC_cf_BPP > MPC_cutoff
            in_top_third_MPC = wealth_quintiles[these]
            temp_weights = CohortWeight[these]
            hand_to_mouth_total = np.sum(temp_weights)
            hand_to_mouth_pct = []
            for q in range(1, 6):
                hand_to_mouth_pct.append(
                    np.sum(temp_weights[in_top_third_MPC == q]) /
                    hand_to_mouth_total)
            self.HandToMouthPct = np.array(hand_to_mouth_pct)

        else:  # If we don't want these stats, just put empty values in history
            self.MPCall = np.nan
            self.MPCunemployed = np.nan
            self.MPCemployed = np.nan
            self.MPCretired = np.nan
            self.MPCbyWealthRatio = np.nan
            self.MPCbyIncome = np.nan
            self.HandToMouthPct = np.nan
예제 #4
0
def makeCSTWstats(DiscFac,
                  nabla,
                  this_type_list,
                  age_weight,
                  lorenz_distance=0.0,
                  save_name=None):
    '''
    Displays (and saves) a bunch of statistics.  Separate from makeCSTWresults()
    for compatibility with the aggregate shock model.

    Parameters
    ----------
    DiscFac : float
        Center of the uniform distribution of discount factors
    nabla : float
        Width of the uniform distribution of discount factors
    this_type_list : [cstwMPCagent]
        List of agent types in the economy.
    age_weight : np.array
        Age-conditional array of weights for the wealth data.
    lorenz_distance : float
        Distance between simulated and actual Lorenz curves, for display.
    save_name : string
        Name to save the calculated results, for later use in producing figures
        and tables, etc.

    Returns
    -------
    none
    '''
    sim_length = this_type_list[0].sim_periods
    sim_wealth = (np.vstack(
        (this_type.W_history for this_type in this_type_list))).flatten()
    sim_wealth_short = (np.vstack(
        (this_type.W_history[0:sim_length, :]
         for this_type in this_type_list))).flatten()
    sim_kappa = (np.vstack(
        (this_type.kappa_history for this_type in this_type_list))).flatten()
    sim_income = (np.vstack((this_type.pHist[0:sim_length, :] *
                             np.asarray(this_type.TranShkHist[0:sim_length, :])
                             for this_type in this_type_list))).flatten()
    sim_ratio = (np.vstack((this_type.W_history[0:sim_length, :] /
                            this_type.pHist[0:sim_length, :]
                            for this_type in this_type_list))).flatten()
    if Params.do_lifecycle:
        sim_unemp = (np.vstack((np.vstack((
            this_type.IncUnemp == this_type.TranShkHist[0:Params.working_T, :],
            np.zeros((Params.retired_T + 1, this_type_list[0].Nagents),
                     dtype=bool)))
                                for this_type in this_type_list))).flatten()
        sim_emp = (np.vstack((np.vstack(
            (this_type.IncUnemp !=
             this_type.TranShkHist[0:Params.working_T, :],
             np.zeros((Params.retired_T + 1, this_type_list[0].Nagents),
                      dtype=bool)))
                              for this_type in this_type_list))).flatten()
        sim_ret = (np.vstack((np.vstack(
            (np.zeros((Params.working_T, this_type_list[0].Nagents),
                      dtype=bool),
             np.ones((Params.retired_T + 1, this_type_list[0].Nagents),
                     dtype=bool)))
                              for this_type in this_type_list))).flatten()
    else:
        sim_unemp = np.vstack(
            (this_type.IncUnemp == this_type.TranShkHist[0:sim_length, :]
             for this_type in this_type_list)).flatten()
        sim_emp = np.vstack(
            (this_type.IncUnemp != this_type.TranShkHist[0:sim_length, :]
             for this_type in this_type_list)).flatten()
        sim_ret = np.zeros(sim_emp.size, dtype=bool)
    sim_weight_all = np.tile(np.repeat(age_weight, this_type_list[0].Nagents),
                             Params.pref_type_count)

    if Params.do_beta_dist and Params.do_lifecycle:
        kappa_mean_by_age_type = (np.mean(np.vstack(
            (this_type.kappa_history for this_type in this_type_list)),
                                          axis=1)).reshape(
                                              (Params.pref_type_count * 3,
                                               DropoutType.T_total + 1))
        kappa_mean_by_age_pref = np.zeros(
            (Params.pref_type_count, DropoutType.T_total + 1)) + np.nan
        for j in range(Params.pref_type_count):
            kappa_mean_by_age_pref[
                j, ] = Params.d_pct * kappa_mean_by_age_type[
                    3 * j + 0, ] + Params.h_pct * kappa_mean_by_age_type[
                        3 * j + 1, ] + Params.c_pct * kappa_mean_by_age_type[
                            3 * j + 2, ]
        kappa_mean_by_age = np.mean(kappa_mean_by_age_pref, axis=0)
        kappa_lo_beta_by_age = kappa_mean_by_age_pref[0, :]
        kappa_hi_beta_by_age = kappa_mean_by_age_pref[Params.pref_type_count -
                                                      1, :]

    lorenz_fig_data = makeLorenzFig(Params.SCF_wealth, Params.SCF_weights,
                                    sim_wealth, sim_weight_all)
    mpc_fig_data = makeMPCfig(sim_kappa, sim_weight_all)

    kappa_all = calcWeightedAvg(
        np.vstack((this_type.kappa_history for this_type in this_type_list)),
        np.tile(age_weight / float(Params.pref_type_count),
                Params.pref_type_count))
    kappa_unemp = np.sum(
        sim_kappa[sim_unemp] * sim_weight_all[sim_unemp]) / np.sum(
            sim_weight_all[sim_unemp])
    kappa_emp = np.sum(sim_kappa[sim_emp] * sim_weight_all[sim_emp]) / np.sum(
        sim_weight_all[sim_emp])
    kappa_ret = np.sum(sim_kappa[sim_ret] * sim_weight_all[sim_ret]) / np.sum(
        sim_weight_all[sim_ret])

    my_cutoffs = [(0.99, 1), (0.9, 1), (0.8, 1), (0.6, 0.8), (0.4, 0.6),
                  (0.2, 0.4), (0.0, 0.2)]
    kappa_by_ratio_groups = calcSubpopAvg(sim_kappa, sim_ratio, my_cutoffs,
                                          sim_weight_all)
    kappa_by_income_groups = calcSubpopAvg(sim_kappa, sim_income, my_cutoffs,
                                           sim_weight_all)

    quintile_points = getPercentiles(sim_wealth_short,
                                     weights=sim_weight_all,
                                     percentiles=[0.2, 0.4, 0.6, 0.8])
    wealth_quintiles = np.ones(sim_wealth_short.size, dtype=int)
    wealth_quintiles[sim_wealth_short > quintile_points[0]] = 2
    wealth_quintiles[sim_wealth_short > quintile_points[1]] = 3
    wealth_quintiles[sim_wealth_short > quintile_points[2]] = 4
    wealth_quintiles[sim_wealth_short > quintile_points[3]] = 5
    MPC_cutoff = getPercentiles(sim_kappa,
                                weights=sim_weight_all,
                                percentiles=[2.0 / 3.0])
    these_quintiles = wealth_quintiles[sim_kappa > MPC_cutoff]
    these_weights = sim_weight_all[sim_kappa > MPC_cutoff]
    hand_to_mouth_total = np.sum(these_weights)
    hand_to_mouth_pct = []
    for q in range(5):
        hand_to_mouth_pct.append(
            np.sum(these_weights[these_quintiles == (q + 1)]) /
            hand_to_mouth_total)

    results_string = 'Estimate is DiscFac=' + str(DiscFac) + ', nabla=' + str(
        nabla) + '\n'
    results_string += 'Lorenz distance is ' + str(lorenz_distance) + '\n'
    results_string += 'Average MPC for all consumers is ' + mystr(
        kappa_all) + '\n'
    results_string += 'Average MPC in the top percentile of W/Y is ' + mystr(
        kappa_by_ratio_groups[0]) + '\n'
    results_string += 'Average MPC in the top decile of W/Y is ' + mystr(
        kappa_by_ratio_groups[1]) + '\n'
    results_string += 'Average MPC in the top quintile of W/Y is ' + mystr(
        kappa_by_ratio_groups[2]) + '\n'
    results_string += 'Average MPC in the second quintile of W/Y is ' + mystr(
        kappa_by_ratio_groups[3]) + '\n'
    results_string += 'Average MPC in the middle quintile of W/Y is ' + mystr(
        kappa_by_ratio_groups[4]) + '\n'
    results_string += 'Average MPC in the fourth quintile of W/Y is ' + mystr(
        kappa_by_ratio_groups[5]) + '\n'
    results_string += 'Average MPC in the bottom quintile of W/Y is ' + mystr(
        kappa_by_ratio_groups[6]) + '\n'
    results_string += 'Average MPC in the top percentile of y is ' + mystr(
        kappa_by_income_groups[0]) + '\n'
    results_string += 'Average MPC in the top decile of y is ' + mystr(
        kappa_by_income_groups[1]) + '\n'
    results_string += 'Average MPC in the top quintile of y is ' + mystr(
        kappa_by_income_groups[2]) + '\n'
    results_string += 'Average MPC in the second quintile of y is ' + mystr(
        kappa_by_income_groups[3]) + '\n'
    results_string += 'Average MPC in the middle quintile of y is ' + mystr(
        kappa_by_income_groups[4]) + '\n'
    results_string += 'Average MPC in the fourth quintile of y is ' + mystr(
        kappa_by_income_groups[5]) + '\n'
    results_string += 'Average MPC in the bottom quintile of y is ' + mystr(
        kappa_by_income_groups[6]) + '\n'
    results_string += 'Average MPC for the employed is ' + mystr(
        kappa_emp) + '\n'
    results_string += 'Average MPC for the unemployed is ' + mystr(
        kappa_unemp) + '\n'
    results_string += 'Average MPC for the retired is ' + mystr(
        kappa_ret) + '\n'
    results_string += 'Of the population with the 1/3 highest MPCs...' + '\n'
    results_string += mystr(
        hand_to_mouth_pct[0] *
        100) + '% are in the bottom wealth quintile,' + '\n'
    results_string += mystr(
        hand_to_mouth_pct[1] *
        100) + '% are in the second wealth quintile,' + '\n'
    results_string += mystr(hand_to_mouth_pct[2] *
                            100) + '% are in the third wealth quintile,' + '\n'
    results_string += mystr(
        hand_to_mouth_pct[3] *
        100) + '% are in the fourth wealth quintile,' + '\n'
    results_string += 'and ' + mystr(
        hand_to_mouth_pct[4] *
        100) + '% are in the top wealth quintile.' + '\n'
    print(results_string)

    if save_name is not None:
        with open('./Results/' + save_name + 'LorenzFig.txt', 'w') as f:
            my_writer = csv.writer(
                f,
                delimiter='\t',
            )
            for j in range(len(lorenz_fig_data[0])):
                my_writer.writerow([
                    lorenz_fig_data[0][j], lorenz_fig_data[1][j],
                    lorenz_fig_data[2][j]
                ])
            f.close()
        with open('./Results/' + save_name + 'MPCfig.txt', 'w') as f:
            my_writer = csv.writer(f, delimiter='\t')
            for j in range(len(mpc_fig_data[0])):
                my_writer.writerow([lorenz_fig_data[0][j], mpc_fig_data[1][j]])
            f.close()
        if Params.do_beta_dist and Params.do_lifecycle:
            with open('./Results/' + save_name + 'KappaByAge.txt', 'w') as f:
                my_writer = csv.writer(f, delimiter='\t')
                for j in range(len(kappa_mean_by_age)):
                    my_writer.writerow([
                        kappa_mean_by_age[j], kappa_lo_beta_by_age[j],
                        kappa_hi_beta_by_age[j]
                    ])
                f.close()
        with open('./Results/' + save_name + 'Results.txt', 'w') as f:
            f.write(results_string)
            f.close()