# R/01-linear-models.R#' Comprehensive linear regression analysis#'#' @param data Data frame#' @param formula Regression formula#' @param validation_method Validation method#' @return Linear regression resultslinear_regression_analysis<-function(data,formula,validation_method="holdout"){# Fit the modelmodel<-lm(formula,data=data)# Model summarymodel_summary<-summary(model)# Model diagnosticsdiagnostics<-perform_model_diagnostics(model,data)# Model validationvalidation_results<-validate_model(model,data,validation_method)# Model selectionselection_results<-perform_model_selection(data,formula)results<-list(model=model,summary=model_summary,diagnostics=diagnostics,validation=validation_results,selection=selection_results)return(results)}#' Perform model diagnostics#'#' @param model Fitted model#' @param data Original data#' @return Diagnostic resultsperform_model_diagnostics<-function(model,data){diagnostics<-list(residuals=residuals(model),fitted_values=fitted(model),leverage=hatvalues(model),cooks_distance=cooks.distance(model),dffits=dffits(model),dfbetas=dfbetas(model))# Normality testsdiagnostics$normality_tests<-list(shapiro_test=shapiro.test(diagnostics$residuals),anderson_darling=nortest::ad.test(diagnostics$residuals))# Heteroscedasticity testsdiagnostics$heteroscedasticity_tests<-list(breusch_pagan=lmtest::bptest(model),white_test=lmtest::bptest(model,~fitted(model)+I(fitted(model)^2)))# Autocorrelation testsdiagnostics$autocorrelation_tests<-list(durbin_watson=lmtest::dwtest(model))# Multicollinearitydiagnostics$multicollinearity<-calculate_multicollinearity(model)return(diagnostics)}#' Calculate multicollinearity measures#'#' @param model Fitted model#' @return Multicollinearity measurescalculate_multicollinearity<-function(model){# Variance Inflation Factorsvif_values<-car::vif(model)# Condition IndexX<-model.matrix(model)eigen_values<-eigen(t(X)%*%X)$valuescondition_index<-sqrt(max(eigen_values)/eigen_values)# Tolerancetolerance<-1/vif_valuesreturn(list(vif=vif_values,condition_index=condition_index,tolerance=tolerance))}#' Validate model using various methods#'#' @param model Fitted model#' @param data Original data#' @param method Validation method#' @return Validation resultsvalidate_model<-function(model,data,method="holdout"){if(method=="holdout"){return(holdout_validation(model,data))}elseif(method=="cross_validation"){return(cross_validation(model,data))}elseif(method=="bootstrap"){return(bootstrap_validation(model,data))}}#' Holdout validation#'#' @param model Fitted model#' @param data Original data#' @return Holdout validation resultsholdout_validation<-function(model,data){# Split dataset.seed(123)train_indices<-sample(1:nrow(data),0.7*nrow(data))train_data<-data[train_indices,]test_data<-data[-train_indices,]# Fit model on training datatrain_model<-lm(formula(model),data=train_data)# Predict on test datapredictions<-predict(train_model,newdata=test_data)actual<-test_data[[as.character(formula(model)[[2]])]]# Calculate metricsmse<-mean((actual-predictions)^2)rmse<-sqrt(mse)mae<-mean(abs(actual-predictions))r_squared<-1-sum((actual-predictions)^2)/sum((actual-mean(actual))^2)return(list(mse=mse,rmse=rmse,mae=mae,r_squared=r_squared,predictions=predictions,actual=actual))}#' Cross-validation#'#' @param model Fitted model#' @param data Original data#' @param k Number of folds#' @return Cross-validation resultscross_validation<-function(model,data,k=10){set.seed(123)folds<-create_folds(1:nrow(data),k=k)cv_results<-list()for(iin1:k){train_indices<-unlist(folds[-i])test_indices<-folds[[i]]train_data<-data[train_indices,]test_data<-data[test_indices,]# Fit modelcv_model<-lm(formula(model),data=train_data)# Predictpredictions<-predict(cv_model,newdata=test_data)actual<-test_data[[as.character(formula(model)[[2]])]]# Calculate metricsmse<-mean((actual-predictions)^2)mae<-mean(abs(actual-predictions))cv_results[[i]]<-list(mse=mse,mae=mae)}# Aggregate resultsmean_mse<-mean(sapply(cv_results,function(x)x$mse))mean_mae<-mean(sapply(cv_results,function(x)x$mae))sd_mse<-sd(sapply(cv_results,function(x)x$mse))sd_mae<-sd(sapply(cv_results,function(x)x$mae))return(list(mean_mse=mean_mse,mean_mae=mean_mae,sd_mse=sd_mse,sd_mae=sd_mae,cv_results=cv_results))}#' Create k-fold cross-validation folds#'#' @param indices Data indices#' @param k Number of folds#' @return List of fold indicescreate_folds<-function(indices,k=10){n<-length(indices)fold_size<-floor(n/k)remainder<-n%%kfolds<-list()start<-1for(iin1:k){end<-start+fold_size-1if(i<=remainder){end<-end+1}folds[[i]]<-indices[start:end]start<-end+1}return(folds)}
# R/02-generalized-linear-models.R#' Comprehensive GLM analysis#'#' @param data Data frame#' @param formula GLM formula#' @param family GLM family#' @return GLM analysis resultsglm_analysis<-function(data,formula,family=gaussian()){# Fit the modelmodel<-glm(formula,data=data,family=family)# Model summarymodel_summary<-summary(model)# Model diagnosticsdiagnostics<-perform_glm_diagnostics(model,data)# Model validationvalidation_results<-validate_glm_model(model,data)# Model comparisoncomparison_results<-compare_glm_models(data,formula,family)results<-list(model=model,summary=model_summary,diagnostics=diagnostics,validation=validation_results,comparison=comparison_results)return(results)}#' Perform GLM diagnostics#'#' @param model Fitted GLM model#' @param data Original data#' @return GLM diagnostic resultsperform_glm_diagnostics<-function(model,data){diagnostics<-list(residuals=residuals(model),fitted_values=fitted(model),deviance_residuals=residuals(model,type="deviance"),pearson_residuals=residuals(model,type="pearson"),leverage=hatvalues(model),cooks_distance=cooks.distance(model))# Deviance analysisdiagnostics$deviance_analysis<-perform_deviance_analysis(model)# Goodness of fit testsdiagnostics$goodness_of_fit<-perform_goodness_of_fit_tests(model)return(diagnostics)}#' Perform deviance analysis#'#' @param model Fitted GLM model#' @return Deviance analysis resultsperform_deviance_analysis<-function(model){# Null deviancenull_deviance<-model$null.deviance# Residual devianceresidual_deviance<-model$deviance# Deviance explaineddeviance_explained<-(null_deviance-residual_deviance)/null_deviance# Deviance residualsdeviance_residuals<-residuals(model,type="deviance")return(list(null_deviance=null_deviance,residual_deviance=residual_deviance,deviance_explained=deviance_explained,deviance_residuals=deviance_residuals))}#' Perform goodness of fit tests#'#' @param model Fitted GLM model#' @return Goodness of fit test resultsperform_goodness_of_fit_tests<-function(model){# Hosmer-Lemeshow test (for logistic regression)if(model$family$family=="binomial"){hosmer_lemeshow<-ResourceSelection::hoslem.test(model$y,fitted(model))}else{hosmer_lemeshow<-NULL}# Pearson chi-square testpearson_chi_square<-sum(residuals(model,type="pearson")^2)pearson_p_value<-1-pchisq(pearson_chi_square,model$df.residual)return(list(hosmer_lemeshow=hosmer_lemeshow,pearson_chi_square=pearson_chi_square,pearson_p_value=pearson_p_value))}#' Compare different GLM models#'#' @param data Data frame#' @param formula Base formula#' @param family GLM family#' @return Model comparison resultscompare_glm_models<-function(data,formula,family){# Fit different modelsmodels<-list()# Full modelmodels$full<-glm(formula,data=data,family=family)# Stepwise selectionmodels$stepwise<-step(models$full,direction="both",trace=FALSE)# AIC-based selectionmodels$aic<-step(models$full,direction="both",k=2,trace=FALSE)# BIC-based selectionmodels$bic<-step(models$full,direction="both",k=log(nrow(data)),trace=FALSE)# Compare modelscomparison<-data.frame(model=names(models),aic=sapply(models,AIC),bic=sapply(models,BIC),deviance=sapply(models,function(x)x$deviance),df_residual=sapply(models,function(x)x$df.residual))return(list(models=models,comparison=comparison))}
# R/03-mixed-effects-models.R#' Comprehensive linear mixed effects analysis#'#' @param data Data frame#' @param formula Mixed effects formula#' @param random_effects Random effects specification#' @return Mixed effects analysis resultslme_analysis<-function(data,formula,random_effects){# Fit the modelmodel<-lme4::lmer(formula,data=data,REML=TRUE)# Model summarymodel_summary<-summary(model)# Model diagnosticsdiagnostics<-perform_lme_diagnostics(model,data)# Model validationvalidation_results<-validate_lme_model(model,data)# Model comparisoncomparison_results<-compare_lme_models(data,formula,random_effects)results<-list(model=model,summary=model_summary,diagnostics=diagnostics,validation=validation_results,comparison=comparison_results)return(results)}#' Perform LME diagnostics#'#' @param model Fitted LME model#' @param data Original data#' @return LME diagnostic resultsperform_lme_diagnostics<-function(model,data){diagnostics<-list(residuals=residuals(model),fitted_values=fitted(model),random_effects=ranef(model),conditional_residuals=residuals(model,type="response"),marginal_residuals=residuals(model,type="pearson"))# Normality tests for residualsdiagnostics$residual_normality<-shapiro.test(diagnostics$residuals)# Normality tests for random effectsdiagnostics$random_effects_normality<-lapply(diagnostics$random_effects,function(x){if(ncol(x)==1){shapiro.test(x[,1])}else{NULL}})# Heteroscedasticity testsdiagnostics$heteroscedasticity<-lmtest::bptest(lm(residuals(model)~fitted(model)))return(diagnostics)}#' Validate LME model#'#' @param model Fitted LME model#' @param data Original data#' @return LME validation resultsvalidate_lme_model<-function(model,data){# Cross-validationcv_results<-cross_validate_lme(model,data)# Bootstrap validationbootstrap_results<-bootstrap_validate_lme(model,data)# Model fit statisticsfit_statistics<-calculate_lme_fit_statistics(model)return(list(cross_validation=cv_results,bootstrap=bootstrap_results,fit_statistics=fit_statistics))}#' Cross-validate LME model#'#' @param model Fitted LME model#' @param data Original data#' @param k Number of folds#' @return Cross-validation resultscross_validate_lme<-function(model,data,k=10){set.seed(123)folds<-create_folds(1:nrow(data),k=k)cv_results<-list()for(iin1:k){train_indices<-unlist(folds[-i])test_indices<-folds[[i]]train_data<-data[train_indices,]test_data<-data[test_indices,]# Fit modelcv_model<-lme4::lmer(formula(model),data=train_data,REML=TRUE)# Predictpredictions<-predict(cv_model,newdata=test_data,allow.new.levels=TRUE)actual<-test_data[[as.character(formula(model)[[2]])]]# Calculate metricsmse<-mean((actual-predictions)^2)mae<-mean(abs(actual-predictions))cv_results[[i]]<-list(mse=mse,mae=mae)}# Aggregate resultsmean_mse<-mean(sapply(cv_results,function(x)x$mse))mean_mae<-mean(sapply(cv_results,function(x)x$mae))sd_mse<-sd(sapply(cv_results,function(x)x$mse))sd_mae<-sd(sapply(cv_results,function(x)x$mae))return(list(mean_mse=mean_mse,mean_mae=mean_mae,sd_mse=sd_mse,sd_mae=sd_mae,cv_results=cv_results))}#' Calculate LME fit statistics#'#' @param model Fitted LME model#' @return Fit statisticscalculate_lme_fit_statistics<-function(model){# AIC and BICaic<-AIC(model)bic<-BIC(model)# Log-likelihoodlog_lik<-logLik(model)# R-squaredr_squared<-calculate_lme_r_squared(model)return(list(aic=aic,bic=bic,log_likelihood=log_lik,r_squared=r_squared))}#' Calculate LME R-squared#'#' @param model Fitted LME model#' @return R-squared valuescalculate_lme_r_squared<-function(model){# Marginal R-squaredmarginal_r_squared<-r.squaredGLMM(model)[1]# Conditional R-squaredconditional_r_squared<-r.squaredGLMM(model)[2]return(list(marginal=marginal_r_squared,conditional=conditional_r_squared))}
# R/04-time-series-models.R#' Comprehensive ARIMA analysis#'#' @param data Time series data#' @param order ARIMA order#' @param seasonal_order Seasonal ARIMA order#' @return ARIMA analysis resultsarima_analysis<-function(data,order=NULL,seasonal_order=NULL){# Auto-select order if not providedif(is.null(order)){order<-auto_arima_order(data)}# Fit the modelmodel<-arima(data,order=order,seasonal=seasonal_order)# Model summarymodel_summary<-summary(model)# Model diagnosticsdiagnostics<-perform_arima_diagnostics(model,data)# Model validationvalidation_results<-validate_arima_model(model,data)# Forecastingforecast_results<-forecast_arima_model(model,data)results<-list(model=model,summary=model_summary,diagnostics=diagnostics,validation=validation_results,forecast=forecast_results)return(results)}#' Auto-select ARIMA order#'#' @param data Time series data#' @return ARIMA orderauto_arima_order<-function(data){# Use auto.arima from forecast packageauto_model<-forecast::auto.arima(data,seasonal=FALSE,stepwise=FALSE,approximation=FALSE)return(auto_model$arma[1:3])}#' Perform ARIMA diagnostics#'#' @param model Fitted ARIMA model#' @param data Original data#' @return ARIMA diagnostic resultsperform_arima_diagnostics<-function(model,data){diagnostics<-list(residuals=residuals(model),fitted_values=fitted(model),acf_residuals=acf(residuals(model),plot=FALSE),pacf_residuals=pacf(residuals(model),plot=FALSE))# Ljung-Box testdiagnostics$ljung_box<-Box.test(residuals(model),type="Ljung-Box")# Normality testdiagnostics$normality<-shapiro.test(residuals(model))# ARCH testdiagnostics$arch_test<-FinTS::ArchTest(residuals(model))return(diagnostics)}#' Validate ARIMA model#'#' @param model Fitted ARIMA model#' @param data Original data#' @return ARIMA validation resultsvalidate_arima_model<-function(model,data){# Out-of-sample validationn<-length(data)train_size<-floor(0.8*n)train_data<-data[1:train_size]test_data<-data[(train_size+1):n]# Fit model on training datatrain_model<-arima(train_data,order=model$arma[1:3])# Forecastforecast_values<-forecast::forecast(train_model,h=length(test_data))# Calculate metricsmse<-mean((test_data-forecast_values$mean)^2)mae<-mean(abs(test_data-forecast_values$mean))mape<-mean(abs((test_data-forecast_values$mean)/test_data))*100return(list(mse=mse,mae=mae,mape=mape,forecast_values=forecast_values$mean,actual_values=test_data))}#' Forecast ARIMA model#'#' @param model Fitted ARIMA model#' @param data Original data#' @param h Forecast horizon#' @return Forecast resultsforecast_arima_model<-function(model,data,h=12){# Generate forecastsforecast_values<-forecast::forecast(model,h=h)# Calculate prediction intervalsprediction_intervals<-forecast_values$lower[,1:2]prediction_intervals<-cbind(prediction_intervals,forecast_values$upper[,1:2])colnames(prediction_intervals)<-c("lower_80","lower_95","upper_80","upper_95")return(list(forecast=forecast_values$mean,prediction_intervals=prediction_intervals,forecast_object=forecast_values))}
# R/05-model-selection.R#' Comprehensive model selection#'#' @param data Data frame#' @param response_variable Response variable name#' @param candidate_models List of candidate models#' @return Model selection resultsmodel_selection<-function(data,response_variable,candidate_models){# Fit all candidate modelsfitted_models<-fit_candidate_models(data,response_variable,candidate_models)# Calculate selection criteriaselection_criteria<-calculate_selection_criteria(fitted_models)# Perform model comparisonmodel_comparison<-compare_models(fitted_models,selection_criteria)# Select best modelbest_model<-select_best_model(fitted_models,selection_criteria)results<-list(fitted_models=fitted_models,selection_criteria=selection_criteria,model_comparison=model_comparison,best_model=best_model)return(results)}#' Fit candidate models#'#' @param data Data frame#' @param response_variable Response variable name#' @param candidate_models List of candidate models#' @return Fitted modelsfit_candidate_models<-function(data,response_variable,candidate_models){fitted_models<-list()for(model_nameinnames(candidate_models)){model_spec<-candidate_models[[model_name]]tryCatch({if(model_spec$type=="linear"){fitted_models[[model_name]]<-lm(model_spec$formula,data=data)}elseif(model_spec$type=="glm"){fitted_models[[model_name]]<-glm(model_spec$formula,data=data,family=model_spec$family)}elseif(model_spec$type=="lme"){fitted_models[[model_name]]<-lme4::lmer(model_spec$formula,data=data)}},error=function(e){warning(paste("Failed to fit model",model_name,":",e$message))})}return(fitted_models)}#' Calculate selection criteria#'#' @param fitted_models Fitted models#' @return Selection criteriacalculate_selection_criteria<-function(fitted_models){criteria<-data.frame(model=names(fitted_models),aic=sapply(fitted_models,AIC),bic=sapply(fitted_models,BIC),log_likelihood=sapply(fitted_models,function(x)as.numeric(logLik(x))),r_squared=sapply(fitted_models,function(x){if(inherits(x,"lm")){summary(x)$r.squared}else{NA}}),adj_r_squared=sapply(fitted_models,function(x){if(inherits(x,"lm")){summary(x)$adj.r.squared}else{NA}}),stringsAsFactors=FALSE)return(criteria)}#' Compare models#'#' @param fitted_models Fitted models#' @param selection_criteria Selection criteria#' @return Model comparison resultscompare_models<-function(fitted_models,selection_criteria){comparison<-list()# AIC comparisoncomparison$aic<-selection_criteria[order(selection_criteria$aic),]# BIC comparisoncomparison$bic<-selection_criteria[order(selection_criteria$bic),]# Likelihood ratio testscomparison$likelihood_ratio_tests<-perform_likelihood_ratio_tests(fitted_models)# Information criteria differencescomparison$aic_differences<-calculate_information_criteria_differences(selection_criteria,"aic")comparison$bic_differences<-calculate_information_criteria_differences(selection_criteria,"bic")return(comparison)}#' Perform likelihood ratio tests#'#' @param fitted_models Fitted models#' @return Likelihood ratio test resultsperform_likelihood_ratio_tests<-function(fitted_models){model_names<-names(fitted_models)n_models<-length(model_names)lrt_results<-data.frame(model1=character(0),model2=character(0),lr_statistic=numeric(0),p_value=numeric(0),stringsAsFactors=FALSE)for(iin1:(n_models-1)){for(jin(i+1):n_models){model1<-fitted_models[[model_names[i]]]model2<-fitted_models[[model_names[j]]]if(inherits(model1,"lm")&&inherits(model2,"lm")){lrt<-anova(model1,model2)lr_statistic<-lrt$F[2]p_value<-lrt$`Pr(>F)`[2]lrt_results<-rbind(lrt_results,data.frame(model1=model_names[i],model2=model_names[j],lr_statistic=lr_statistic,p_value=p_value,stringsAsFactors=FALSE))}}}return(lrt_results)}#' Calculate information criteria differences#'#' @param selection_criteria Selection criteria#' @param criterion Information criterion#' @return Information criteria differencescalculate_information_criteria_differences<-function(selection_criteria,criterion){min_value<-min(selection_criteria[[criterion]],na.rm=TRUE)differences<-selection_criteria[[criterion]]-min_valuereturn(differences)}#' Select best model#'#' @param fitted_models Fitted models#' @param selection_criteria Selection criteria#' @return Best modelselect_best_model<-function(fitted_models,selection_criteria){# Select model with minimum AICbest_aic_idx<-which.min(selection_criteria$aic)best_aic_model<-names(fitted_models)[best_aic_idx]# Select model with minimum BICbest_bic_idx<-which.min(selection_criteria$bic)best_bic_model<-names(fitted_models)[best_bic_idx]return(list(best_aic=best_aic_model,best_bic=best_bic_model,best_aic_model=fitted_models[[best_aic_model]],best_bic_model=fitted_models[[best_bic_model]]))}
# Model fitting and validationfit_and_validate<-function(data,formula,model_type="linear"){# Fit modelif(model_type=="linear"){model<-lm(formula,data=data)}elseif(model_type=="glm"){model<-glm(formula,data=data,family=binomial())}# Validate modelvalidation<-validate_model(model,data)# Return resultsreturn(list(model=model,validation=validation))}