├── .gitattributes ├── Exercises ├── Chapter 1 │ ├── Chapter1iv.m │ ├── Surplus.m │ ├── Utility2.m │ ├── SIGN.m │ ├── Chapter1ii.m │ ├── Chapter1i.m │ └── Chapter1iii.m ├── Chapter 3 │ ├── MMobjective.m │ ├── GMM2STEP.m │ ├── Chapter3iib.m │ ├── Chapter3iii.m │ ├── Chapter3iv.m │ ├── ProbitML.m │ ├── Chapter3iia.m │ └── Chapter3i.m ├── Chapter 2 │ ├── Chapter2i.m │ ├── Chapter2iii.m │ └── Chapter2ii.m └── Chapter 4 │ ├── Chapter4i.m │ ├── Chapter4ii.m │ ├── Chapter4vi.m │ └── Chapter4iii_v.m └── Text examples ├── BinaryLogitLL.m ├── Chapter1_2.m ├── Chapter1_1.m ├── Chapter3_2.m ├── Chapter1_3.m ├── Chapter2_2.m ├── Chapter2_1.m ├── Chapter3_1.m └── Chapter4_1.m /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Exercises/Chapter 1/Chapter1iv.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StijnDreesen/MMintro/HEAD/Exercises/Chapter 1/Chapter1iv.m -------------------------------------------------------------------------------- /Exercises/Chapter 3/MMobjective.m: -------------------------------------------------------------------------------- 1 | function m = MMobjective(Beta,y,X) 2 | 3 | N = length(y); 4 | K = size(X,2); 5 | u = y - X*Beta; 6 | m = 1/N*u'*X; 7 | 8 | return -------------------------------------------------------------------------------- /Exercises/Chapter 1/Surplus.m: -------------------------------------------------------------------------------- 1 | function u = Surplus(g,r) 2 | 3 | u = -exp(-r.*g)-exp(0.5.*(r.^2)).*(1-cdf('Normal',g+r,0,1)).*(1./(1-cdf('Normal',g,0,1))) 4 | 5 | 6 | return 7 | -------------------------------------------------------------------------------- /Text examples/BinaryLogitLL.m: -------------------------------------------------------------------------------- 1 | function [LL, ll_i] = BinaryLogitLL(Beta, y, x) % Fixed code. 2 | 3 | Lambda_xb = exp(x * Beta)./(1 + exp(x * Beta)); % Logistic CDF (4.6). 4 | 5 | ll_i = y .* log(Lambda_xb) + (1 - y) .* log(1 - Lambda_xb); % Likelihood function (4.9). 6 | 7 | LL = -sum(ll_i); 8 | 9 | return -------------------------------------------------------------------------------- /Text examples/Chapter1_2.m: -------------------------------------------------------------------------------- 1 | % Assuming auto.dta is still in the memory as done in Chapter1_1.m: 2 | 3 | OLS(y, X) % Results are the same. 4 | 5 | % We can save these results in a matrix: 6 | 7 | OLS_Beta = OLS(y, X) 8 | 9 | % But where are the standard errors? 10 | 11 | [OLS_Beta, OLS_se] = OLS(y, X) -------------------------------------------------------------------------------- /Exercises/Chapter 2/Chapter2i.m: -------------------------------------------------------------------------------- 1 | % Revenue function: R(a,b) = 7a + 12 where a is trout and b salmon. 2 | 3 | f = [-7, -12] % Since we are actually minimizing the objective function. 4 | A = [1,2; 2,3] 5 | b = [1000; 1600] 6 | % Since a+2b<=1000 and 2a+3b<=1600. 7 | lb = zeros(2,1); 8 | 9 | [fish, obj, exitflag] = linprog(f, A, b, [], [], lb) 10 | 11 | % The fisherwoman must catch 200 trout and 400 salmon. She then has a 12 | % revenue of 6200 dollars. Exitflag = 1, so a solution has been found. -------------------------------------------------------------------------------- /Exercises/Chapter 3/GMM2STEP.m: -------------------------------------------------------------------------------- 1 | function Q = GMM2STEP(Beta,y,X) % Where Beta are the results from the first-stage estimates. 2 | 3 | N = length(y); 4 | K = size(X,2); 5 | 6 | u = y - X*Beta; 7 | 8 | % Here we implement the second step of the estimator (defining a new 9 | % optimal weight matrix based on our first-stage estimates supplied by 10 | % GMMobjective.m 11 | 12 | 13 | A = (X'*(y-X*Beta))'*(X'*(y-X*Beta)) 14 | W = 1/N*sum(A) 15 | 16 | m = 1/N*u'*X; 17 | Q = m*W*m'; 18 | 19 | 20 | return 21 | -------------------------------------------------------------------------------- /Exercises/Chapter 1/Utility2.m: -------------------------------------------------------------------------------- 1 | function u = Utility(x1, x2, a) 2 | %------------------------------------------------ 3 | % PURPOSE: calculate utility: 2 good Cobb-Douglas 4 | % specification for a given alpha. 5 | %------------------------------------------------ 6 | % USAGE: u : Utility(x1, x2) 7 | % where: x1 : quantity of q1 8 | % x2 : quantity of q2 9 | % a : consumer preferences 10 | %------------------------------------------------ 11 | % OUTPUT: u : overall utility 12 | %------------------------------------------------ 13 | 14 | u = (x1.^a) .* (x2.^(1-a)); 15 | 16 | return 17 | -------------------------------------------------------------------------------- /Text examples/Chapter1_1.m: -------------------------------------------------------------------------------- 1 | DataIn = dlmread('auto.csv'); % We import the data sheet. We name this imported data DataIn. 2 | whos('DataIn') 3 | y = DataIn(:,1); % Take first column and call it y. 4 | X = [DataIn(:, 2:3), ones(74,1)]; % Take second and third column and join them with a vector of ones. : denotes that every row is taken. 5 | 6 | OLS(y,X) % Two matrices are now generated, one for the estimated betas and one for SEs, t 7 | 8 | BetaHat = inv(X'*X)*X'*y % Calculate BetaHat according to the well-known matrix notation. 9 | 10 | 11 | % We can then again make the relatively easy transition from the matrix 12 | % notation of standard errors. 13 | 14 | 15 | -------------------------------------------------------------------------------- /Exercises/Chapter 3/Chapter3iib.m: -------------------------------------------------------------------------------- 1 | % We retake the code from Chapter 3.2. The method follows page 19 on 2 | % https://www.stata.com/manuals13/rgmm.pdf. 3 | 4 | clear; 5 | DataIn = dlmread('auto.csv'); 6 | X = [ones(74,1) DataIn(:,2:3)]; 7 | y = DataIn(:,1); 8 | [Beta,Q] = fminsearch(@(B) GMMObjective(B,y,X), [10,0,0]', optimset('TolX',1e-9)) 9 | 10 | % Our weight matrix is not the optimal one. The covariance matrix is then: 11 | 12 | [N, K] = size(X) 13 | 14 | V = inv(X'*X) 15 | 16 | % Calculate covariance of residuals: 17 | 18 | yhat = X*Beta; 19 | u = y - yhat; 20 | 21 | C = cov(u) 22 | 23 | COV = C*V 24 | 25 | SE = sqrt(COV) 26 | 27 | % The standard errors are a bit different than the ones reported on p.6 28 | % Note that GMM is efficient in the class of asymptotically normal estimators. -------------------------------------------------------------------------------- /Exercises/Chapter 3/Chapter3iii.m: -------------------------------------------------------------------------------- 1 | % In this exercise, we do a two-step GMM. The first step is performed by 2 | % GMMObjective.m and supplies the first-stage estimates to be used in the 3 | % second step's optimal weighting matrix, handled by the function GMM2step. 4 | 5 | clear; 6 | DataIn = dlmread('auto.csv'); 7 | X = [ones(74,1) DataIn(:,2:3)]; 8 | y = DataIn(:,1); 9 | [Beta,Q] = fminsearch(@(B) GMMObjective(B,y,X), [10,0,0]', optimset('TolX',1e-9)) 10 | 11 | % We are now supplied with new Betas. Use these new ones by minimizing the 12 | % objective function GMM2STEP. 13 | 14 | [Beta2,Q] = fminsearch(@(Beta) GMM2STEP(Beta,y,X), [10,0,0]', optimset('TolX',1e-9)) 15 | 16 | % The same results are found, which is logical (remember that if Z=X, then 17 | % the moment equation is exactly equal to least squares (just like in one-step GMM). 18 | 19 | 20 | -------------------------------------------------------------------------------- /Text examples/Chapter3_2.m: -------------------------------------------------------------------------------- 1 | % Using GMM, we define population moments that are true in the model. GMM 2 | % again requires optimizing the objective function. (3.4) is the moment 3 | % vector, which is equal to zero. The estimated betas should drive the 4 | % quadratic distance (mWm') as close to zero as possible. The weight matrix 5 | % W needs to be positive semidefinite. 6 | 7 | % Let's put GMMobjective.m to use. 8 | clear; 9 | DataIn = dlmread('auto.csv'); 10 | X = [ones(74,1) DataIn(:,2:3)]; 11 | y = DataIn(:,1); 12 | [Beta,Q] = fminsearch(@(B) GMMObjective(B,y,X), [10,0,0]', optimset('TolX',1e-9)) % The choice variable is Beta. No constraints are imposed, but initial values are given for the Betas. 13 | 14 | % Note Q comes very close to zero. We have exactly as many moments as 15 | % unknown, so Q should be zero (otherwise, the optimization needs some 16 | % finetuning. 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Exercises/Chapter 3/Chapter3iv.m: -------------------------------------------------------------------------------- 1 | % For more info, read from page 10. onwards. 2 | 3 | % OLS can easily be viewed as an MM estimator, where rather than minimizing 4 | % the quadratic distance, we simply set each moment to zero instead. 5 | % Indeed, the sample moment should be equal to zero (and it is precisely of 6 | % the form in 3.4). Effectively, coding this estimator boils down to 7 | % stripping GMMobjective.m of the parts referring to quadratic distance. 8 | % Indeed, we can much more simply use the fsolve function to solve 9 | % MMobjective.m for Beta, setting m = 0 as in (3.4.). Notice the output of 10 | % the function MMobjective.m is now simply m. 11 | 12 | clear; 13 | DataIn = dlmread('auto.csv'); 14 | X = [ones(74,1) DataIn(:,2:3)]; 15 | y = DataIn(:,1); 16 | 17 | [Beta] = fsolve(@(Beta) MMobjective(Beta, y, X), [10,0,0]') 18 | 19 | % Indeed, we arrive at the same solution as our previous estimators. 20 | -------------------------------------------------------------------------------- /Text examples/Chapter1_3.m: -------------------------------------------------------------------------------- 1 | % The file UtilitySimple returns the correct answers: 2 | 3 | UtilitySimple(1, 4) 4 | UtilitySimple(3, 3) 5 | % Any reasons it shows all these zeroes? for line 4? 6 | 7 | x1 = [1:10]'; 8 | x2 = 5; 9 | 10 | % UtilitySimple(x1, x2) This code does not work, because UtilitySimple is 11 | % not equipped to handle anything else but scalars. 12 | 13 | % We can now instead use the more complex version, able to handle vectors and 14 | % matrices. We first redefine x1 and x2 to a meshgrid: 15 | 16 | [x1, x2] = meshgrid([0:3], [0:3]) 17 | 18 | u = Utility(x1, x2) 19 | 20 | surfc(x1, x2, u) % This visualizes all utilities for the two-dimensional space [0,3] x [0, 3]. As basic input, it simply needs values X, Y and Z. 21 | 22 | % Finetuning the grid is easy: 23 | 24 | [x1, x2] = meshgrid([0:.1:3], [0:.1:3]); % Note we now use intervals 0.1. 25 | 26 | u = Utility(x1, x2); 27 | surfc(x1, x2, u) 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Exercises/Chapter 1/SIGN.m: -------------------------------------------------------------------------------- 1 | % In this exercise, we write a function to be used AFTER OLS.m which 2 | % calculates a 95 confidence interval for the betas as well as t and 3 | % p-values. Remember that the function OLS.m returns Beta and se. The 4 | % function therefore uses these values as input and returns confidence 5 | % intervals, p-values and t-values. We call this function simply 'SIGN' 6 | % after significance. 7 | 8 | function [BetaT, CI, BetaP] = SIGN(Beta, se, N, K) 9 | 10 | % Remembering the formula for the t-statistic of beta (simply Beta divided 11 | % by its standard error (se), which have been calculated in OLS.m), testing 12 | % for beta = 0). 13 | 14 | BetaT = Beta./se; 15 | 16 | % And the confidence interval: 17 | invT= -tinv(0.025,N); % Calculate the 97.5% critical value. 18 | CI = [Beta-invT.*se, Beta+invT.*se]; % Classic formula for the 95 CI. 19 | 20 | % Finally, the p-value: 21 | 22 | BetaP = 2*(1-tcdf(abs(BetaT),N)) 23 | 24 | return 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Exercises/Chapter 3/ProbitML.m: -------------------------------------------------------------------------------- 1 | function LL = ProbitML(Beta,y,x) % Note: Defining a theta is not necessary: we just need Beta. 2 | %---------------------------------------------- 3 | % PURPOSE: calculates the likelihood function 4 | % for probit estimation. 5 | %---------------------------------------------- 6 | % USAGE: LL = NormalML(theta,y,x) 7 | % where: Beta : parameter vector 8 | % y : N-by-1 dependent variable 9 | % x : N-by-K independent variable 10 | %---------------------------------------------- 11 | % OUTPUT: LL = log-likelihood value 12 | %---------------------------------------------- 13 | % Translate the text's formula from exercise i in a log-likelihood 14 | % function. I broke up the code in several parts for clarity. Some often 15 | % overlooked mistakes that might occur are doing element-by-element 16 | % multiplication (not necessary) or not transposing y and Beta. 17 | 18 | a = y'*log(normcdf(x*Beta')) 19 | b = (1-y)'*log(1-normcdf(x*Beta')) 20 | c = -sum(a+b) 21 | LL = c 22 | 23 | -------------------------------------------------------------------------------- /Exercises/Chapter 1/Chapter1ii.m: -------------------------------------------------------------------------------- 1 | % In this exercise, we check our-self written function SIGN.m, which 2 | % calculates the confidence interval, p-value and t-statistic of the 3 | % coefficients calculated in OLS.m. To demonstrate its functionality, 4 | % we can compare our results with the results in the table of page 6. 5 | 6 | clear; 7 | 8 | DataIn = dlmread('auto.csv'); 9 | whos('DataIn') 10 | y = DataIn(:,1); 11 | X = [DataIn(:, 2:3), ones(74,1)]; 12 | 13 | [Beta, se] = OLS(y, X) 14 | % Note that we call the output of OLS.m 'Beta' and 'se', same as the input 15 | % arguments of SIGN.m. 16 | 17 | % Since the function OLS.m only outputs Beta and se, we also need to 18 | % calculate N and K and use them as input: 19 | 20 | [N, K] = size(X) 21 | 22 | % We now have everything necessary to test our function: 23 | 24 | SIGN(Beta, se, N, K) % Note it only gives the very first output which is supposed to be returned: the t-statistic (see also page 12). 25 | 26 | % We can, however, easily request all output: 27 | 28 | [BetaT, CI, BetaP] = SIGN(Beta, se, N, K) 29 | 30 | % Compare to the table on page 6: the results are exactly the same. -------------------------------------------------------------------------------- /Exercises/Chapter 1/Chapter1i.m: -------------------------------------------------------------------------------- 1 | % The goal is to replicate the standard errors as generated in 2 | % Chapter1_2.m by the OLS.m function. 3 | 4 | clear; 5 | 6 | DataIn = dlmread('auto.csv'); % Read in the data again. 7 | y = DataIn(:,1); % Take first column and call it y. 8 | X = [DataIn(:, 2:3), ones(74,1)]; % Take second and third column and join them with a vector of ones. : denotes that every row is taken. 9 | size(X) % Check that the size of our matrix X is as needed. 10 | 11 | BetaHat = inv(X'*X)*X'*y % Calculate BetaHat according to the well-known matrix notation. These are the same as OLS_beta. 12 | 13 | % We can then again make the relatively easy transition from the matrix 14 | % notation of standard errors to MATLAB code. 15 | % We need a value N (number of observations) and K (number of independent 16 | % variables): 17 | 18 | [N, K] = size(X); 19 | yhat = X*BetaHat; 20 | u = y - yhat; 21 | VarHat = inv(X'*X)*inv(N-K)*(u'*u); 22 | BetaSE = diag(sqrt(VarHat)) % Note that we only need the diagonal elements. 23 | 24 | % Compare with the results from OLS.m: 25 | 26 | [OLS_Beta, OLS_se] = OLS(y, X) 27 | 28 | % They are the same! In fact, the code above is roughly the same as the one 29 | % in OLS.m. 30 | 31 | -------------------------------------------------------------------------------- /Exercises/Chapter 4/Chapter4i.m: -------------------------------------------------------------------------------- 1 | % Note, SimulateBinaryLogit is missing the Utility output in its function. 2 | % i.e. it has been changed to [y,utility]=SimulateBinaryLogit(x,Beta) for 3 | % this exercise. The augmented beta has also been removed. The expected 4 | % value of y is then simply 0.5. 5 | 6 | clear; 7 | 8 | N = 10000; 9 | Beta = [0.5, 0.5]'; % Our true Betas. 10 | income = randn(N, 1) % Generate normally distributed random numbers for income. 11 | x = [ones(N, 1), income] % Conjoin them with a vector of constants (ones). 12 | 13 | 14 | % Taking a look at SimulateBinaryLogit.m, we get an output (y) and the 15 | % utility as dictated by the equations on page 43. Notice line 17: 16 | % epsilon = -log(-log(rand(N, J))); 17 | % It draws from the Type 1 extreme value distribution (compare with 18 | % Equation (4.5). We can test this estimator on our simulated data: 19 | 20 | [y, utility] = SimulateBinaryLogit(x, Beta); % Notice we simply receive the y-values here. 21 | 22 | mu = mean(y) 23 | sigma = var(y) 24 | 25 | % For smaller N's, the mean is not always close to the expected value of y. 26 | % For larger N's, the mean gets closer to 0.61, the expected value. The 27 | % variance stays about the same for larger sample sizes. This is in 28 | % accordance with the law of large numbers and CLT. 29 | 30 | 31 | -------------------------------------------------------------------------------- /Text examples/Chapter2_2.m: -------------------------------------------------------------------------------- 1 | % We now focus on non-linear problems, such as the CD function in Chapter 2 | % 1. We then need a generalized optimization method, the fmincon. We also 3 | % allow for non-linear constraints (as can be seen in (2.6.). Note that 4 | % fmincon now DOES require us to feed an initial guess (x0) to the 5 | % algorithm. 6 | 7 | I = 100; % The income to spend on both goods. 8 | P = [4,7]; % First good costs 4$ and 7$. 9 | G = [15,5]; % An initial guess (economic intuition would indeed suggest she buys more of the cheaper good). 10 | lb = [0,0]; % We cannot buy a negative amount of goods. 11 | 12 | 13 | [consumption, u, exitflag] = fmincon(@CobbDouglas,G,P,I,[],[],lb) % We feed fmincon objective function, the initial values, the prices, the income we can spend on these prices and a lower bound). 14 | 15 | % Again, pay attention that u is now negative. The exitflag is 1, meaning 16 | % that the optimality conditions of the first order conditions are 17 | % satisfied. 18 | 19 | 20 | % We can now tell fmincon to optimize using the sequential quadratic 21 | % programming algorithm. Define options: 22 | 23 | opts= optimset('Algorithm','sqp'); 24 | 25 | % We can repeat the code from line 13, now specifying different options: 26 | 27 | [consumption,u,exitflag]= fmincon(@CobbDouglas,G,P,I,[],[],lb,[],[],opts) % Note that we now HAVE to insert twice [] for the upper bound and the non-linear constraints, which do not exist. 28 | 29 | % The same results as above are reported. 30 | -------------------------------------------------------------------------------- /Exercises/Chapter 1/Chapter1iii.m: -------------------------------------------------------------------------------- 1 | % In this exercise we test our user-written code Utility2.m. The only 2 | % changes to its code compared to Utility2.m is the inclusion of a general 3 | % alpha as an input (the consumer preferences). See also Varian's 4 | % intermediate microeconomics, p. 63 (Cobb-Douglas preferences). 5 | 6 | % We first check the special case alpha=0.5. 7 | 8 | % Create a meshgrid covering the two-dimensional space [0,3] x [0,3]. 9 | 10 | [x1, x2] = meshgrid([0:3], [0:3]) 11 | 12 | 13 | u = Utility2(x1, x2, 0.5) % The utilities reported are the same as on page 16. 14 | surfc(x1, x2, u) % The figure is the same as Figure 1.1 (a) on page 17. 15 | 16 | % We can have more detailed results: 17 | 18 | [x1, x2] = meshgrid([0:0.1:3], [0:0.1:3]) 19 | 20 | u = Utility2(x1, x2, 0.5); % Output takes a lot of space in the Command Window, so it is supressed using the semicolon. 21 | surfc(x1, x2, u) % The figure is the same as Figure 1.1 (b) on page 17. 22 | 23 | % Take alpha=1: 24 | 25 | [x1, x2] = meshgrid([0:0.1:3], [0:0.1:3]) 26 | u = Utility2(x1, x2, 1) % Utilities are simply multiplied with eachother. (i.e. the utility function becomes u = x1*x2 27 | surfc(x1, x2, u) 28 | 29 | % Take alpha=0.25 30 | 31 | [x1, x2] = meshgrid([0:0.1:3], [0:0.1:3]) 32 | u = Utility2(x1, x2, 0.25) % u is overall much lower, but a lower consumption of goods already nears this maximum 5 (increasing returns) 33 | surfc(x1, x2, u) 34 | 35 | % Take alpha=0.75 36 | 37 | [x1, x2] = meshgrid([0:0.1:3], [0:0.1:3]) 38 | u = Utility2(x1, x2, 0.75) % u reaches maximum of 5, but the utilities are decreasing. 39 | surfc(x1, x2, u) -------------------------------------------------------------------------------- /Text examples/Chapter2_1.m: -------------------------------------------------------------------------------- 1 | clear; 2 | 3 | % Farmer has 75 acres to plant with two crops, wheat a or corn b. 4 | % If the farmer was unconstrained, revenue would be maximized by 5 | % continuously growing crop a according to the revenue function: 6 | 7 | % R(a,b) = 143a + 60b. 8 | 9 | % However, the farmer is in fact constrained: crop a requires more space 10 | % than crop b and the farmer only has 4000 storage units for both: 11 | 12 | % 110a + 30b <= 4000 13 | 14 | % Furthermore, the farmer only has $15,000 to spend on both crops: 15 | 16 | % 120a + 210b <= 15000 17 | 18 | % We want to answer: 19 | %{ 20 | (i) How much crop a should she plant? 21 | (ii) How much crop b should she plant? 22 | (iii) What is her optimal revenue? 23 | %} 24 | 25 | % Linprog MINIMIZES the objective function: 26 | 27 | f = [-143, -60]; % The coefficients in line 5. 28 | 29 | % Furthermore, we have in fact three constraints, line 5, 10 and 25. 30 | 31 | A = [1, 1;110, 30;120, 210] 32 | 33 | b = [75; 4000; 15000] % Note that the 75 refers to the 75 acres to be planted. 34 | 35 | % Furthermoe, we cannot plant a negative amount of crops: 36 | 37 | lb = zeros(2,1); 38 | 39 | % We request the number of crops, the revenue obtained with those crops and 40 | % the exitflag. Note we have two times [] since we do not have any strict 41 | % equality constraints as defined in (2.1). 42 | 43 | [crops, obj, exitflag] = linprog(f, A, b, [], [], lb) 44 | 45 | % Note that the value of the objective function is negative, so we need its 46 | % absolute value to determine the revenue obtained (about 632). The 47 | % exitflag '1' means a solution has been reached. 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Exercises/Chapter 2/Chapter2iii.m: -------------------------------------------------------------------------------- 1 | clear; 2 | 3 | % In this exercise, both the price of good 1 and income vary. However, they 4 | % are not independent: using the function mvnrnd, we can specify covariance 5 | % between these two variables: 6 | 7 | mu = [50,1]; % Income has mean 50, price (of good 1) has mean 1. 8 | sigma = [10,-0.9;-0.9,0.1]; % Correlation is set negative (-0.9), so a negative relationship is established between income and prices. 9 | rng default % For reproducibility of the results. 10 | r = mvnrnd(mu,sigma,100) % The columns of r are negatively correlated. 11 | 12 | plot(r(:,1),r(:,2),'+'); % Plot shows the negative relationship. 13 | reps = 100; 14 | 15 | price = [r(:,2), ones(reps, 1)]; % First column has mean 1 and variance 0.1, second price does not vary. 16 | c = NaN(reps, 2); % Allocate a matrix c to gather the consumption bundles. 17 | opts = optimset('algorithm', 'sqp', 'display', 'off'); 18 | x0 = [1, 1] % Starting value. 19 | lb = [0, 0] % Lower bound. 20 | 21 | for i = 1:reps 22 | TempI = r(i,1); % Take the first column of r, the income with mean 50 and variance. 23 | TempP = price(i,:) % Simply take the price matrix, both columns (first varies, second does not). 24 | ub = TempI./TempP; % Upper bound on the amount of goods that can be bought with income I. 25 | c(i, :) = fmincon(@CobbDouglas, x0, TempP, TempI, [], [], lb, ub, [], opts) 26 | end 27 | 28 | % Note: results are in scientific notation. 29 | -------------------------------------------------------------------------------- /Exercises/Chapter 3/Chapter3iia.m: -------------------------------------------------------------------------------- 1 | % As is well-known, the variance of an ML estimator is the inverse of the 2 | % Information matrix, which is the negative of the expected value of the 3 | % Hessian matrix. Luckily, the function fmincon provides the Hessian matrix 4 | % for us by specifically requesting it (see line 18). The standard errors 5 | % are therefore simply the square roots of the diagonal terms of the 6 | % inverted Hessian matrix. If a refresher for this is needed, read through 7 | % the following document: 8 | 9 | % https://jdemeritt.weebly.com/uploads/2/2/7/7/22771764/mle_introduction1.pdf 10 | 11 | % Simply retake the code from Chapter 3.1. and add code to request the 12 | % Hessian and compute the square root of the diagonals of its inverse. 13 | 14 | clear; 15 | DataIn = dlmread('auto.csv'); 16 | whos('DataIn') 17 | y = DataIn(:,1); 18 | X = [DataIn(:, 2:3), ones(74,1)]; 19 | 20 | 21 | lb = [-1000, -1000, -1000, 0]; 22 | ub = [1000, 1000, 1000, 100]; 23 | theta0 = [0, 0, 0, 1]; 24 | 25 | opt = optimset('TolFun',1E-20,'TolX',1E-20, 'MaxFunEvals',1000, 'algorithm', 'sqp', 'PlotFcns', 'optimplotfval'); 26 | [x,fval,exitflag,output,lambda,grad,hessian] = fmincon(@(theta)NormalML(theta,y,X), theta0, [], [], [], [], lb, ub, [], opt) 27 | 28 | err = sqrt(diag(inv(hessian))) 29 | 30 | % The standard errors are roughly equal but a bit smaller than the results 31 | % reported by OLS on page 6. Econometrically, the variance of the estimator 32 | % is in fact the lowest variance an unbiased estimator of theta can achieve 33 | % (partakers in econometrics courses will remember this lower bound being 34 | % called the 'Cramer-Rao lower bound'. Maximum likelihood estimation is 35 | % therefore efficient. 36 | 37 | 38 | -------------------------------------------------------------------------------- /Exercises/Chapter 4/Chapter4ii.m: -------------------------------------------------------------------------------- 1 | % Retake the code from 4.1 2 | clear; 3 | rng(50) % We set the seed. 4 | N = 1000; % 1000 observations. 5 | Beta = [0.5, 0.5]'; % Our true Betas. 6 | income = randn(N, 1) % Generate normally distributed random numbers for income. 7 | x = [ones(N, 1), income] % Conjoin them with a vector of constants (ones). 8 | [y, utility] = SimulateBinaryLogit(x, Beta) % Notice we simply receive the y-values here. 9 | 10 | R = 2000; % Set the number of replications. 11 | Beta_init = [0; 0]; % Initial Betas. 12 | lb = [-10; -10]; % Here we simply restrict the domain over which the function searched. 13 | ub = [10; 10]; % Because of these upper and lower bounds, we have to use fmincon. 14 | opts2 = optimset('Algorithm', 'sqp', 'DiffMinChange', 1e-2); % Set the algorithm to SQP (see above) and the smallest change the function can make (the SLL is flat in the local domain). 15 | 16 | [EstBetaMSL, LL, exitflag] = fmincon(@(parameters) BinaryLogitSimulatedLL(parameters, y, x, R), Beta_init, [], [], [],[], lb, ub, [], opts2) 17 | 18 | % Now try adjusting the values for N and R. Note, it may take a while 19 | % before MATLAB returns EstBetaMSL. The results for this particular seed 20 | % were: 21 | 22 | % N = 1000 and R = 1000 23 | % 0.4709 0.4625 24 | % N = 2000 and R = 1000 25 | % 0.4994 0.4555 26 | % N = 1000 and R = 2000 27 | % 0.5346 0.4322 28 | 29 | % It seems the number of observations is numerically the most important: it 30 | % appears to closely approximate the true parameter. Increasing the number 31 | % of simulations does not appear to help much (by stroke of bad luck, it 32 | % even worsens the estimates). 33 | -------------------------------------------------------------------------------- /Exercises/Chapter 3/Chapter3i.m: -------------------------------------------------------------------------------- 1 | % In this exercise, we use our new probitML.m function to replicate the 2 | % results of a probit analysis carried out in Stata. Specifically, a probit 3 | % analysis has been run for a car being foreign or not, depending on its 4 | % length and weight (and a constant). Run 'probit foreign length weight' in 5 | % Stata and take note of its results. 6 | 7 | % Note that a new file (we call it auto2.csv) needs to be exported from 8 | % Stata with these variables using: 'export delimited foreign length weight using auto2.csv, novarnames nolabel'. 9 | % That last option is important, because otherwise we would have the labels 10 | % of the 'foreign' variable instead of the actual values, which would result 11 | % in an error in line 16. 12 | 13 | % We can then read-in the data. 14 | 15 | clear; 16 | DataIn = dlmread('auto2.csv'); 17 | whos('DataIn') 18 | y = DataIn(:,1); % Take first column and call it y. 19 | X = [DataIn(:, 2:3), ones(74,1)]; % Take second and third column and join them with a vector of ones. : denotes that every row is taken (a constant is included). 20 | 21 | % Some initial guesses for the Betas: 22 | 23 | Beta0 = [0, 0, 0]; % Set up some initial guess. 24 | 25 | % Define a domain to search over: 26 | 27 | lb = [-1000, -1000, -1000]; 28 | ub = [1000, 1000, 1000]; 29 | 30 | % Define the options: 31 | 32 | opt = optimset('TolFun',1E-20,'TolX',1E-20, 'MaxFunEvals',1000); % Set up the options. We keep the function running until the changes in the objective function AND the optimands are very small. The objective function is evaluated for a maximum 1000 number of times. 33 | 34 | fmincon(@(Beta)ProbitML(Beta,y,X), Beta0, [], [], [], [], lb, ub, [], opt) 35 | 36 | % Check that the estimates correspond to Stata's output (the output should 37 | % be 0.0016 -0.0015 3.4895). 38 | 39 | % We can do a final check with Lesage's probit function: 40 | res = probit(y, X) 41 | prt(res) 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Text examples/Chapter3_1.m: -------------------------------------------------------------------------------- 1 | % We use fmincon to maximize the likelihood function (3.1). We are looking 2 | % for a vector Beta, Var which maximizes this function (remember that 3 | % fmincon only accepts a vector to optimize. See the function NormalML how 4 | % the likelihood function is calculated. 5 | 6 | % We again use the auto.csv example from Chapter 1: 7 | 8 | clear; 9 | DataIn = dlmread('auto.csv'); % We import the data sheet. We name this imported data DataIn. 10 | whos('DataIn') 11 | y = DataIn(:,1); % Take first column and call it y. 12 | X = [DataIn(:, 2:3), ones(74,1)]; % Take second and third column and join them with a vector of ones. : denotes that every row is taken. 13 | 14 | % There are no real upper or lower bounds, but we can restrict a domain 15 | % over which the function searches. Here, we estimate the three betas from 16 | % auto.csv and the variance. Remember that the variance is larger than 0. 17 | 18 | lb = [-1000, -1000, -1000, 0]; 19 | ub = [1000, 1000, 1000, 100]; 20 | theta0 = [0, 0, 0, 1]; % Set up some initial guess. 21 | 22 | opt = optimset('TolFun',1E-20,'TolX',1E-20, 'MaxFunEvals',1000, 'algorithm', 'sqp', 'PlotFcns', 'optimplotfval'); % Set up the options. We keep the function running until the changes in the objective function AND the optimands are very small. The objective function is evaluated for a maximum 1000 number of times. 23 | 24 | fmincon(@(theta)NormalML(theta,y,X), theta0, [], [], [], [], lb, ub, [], opt) % No non-linear constraints, no strict constraints and no regular constraints. The constraint of var>0 is contained within the lower and upper bounds. 25 | 26 | % Note that we now declare one of the function inputs to be a choice 27 | % variable; theta. We minimize the function NormalML GIVEN y and X with 28 | % choice variable theta. Note we included the PlotFcns as the text 29 | % suggested, which shows the function value (the log-likelihood) as a 30 | % function of the iterations. 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Exercises/Chapter 2/Chapter2ii.m: -------------------------------------------------------------------------------- 1 | % We simulate a random variation of income to be allocated across goods x1 2 | % and x2. We take p1=1 and p2=1. 3 | 4 | clear; 5 | 6 | reps = 100; % Choices of 100 individuals. 7 | Ishock = rand(reps, 1)*50 % Model the shock to income. 8 | x0 = [1, 1]; % Starting values for good 1 and good 2. 9 | P = [1, 1]; % Fixed prices. 10 | lb = [0, 0]; % Lower bound. 11 | c = NaN(reps, 2) % Where optimized consumption will end up in. 12 | I = 50 % Income is set to 50, so when the shock is applied, the income is U[50,100] (similar to the textbook). 13 | opts = optimset('algorithm', 'sqp', 'display', 'off'); % Same options as ConsumptionSim. 14 | Inc = NaN(reps, 1) % Allocate space to save the income variation in. 15 | 16 | for i = 1:reps % For each individual (1 to 100). 17 | TempI = I + Ishock(i, :); % Introduce the shock to the income. 18 | Inc(i) = TempI % We save the income for later use in the Engel curves. 19 | ub = TempI./P % Define the upper bound. 20 | c(i, :) = fmincon(@CobbDouglas, x0, P, TempI, [], [], lb, ub, [], opts) 21 | end 22 | 23 | % The result should be optimized amounts of consumption. Note that their 24 | % sums add up to an income between 50 and 100 (since prices are taken to be 25 | % unity). 26 | 27 | % Plot the Engel curves for both goods, which shows how demand changes 28 | % (holding prices fixed) when income changes. 29 | 30 | % Engel curve for x1: 31 | 32 | subplot(1, 2, 1) 33 | scatter(c(:,1), Inc) 34 | xlabel('Good 1 Consumption') 35 | ylabel('Income') 36 | 37 | % Engel curve for x2: 38 | 39 | subplot(1, 2, 1) 40 | scatter(c(:,2), Inc) 41 | xlabel('Good 2 Consumption') 42 | ylabel('Income') 43 | 44 | % These of course look exactly the same. 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Exercises/Chapter 4/Chapter4vi.m: -------------------------------------------------------------------------------- 1 | % Note, remember to use the fixed version of BinaryLogitLL. 2 | 3 | clear; 4 | 5 | rng(1) 6 | N = 1000; % 1000 observations. 7 | Beta = [0.5, 0.5]'; % Our true Betas. 8 | income = randn(N, 1) % Generate normally distributed random numbers for income. 9 | x = [ones(N, 1), income] % Conjoin them with a vector of constants (ones). 10 | 11 | y = SimulateBinaryLogit(x, Beta) % Notice we simply receive the y-values here. 12 | 13 | options = optimset('Algorithm', 'sqp', 'Display', 'iter'); % We set up some options: iter displays output at each iteration, and the iterative method is a sequential quadratic programming algorithm (see https://en.wikipedia.org/wiki/Sequential_quadratic_programming). 14 | Beta_init = [0; 0]; % Initial Betas. 15 | lb = [-10; -10]; % Here we simply restrict the domain over which the function searched. 16 | ub = [10; 10]; % Because of these upper and lower bounds, we have to use fmincon. 17 | 18 | 19 | [EstBetaML, LL, exitflag] = fmincon(@(beta) BinaryLogitLL(beta, y, x), Beta_init, [], [], [], [], lb, ub, [], options) 20 | 21 | % A challenge actually lies in retrieving LL_i from fmincon. There is no 22 | % command in its syntax for retrieving it. However, remember that we can 23 | % simply use the objective function itself with the estimated betas (under 24 | % these betas, the sum of likelihoods is minimal!). 25 | 26 | [LL, ll_i] = BinaryLogitLL(EstBetaML, y, x) 27 | 28 | % There should now be a 1000x1 matrix with all individual likelihoods 29 | % called ll_i. This is ll_i under the analytical expression (4.9). Now call 30 | % ll_i from the simulated function: 31 | 32 | R = 1000; % Set the number of replications. 33 | opts2 = optimset('Algorithm', 'sqp', 'DiffMinChange', 1e-2); % Set the algorithm to SQP (see above) and the smallest change the function can make (the SLL is flat in the local domain). 34 | 35 | [EstBetaMSL, LL, exitflag] = fmincon(@(beta) BinaryLogitSimulatedLL(beta, y, x, R), Beta_init, [], [], [],[], lb, ub, [], opts2) 36 | 37 | % Extract Sll_i: 38 | 39 | [LL, Sll_i] = BinaryLogitSimulatedLL(EstBetaMSL, y, x, R) 40 | 41 | % Produce scatterplot. 42 | 43 | scatter(ll_i, Sll_i) 44 | 45 | % Note that the relationship is near linear with a bit of dispersion. 46 | 47 | % Try increasing R to say, 2000. Notice how this dispersion becomes 48 | % smaller; the analytical likelihood and the simulated likelihood will be 49 | % more equal. 50 | 51 | -------------------------------------------------------------------------------- /Exercises/Chapter 4/Chapter4iii_v.m: -------------------------------------------------------------------------------- 1 | % Exercise iii % 2 | %--------------% 3 | 4 | % We can simply adapt use the author's code, SimulateMNlogit. An oft-made 5 | % mistake here is having 6 elements in Beta, while in fact there should be 6 | % only 4 (remember we defined utility in relative terms. For some reason, 7 | % readers also sometimes use 3 Betas. This will 8 | % give an error, specifically when using the reshape-function in the code. 9 | % Notice that the calculation for J in that code (line 5) 10 | % gives J = 3, the number of choices we are considering. 11 | 12 | clear; 13 | rng(50) % We set the seed. 14 | N = 2000; % 2000 observations. 15 | Beta = [0.5, 0.5, 0.5, 0.5]'; % Our true Betas. Note we now also add a third 0.5 (say, alpha_13 in (4.17)). Adding another fourth choice requires adding another true value for beta. 16 | income = randn(N, 1) % Generate normally distributed random numbers for income. 17 | x = [ones(N, 1), income] % Conjoin them with a vector of constants (ones). 18 | 19 | % Calculating the y's and respective utilities is straightforward. 20 | 21 | [y, utility] = SimulateMNLogit(x, Beta) 22 | 23 | % To be sure, check that y is indeed 1, 2 or 3. 24 | 25 | %%% Exercise iv %%% 26 | %-----------------% 27 | % Now we can estimates the coefficients from ML. We use the author's code, 28 | % MNlogitLL.m. Doing this is 29 | % straightforward, it simply requires using the function MNLogitLL.m. 30 | % Remember to rewrite the initial Betas, the lower and upper bounds. 31 | 32 | options = optimset('Algorithm', 'sqp', 'Display', 'iter'); % We set up some options: iter displays output at each iteration, and the iterative method is a sequential quadratic programming algorithm (see https://en.wikipedia.org/wiki/Sequential_quadratic_programming). 33 | Beta_init = [0; 0; 0; 0]; % Initial Betas. 34 | lb = [-10; -10; -10; -10]; % Here we simply restrict the domain over which the function searched. 35 | ub = [10; 10; 10; 10]; % Because of these upper and lower bounds, we have to use fmincon. 36 | 37 | [EstBetaML, LL, exitflag] = fmincon(@(parameters) MNLogitLL(parameters, y, x), Beta_init, [], [], [], [], lb, ub, [], options) 38 | 39 | % If everything went well, you should get something close to 0.50 for every 40 | % Beta. 41 | 42 | % Exercise v % 43 | %------------% 44 | 45 | % Finally, use MNLogitSimulatedLL.m to recover the parameters of a 46 | % simulated likelihood function. Again,adapting the author's code is 47 | % straightforward. NOTE: WE ARE DOING 1000 REPLICATIONS ON 2000 48 | % OBSERVATIONS FOR 4 PARAMETERS: THIS FUNCTION WILL TAKE QUITE A LONG TIME 49 | % TO GENERATE OUTPUT. 50 | 51 | R = 1000; % Set the number of replications. 52 | opts2 = optimset('Algorithm', 'sqp', 'DiffMinChange', 1e-2); % Set the algorithm to SQP (see above) and the smallest change the function can make (the SLL is flat in the local domain). 53 | 54 | [EstBetaMSL, LL, exitflag] = fmincon(@(beta) MNLogitSimulatedLL(beta, y, x, R), Beta_init, [], [], [],[], lb, ub, [], opts2) 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Text examples/Chapter4_1.m: -------------------------------------------------------------------------------- 1 | % We generate our own fake dataset to test of binary logit estimator. 2 | % Notice we seed the random number generator, meaning that a predictable 3 | % sequence of random numbers is generated each time. 4 | 5 | clear; 6 | rng(1) % We set the seed. 7 | N = 1000; % 1000 observations. 8 | Beta = [0.5, 0.5]'; % Our true Betas. 9 | income = randn(N, 1) % Generate normally distributed random numbers for income. 10 | x = [ones(N, 1), income] % Conjoin them with a vector of constants (ones). 11 | 12 | 13 | % Taking a look at SimulateBinaryLogit.m, we get an output (y) and the 14 | % utility as dictated by the equations on page 43. Notice line 17: 15 | % epsilon = -log(-log(rand(N, J))); 16 | % It draws from the Type 1 extreme value distribution (compare with 17 | % Equation (4.5). We can test this estimator on our simulated data: 18 | 19 | y = SimulateBinaryLogit(x, Beta) % Notice we simply receive the y-values here. 20 | 21 | % We can now proceed to estimation. The function BinaryLogitLL.m evaluates 22 | % Equation (4.9). Notice that in its code, we define the logistic cdf as in 23 | % Equation (4.6). We can now try to find the ML paramaters of such a binary 24 | % logit model. Warning: the author's code for BinaryLogitLL is incomplete, 25 | % use the updated one from Github. 26 | 27 | options = optimset('Algorithm', 'sqp', 'Display', 'iter'); % We set up some options: iter displays output at each iteration, and the iterative method is a sequential quadratic programming algorithm (see https://en.wikipedia.org/wiki/Sequential_quadratic_programming). 28 | Beta_init = [0; 0]; % Initial Betas. 29 | lb = [-10; -10]; % Here we simply restrict the domain over which the function searched. 30 | ub = [10; 10]; % Because of these upper and lower bounds, we have to use fmincon. 31 | 32 | 33 | [EstBetaML, LL, exitflag] = fmincon(@(parameters) BinaryLogitLL(parameters, y, x), Beta_init, [], [], [], [], lb, ub, [], options) 34 | 35 | % Notice we look for the optimal parameters (Beta in BinaryLogitLL). Seeing 36 | % as the numbers are randomly generated, you will get different results 37 | % than the ones on page 45. Removing the seed on line 6 will give different 38 | % results each time. 39 | 40 | % Next, suppose an analytical expression is not possible for the 41 | % log-likelihood as in equation (4.9). The solution is estimating by 42 | % simulation. The choice in y depends on observable behaviour (x) and the 43 | % parameters associated with it (Beta). We can try and estimate B such that 44 | % the simulated data x will look like real data. We assume here to have a 45 | % fully parametric model (we know the distribution of our unobservable, in 46 | % fact, we know it has a logistic distribution as given in (4.6). With 47 | % this assumption in mind, we can estimate by Maximum Simulated 48 | % likelihood. Instead of then using the analytical expression (4.9) to 49 | % calculate probabilities, we instead use sample probabilities generated 50 | % from the simulated data. We define a new scalar, R, which tells us the 51 | % number of replications of such a simulation algorithm. Note for a 52 | % respondent i we simulate conditional on the values of x and receive a 53 | % binary outcome y (up until replication R). The simulated expression is 54 | % then (4.10). The BinaryLogitSimulatedLL.m function achieves this (note, 55 | % the code is a bit messier than the one in the book, but it works): 56 | 57 | R = 1000; % Set the number of replications. 58 | opts2 = optimset('Algorithm', 'sqp', 'DiffMinChange', 1e-2); % Set the algorithm to SQP (see above) and the smallest change the function can make (the SLL is flat in the local domain). 59 | 60 | [EstBetaMSL, LL, exitflag] = fmincon(@(parameters) BinaryLogitSimulatedLL(parameters, y, x, R), Beta_init, [], [], [],[], lb, ub, [], opts2) 61 | 62 | 63 | 64 | 65 | 66 | 67 | --------------------------------------------------------------------------------