1function [Res] = update_nowcast(X_old,X_new,Time,Spec,Res,series,period,vintage_old,vintage_new) 2 3 4if ~isnumeric(vintage_old) 5 vintage_old = datenum(vintage_old,'yyyy-mm-dd'); 6end 7if ~isnumeric(vintage_new) 8 vintage_new = datenum(vintage_new,'yyyy-mm-dd'); 9end 10 11% Make sure datasets are the same size 12N = size(X_new,2); 13T_old = size(X_old,1); T_new = size(X_new,1); 14if T_new > T_old 15 X_old = [X_old; NaN(T_new-T_old,N)]; 16end 17% append 1 year (12 months) of data to each dataset to allow for 18% forecasting at different horizons 19X_old = [X_old; NaN(12,N)]; 20X_new = [X_new; NaN(12,N)]; 21 22[y, m, d] = datevec(Time(end)); 23 24Time = [Time; datenum(y,(m+1:m+12)',d)]; 25 26i_series = find(strcmp(series,Spec.SeriesID)); 27 28series_name = Spec.SeriesName{i_series}; 29freq = Spec.Frequency{i_series}; 30 31switch freq 32 case 'm' 33 [y,m] = strtok(period,freq); 34 y = str2double(y); 35 m = str2double(strrep(m,freq,'')); 36 d = 1; 37 t_nowcast = find(Time==datenum(y,m,d)); 38 case 'q' 39 [y,q] = strtok(period,freq); 40 y = str2double(y); 41 q = str2double(strrep(q,freq,'')); 42 m = 3*q; 43 d = 1; 44 t_nowcast = find(Time==datenum(y,m,d)); 45end 46 47if isempty(t_nowcast) 48 error('Period is out of nowcasting horizon (up to one year ahead).'); 49end 50 51 52 53% Update nowcast for target variable 'series' (i) at horizon 'period' (t) 54% > Relate nowcast update into news from data releases: 55% a. Compute the impact from data revisions 56% b. Compute the impact from new data releases 57 58 59X_rev = X_new; 60X_rev(isnan(X_old)) = NaN; 61 62% Compute news -------------------------------------------------------- 63 64% Compute impact from data revisions 65[y_old] = News_DFM(X_old,X_rev,Res,t_nowcast,i_series); 66 67% Compute impact from data releases 68[y_rev,y_new,~,actual,forecast,weight] = News_DFM(X_rev,X_new,Res,t_nowcast,i_series); 69 70% Display output 71fprintf('\n\n\n'); 72fprintf('Nowcast Update: %s \n', datestr(vintage_new, 'mmmm dd, yyyy')) 73fprintf('Nowcast for %s (%s), %s \n',Spec.SeriesName{i_series},Spec.UnitsTransformed{i_series},datestr(Time(t_nowcast),'YYYY:QQ')); 74 75if(isempty(forecast)) % Only display table output if a forecast is made 76 fprintf('\n No forecast was made.\n') 77else 78 79 impact_revisions = y_rev - y_old; % Impact from revisions 80 news = actual - forecast; % News from releases 81 impact_releases = weight .* (news); % Impact of releases 82 83 % Store results 84 news_table = array2table([forecast, actual, weight, impact_releases],... 85 'VariableNames', {'Forecast', 'Actual', 'Weight', 'Impact'},... 86 'RowNames', Spec.SeriesID); 87 88 % Select only series with updates 89 data_released = any(isnan(X_old) & ~isnan(X_new), 1); 90 91 % Display the impact decomposition 92 fprintf('\n Nowcast Impact Decomposition \n') 93 fprintf(' Note: The displayed output is subject to rounding error\n\n') 94 fprintf(' %s nowcast: %5.2f\n', ... 95 datestr(vintage_old, 'mmm dd'), y_old) 96 fprintf(' Impact from data revisions: %5.2f\n', impact_revisions) 97 fprintf(' Impact from data releases: %5.2f\n', sum(news_table.Impact,'omitnan')) 98 fprintf(' +_________\n') 99 fprintf(' Total impact: %5.2f\n', ... 100 impact_revisions + sum(news_table.Impact,'omitnan')) 101 fprintf(' %s nowcast: %5.2f\n\n', ... 102 datestr(vintage_new, 'mmm dd'), y_new) 103 104 % Display the table output 105 fprintf('\n Nowcast Detail Table \n\n') 106 disp(news_table(data_released, :)) 107 108 109 % Output results to structure 110 Res.impact_revisions = impact_revisions; 111 Res.weight = weight; 112 Res.news_table = news_table; 113 114end 115 116end 117 118 119function [y_old,y_new,singlenews,actual,forecast,weight,t_miss,v_miss,innov] = News_DFM(X_old,X_new,Res,t_fcst,v_news) 120%News_DFM() Calculates changes in news 121% 122% Syntax: 123% [y_old, y_new, singlenews, actual, fore, weight ,t_miss, v_miss, innov] = ... 124% News_DFM(X_old, X_new, Q, t_fcst, v_news) 125% 126% Description: 127% News DFM() inputs two datasets, DFM parameters, target time index, and 128% target variable index. The function then produces Nowcast updates and 129% decomposes the changes into news. 130% 131% Input Arguments: 132% X_old: Old data matrix (old vintage) 133% X_new: New data matrix (new vintage) 134% Res: DFM() output results (see DFM for more details) 135% t_fcst: Index for target time 136% v_news: Index for target variable 137% 138% Output Arguments: 139% y_old: Old nowcast 140% y_new: New nowcast 141% single_news: News for each data series 142% actual: Observed series release values 143% fore: Forecasted series values 144% weight: News weight 145% t_miss: Time index for data releases 146% v_miss: Series index for data releases 147% innov: Difference between observed and predicted series values ("innovation") 148 149%% Initialize variables 150 151r = size(Res.C,2); 152[~, N] = size(X_new); 153singlenews = zeros(1,N); % Initialize news vector (will store news for each series) 154 155%% NO FORECAST CASE: Already values for variables v_news at time t_fcst 156 157if ~isnan(X_new(t_fcst,v_news)) 158 Res_old = para_const(X_old, Res, 0); % Apply Kalman filter for old data 159 160 161 for i=1:size(v_news,2) % Loop for each target variable 162 % (Observed value) - (predicted value) 163 singlenews(:,v_news(i)) = X_new(t_fcst,v_news(i)) ... 164 - Res_old.X_sm(t_fcst,v_news(i)); 165 166 % Set predicted and observed y values 167 y_old(1,i) = Res_old.X_sm(t_fcst,v_news(i)); 168 y_new(1,i) = X_new(t_fcst,v_news(i)); 169 end 170 171 % Forecast-related output set to empty 172 actual=[];forecast=[];weight=[];t_miss=[];v_miss=[];innov=[]; 173 174 175else 176 %% FORECAST CASE (these are broken down into (A) and (B)) 177 178 % Initialize series mean/standard deviation respectively 179 Mx = Res.Mx; 180 Wx = Res.Wx; 181 182 % Calculate indicators for missing values (1 if missing, 0 otherwise) 183 miss_old=isnan(X_old); 184 miss_new=isnan(X_new); 185 186 % Indicator for missing--combine above information to single matrix where: 187 % (i) -1: Value is in the old data, but missing in new data 188 % (ii) 1: Value is in the new data, but missing in old data 189 % (iii) 0: Values are missing from/available in both datasets 190 i_miss = miss_old - miss_new; 191 192 % Time/variable indicies where case (b) is true 193 [t_miss,v_miss]=find(i_miss==1); 194 195 %% FORECAST SUBCASE (A): NO NEW INFORMATION 196 197 if isempty(v_miss) 198 % Fill in missing variables using a Kalman filter 199 Res_old = para_const(X_old, Res, 0); 200 Res_new = para_const(X_new, Res, 0); 201 202 % Set predicted and observed y values. New y value is set to old 203 y_old = Res_old.X_sm(t_fcst,v_news); 204 y_new = y_old; 205 % y_new = Res_new.X_sm(t_fcst,v_news); 206 207 % No news, so nothing returned for news-related output 208 groupnews=[];singlenews=[];gain=[];gainSer=[]; 209 actual=[];forecast=[];weight=[];t_miss=[];v_miss=[];innov=[]; 210 else 211 %---------------------------------------------------------------------- 212 % v_miss=[1:size(X_new,2)]'; 213 % t_miss=t_miss(1)*ones(size(X_new,2),1); 214 %---------------------------------------------------------------------- 215 %% FORECAST SUBCASE (B): NEW INFORMATION 216 217 % Difference between forecast time and new data time 218 lag = t_fcst-t_miss; 219 220 % Gives biggest time interval between forecast and new data 221 k = max([abs(lag); max(lag)-min(lag)]); 222 223 C = Res.C; % Observation matrix 224 R = Res.R'; % Covariance for observation matrix residuals 225 226 % Number of new events 227 n_news = size(lag,1); 228 229 % Smooth old dataset 230 Res_old = para_const(X_old, Res, k); 231 Plag = Res_old.Plag; 232 233 % Smooth new dataset 234 Res_new = para_const(X_new, Res, 0); 235 236 % Subset for target variable and forecast time 237 y_old = Res_old.X_sm(t_fcst,v_news); 238 y_new = Res_new.X_sm(t_fcst,v_news); 239 240 241 242 P = Res_old.P(:,:,2:end); 243 P1=[]; % Initialize projection onto updates 244 245 % Cycle through total number of updates 246 for i=1:n_news 247 h = abs(t_fcst-t_miss(i)); 248 m = max([t_miss(i) t_fcst]); 249 250 % If location of update is later than the forecasting date 251 if t_miss(i)>t_fcst 252 Pp=Plag{h+1}(:,:,m); %P(1:r,h*r+1:h*r+r,m)'; 253 else 254 Pp=Plag{h+1}(:,:,m)'; %P(1:r,h*r+1:h*r+r,m); 255 end 256 P1=[P1 Pp*C(v_miss(i),1:r)']; % Projection on updates 257 end 258 259 for i=1:size(t_miss,1) 260 % Standardize predicted and observed values 261 X_new_norm = (X_new(t_miss(i),v_miss(i)) - Mx(v_miss(i)))./Wx(v_miss(i)); 262 X_sm_norm = (Res_old.X_sm(t_miss(i),v_miss(i))- Mx(v_miss(i)))./Wx(v_miss(i)); 263 264 % Innovation: Gives [observed] data - [predicted data] 265 innov(i)= X_new_norm - X_sm_norm; 266 end 267 268 ins=size(innov,2); 269 P2=[]; 270 p2=[]; 271 272 % Gives non-standardized series weights 273 for i=1:size(lag,1) 274 for j=1:size(lag,1) 275 h=abs(lag(i)-lag(j)); 276 m=max([t_miss(i),t_miss(j)]); 277 278 if t_miss(j)>t_miss(i) 279 Pp=Plag{h+1}(:,:,m); %P(1:r,h*r+1:(h+1)*r,m)'; 280 else 281 Pp=Plag{h+1}(:,:,m)'; %P(1:r,h*r+1:(h+1)*r,m); 282 end 283 if v_miss(i)==v_miss(j) & t_miss(i)~=t_miss(j) 284 WW(v_miss(i),v_miss(j))=0; 285 else 286 WW(v_miss(i),v_miss(j))=R(v_miss(i),v_miss(j)); 287 end 288 p2=[p2 C(v_miss(i),1:r)*Pp*C(v_miss(j),1:r)'+WW(v_miss(i),v_miss(j))]; 289 end 290 P2=[P2;p2]; 291 p2=[]; 292 end 293 294 clear temp 295 for i=1:size(v_news,2) % loop on v_news 296 % Convert to real units (unstadardized data) 297 totnews(1,i) = Wx(v_news(i))*C(v_news(i),1:r)*P1*inv(P2)*innov'; 298 temp(1,:,i) = Wx(v_news(i))*C(v_news(i),1:r)*P1*inv(P2).*innov; 299 gain(:,:,i) = Wx(v_news(i))*C(v_news(i),1:r)*P1*inv(P2); 300 end 301 302 % Initialize output objects 303 singlenews = NaN(max(t_miss)-min(t_miss)+1,N); %,size(v_news,2) 304 actual = NaN(N,1); % Actual forecasted values 305 forecast = NaN(N,1); % Forecasted values 306 weight = NaN(N,1,size(v_news,2)); 307 308 % Fill in output values 309 for i=1:size(innov,2) 310 actual(v_miss(i),1) = X_new(t_miss(i),v_miss(i)); 311 forecast(v_miss(i),1) = Res_old.X_sm(t_miss(i),v_miss(i)); 312 313 for j=1:size(v_news,2) 314 singlenews(t_miss(i)-min(t_miss)+1,v_miss(i),j) = temp(1,i,j); 315 weight(v_miss(i),:,j) = gain(:,i,j)/Wx(v_miss(i)); 316 end 317 end 318 319 singlenews = sum(singlenews,1); % Returns total news 320 321 322 [v_miss, ~, ~] = unique(v_miss); 323 324end 325 326end 327 328end 329 330function Res = para_const(X, P, lag) 331%para_const() Implements Kalman filter for "News_DFM.m" 332% 333% Syntax: 334% Res = para_const(X,P,lag) 335% 336% Description: 337% para_const() implements the Kalman filter for the news calculation 338% step. This procedure smooths and fills in missing data for a given 339% data matrix X. In contrast to runKF(), this function is used when 340% model parameters are already estimated. 341% 342% Input parameters: 343% X: Data matrix. 344% P: Parameters from the dynamic factor model. 345% lag: Number of lags 346% 347% Output parameters: 348% Res [struc]: A structure containing the following: 349% Res.Plag: Smoothed factor covariance for transition matrix 350% Res.P: Smoothed factor covariance matrix 351% Res.X_sm: Smoothed data matrix 352% Res.F: Smoothed factors 353% 354 355 356% Kalman filter with specified paramaters 357% written for 358% "MAXIMUM LIKELIHOOD ESTIMATION OF FACTOR MODELS ON DATA SETS WITH 359% ARBITRARY PATTERN OF MISSING DATA." 360% by Marta Banbura and Michele Modugno 361 362%% Set model parameters and data preparation 363 364% Set model parameters 365Z_0 = P.Z_0; 366V_0 = P.V_0; 367A = P.A; 368C = P.C; 369Q = P.Q; 370R = P.R; 371Mx = P.Mx; 372Wx = P.Wx; 373 374% Prepare data 375[T,~] = size(X); 376 377% Standardise x 378Y = ((X-repmat(Mx,T,1))./repmat(Wx,T,1))'; 379 380%% Apply Kalman filter and smoother 381% See runKF() for details about FIS and SKF 382 383Sf = SKF(Y, A, C, Q, R, Z_0, V_0); % Kalman filter 384 385Ss = FIS(A, Sf); % Smoothing step 386 387%% Calculate parameter output 388Vs = Ss.VmT(:,:,2:end); % Smoothed factor covariance for transition matrix 389Vf = Sf.VmU(:,:,2:end); % Filtered factor posterior covariance 390Zsmooth = Ss.ZmT; % Smoothed factors 391Vsmooth = Ss.VmT; % Smoothed covariance values 392 393Plag{1} = Vs; 394 395for jk = 1:lag 396 for jt = size(Plag{1},3):-1:lag+1 397 As = Vf(:,:,jt-jk)*A'*pinv(A*Vf(:,:,jt-jk)*A'+Q); 398 Plag{jk+1}(:,:,jt) = As*Plag{jk}(:,:,jt); 399 end 400end 401 402% Prepare data for output 403Zsmooth=Zsmooth'; 404x_sm = Zsmooth(2:end,:)*C'; % Factors to series representation 405X_sm = repmat(Wx,T,1).*x_sm+repmat(Mx,T,1); % Standardized to unstandardized 406 407%-------------------------------------------------------------------------- 408% Loading the structure with the results 409%-------------------------------------------------------------------------- 410Res.Plag = Plag; 411Res.P = Vsmooth; 412Res.X_sm = X_sm; 413Res.F = Zsmooth(2:end,:); 414 415end 416 417 418%______________________________________________________________________ 419function S = SKF(Y, A, C, Q, R, Z_0, V_0) 420%SKF Applies Kalman filter 421% 422% Syntax: 423% S = SKF(Y, A, C, Q, R, Z_0, V_0) 424% 425% Description: 426% SKF() applies a Kalman filter. This is a bayesian algorithm. Looping 427% forward in time, a 'prior' estimate is calculated from the previous 428% period. Then, using the observed data, a 'posterior' value is obtained. 429% 430% Input parameters: 431% y: Input data. 432% A: Transition matrix coefficients. 433% C: Observation matrix coefficients. 434% Q: Covariance matrix (factors and idiosyncratic component) 435% R: Variance-Covariance for observation equation residuals 436% Z_0: Initial factor values 437% V_0: Initial factor covariance matrix 438% 439% Output parameters: 440% S.Zm: Prior/predicted factor state vector (Z_t|t-1) 441% S.ZmU: Posterior/updated state vector (Z_t|t) 442% S.Vm: Prior/predicted covariance of factor state vector (V_t|t-1) 443% S.VmU: Posterior/updated covariance of factor state vector (V_t|t) 444% S.loglik: Value of likelihood function 445% S.k_t: Kalman gain 446% 447% Model: 448% Y_t = C_t Z_t + e_t, e_t ~ N(0, R) 449% Z_t = A Z_{t-1} + mu_t, mu_t ~ N(0, Q) 450 451%% INSTANTIATE OUTPUT VALUES --------------------------------------------- 452 % Output structure & dimensions of state space matrix 453 [~, m] = size(C); 454 455 % Outputs time for data matrix. "number of observations" 456 nobs = size(Y,2); 457 458 % Initialize output 459 S.Zm = NaN(m, nobs); % Z_t | t-1 (prior) 460 S.Vm = NaN(m, m, nobs); % V_t | t-1 (prior) 461 S.ZmU = NaN(m, nobs+1); % Z_t | t (posterior/updated) 462 S.VmU = NaN(m, m, nobs+1); % V_t | t (posterior/updated) 463 S.loglik = 0; 464 465%% SET INITIAL VALUES ---------------------------------------------------- 466 Zu = Z_0; % Z_0|0 (In below loop, Zu gives Z_t | t) 467 Vu = V_0; % V_0|0 (In below loop, Vu guvse V_t | t) 468 469 % Store initial values 470 S.ZmU(:,1) = Zu; 471 S.VmU(:,:,1) = Vu; 472 473%% KALMAN FILTER PROCEDURE ---------------------------------------------- 474 for t = 1:nobs 475 %%% CALCULATING PRIOR DISTIBUTION---------------------------------- 476 477 % Use transition eqn to create prior estimate for factor 478 % i.e. Z = Z_t|t-1 479 Z = A * Zu; 480 481 % Prior covariance matrix of Z (i.e. V = V_t|t-1) 482 % Var(Z) = Var(A*Z + u_t) = Var(A*Z) + Var(\epsilon) = 483 % A*Vu*A' + Q 484 V = A * Vu* A' + Q; 485 V = 0.5 * (V+V'); % Trick to make symmetric 486 487 %%% CALCULATING POSTERIOR DISTRIBUTION ---------------------------- 488 489 % Removes missing series: These are removed from Y, C, and R 490 [Y_t, C_t, R_t, ~] = MissData(Y(:,t), C, R); 491 492 % Check if y_t contains no data. If so, replace Zu and Vu with prior. 493 if isempty(Y_t) 494 Zu = Z; 495 Vu = V; 496 else 497 % Steps for variance and population regression coefficients: 498 % Var(c_t*Z_t + e_t) = c_t Var(A) c_t' + Var(u) = c_t*V *c_t' + R 499 VC = V * C_t'; 500 iF = inv(C_t * VC + R_t); 501 502 % Matrix of population regression coefficients (QuantEcon eqn #4) 503 VCF = VC*iF; 504 505 % Gives difference between actual and predicted observation 506 % matrix values 507 innov = Y_t - C_t*Z; 508 509 % Update estimate of factor values (posterior) 510 Zu = Z + VCF * innov; 511 512 % Update covariance matrix (posterior) for time t 513 Vu = V - VCF * VC'; 514 Vu = 0.5 * (Vu+Vu'); % Approximation trick to make symmetric 515 516 % Update log likelihood 517 S.loglik = S.loglik + 0.5*(log(det(iF)) - innov'*iF*innov); 518 end 519 520 %%% STORE OUTPUT---------------------------------------------------- 521 522 % Store covariance and observation values for t-1 (priors) 523 S.Zm(:,t) = Z; 524 S.Vm(:,:,t) = V; 525 526 % Store covariance and state values for t (posteriors) 527 % i.e. Zu = Z_t|t & Vu = V_t|t 528 S.ZmU(:,t+1) = Zu; 529 S.VmU(:,:,t+1) = Vu; 530 end 531 532 % Store Kalman gain k_t 533 if isempty(Y_t) 534 S.k_t = zeros(m,m); 535 else 536 S.k_t = VCF * C_t; 537 end 538end 539 540 541 542%______________________________________________________________________ 543function S = FIS(A, S) 544%FIS() Applies fixed-interval smoother 545% 546% Syntax: 547% S = FIS(A, S) 548% 549% Description: 550% SKF() applies a fixed-interval smoother, and is used in conjunction 551% with SKF(). Starting from the final value, this uses a set of 552% recursions and works backwards. Smoothers are advantageous in that 553% future values are used for estimation. See page 154 of 'Forecasting, 554% structural time series models and the Kalman filter' for more details 555% (Harvey, 1990). 556% 557% Input parameters: 558% A: Transition matrix coefficients. 559% S: Output from SKF() step. See SKF() for details. 560% 561% Output parameters: 562% S: In addition to the output from SKF(), FIS() adds the following 563% smoothed estimates. Note that t = 1...T gives time: 564% - S.ZmT: Smoothed estimate of factor values (Z_t|T) 565% - S.VmT: Smoothed estimate of factor covariance matrix (V_t|T = Cov(Z_t|T)) 566% - S.VmT_1: Smoothed estimate of Lag 1 factor covariance matrix (Cov(Z_tZ_t-1|T)) 567% 568% Model: 569% Y_t = C_t Z_t + e_t for e_t ~ N(0, R) 570% Z_t = A Z_{t-1} + mu_t for mu_t ~ N(0, Q) 571 572%% ORGANIZE INPUT --------------------------------------------------------- 573 574% Initialize output matrices 575 [m, nobs] = size(S.Zm); 576 S.ZmT = zeros(m,nobs+1); 577 S.VmT = zeros(m,m,nobs+1); 578 579 % Fill the final period of ZmT, VmT with SKF() posterior values 580 S.ZmT(:,nobs+1) = squeeze(S.ZmU(:, nobs+1)); 581 S.VmT(:,:,nobs+1) = squeeze(S.VmU(:,:, nobs+1)); 582 583 % Initialize VmT_1 lag 1 covariance matrix for final period 584 S.VmT_1(:,:,nobs) = (eye(m)-S.k_t) *A*squeeze(S.VmU(:,:,nobs)); 585 586 % Used for recursion process. See companion file for details 587 J_2 = squeeze(S.VmU(:,:,nobs)) * A' * pinv(squeeze(S.Vm(:,:,nobs))); 588 589 %% RUN SMOOTHING ALGORITHM ---------------------------------------------- 590 591 % Loop through time reverse-chronologically (starting at final period nobs) 592 for t = nobs:-1:1 593 594 % Store posterior and prior factor covariance values 595 VmU = squeeze(S.VmU(:,:,t)); 596 Vm1 = squeeze(S.Vm(:,:,t)); 597 598 % Store previous period smoothed factor covariance and lag-1 covariance 599 V_T = squeeze(S.VmT(:,:,t+1)); 600 V_T1 = squeeze(S.VmT_1(:,:,t)); 601 602 J_1 = J_2; 603 604 % Update smoothed factor estimate 605 S.ZmT(:,t) = S.ZmU(:,t) + J_1 * (S.ZmT(:,t+1) - A * S.ZmU(:,t)) ; 606 607 % Update smoothed factor covariance matrix 608 S.VmT(:,:,t) = VmU + J_1 * (V_T - Vm1) * J_1'; 609 610 if t>1 611 % Update weight 612 J_2 = squeeze(S.VmU(:, :, t-1)) * A' * pinv(squeeze(S.Vm(:,:,t-1))); 613 614 % Update lag 1 factor covariance matrix 615 S.VmT_1(:,:,t-1) = VmU * J_2'+J_1 * (V_T1 - A * VmU) * J_2'; 616 end 617 end 618 619end 620 621 622function [y,C,R,L] = MissData(y,C,R) 623%______________________________________________________________________ 624% PROC missdata 625% PURPOSE: eliminates the rows in y & matrices Z, G that correspond to 626% missing data (NaN) in y 627% INPUT y vector of observations at time t 628% S KF system matrices (structure) 629% must contain Z & G 630% OUTPUT y vector of observations (reduced) 631% Z G KF system matrices (reduced) 632% L To restore standard dimensions 633% where # is the nr of available data in y 634%______________________________________________________________________ 635 636 % Returns 1 for nonmissing series 637 ix = ~isnan(y); 638 639 % Index for columns with nonmissing variables 640 e = eye(size(y,1)); 641 L = e(:,ix); 642 643 % Removes missing series 644 y = y(ix); 645 646 % Removes missing series from observation matrix 647 C = C(ix,:); 648 649 % Removes missing series from transition matrix 650 R = R(ix,ix); 651 652end 653 654