# R/01-data-exploration.R#' Comprehensive data overview#'#' @param data Data frame to explore#' @return List containing data overview informationdata_overview<-function(data){overview<-list(dimensions=dim(data),column_names=names(data),data_types=sapply(data,class),missing_values=colSums(is.na(data)),unique_values=sapply(data,function(x)length(unique(x))),memory_usage=object.size(data))# Add summary statistics for numeric columnsnumeric_cols<-sapply(data,is.numeric)if(sum(numeric_cols)>0){overview$numeric_summary<-summary(data[,numeric_cols,drop=FALSE])}# Add frequency tables for categorical columnscategorical_cols<-sapply(data,function(x)is.character(x)||is.factor(x))if(sum(categorical_cols)>0){overview$categorical_summary<-lapply(data[,categorical_cols,drop=FALSE],table)}return(overview)}#' Print data overview in a formatted way#'#' @param overview Data overview listprint_data_overview<-function(overview){cat("Data Overview\n")cat("=============\n")cat("Dimensions:",overview$dimensions[1],"rows x",overview$dimensions[2],"columns\n")cat("Memory usage:",format(overview$memory_usage,units="MB"),"\n\n")cat("Column Information\n")cat("------------------\n")for(iinseq_along(overview$column_names)){col_name<-overview$column_names[i]col_type<-overview$data_types[i]missing_count<-overview$missing_values[i]unique_count<-overview$unique_values[i]cat(sprintf("%-20s %-10s Missing: %-5d Unique: %-5d\n",col_name,col_type,missing_count,unique_count))}if(!is.null(overview$numeric_summary)){cat("\nNumeric Summary\n")cat("---------------\n")print(overview$numeric_summary)}if(!is.null(overview$categorical_summary)){cat("\nCategorical Summary\n")cat("-------------------\n")for(iinseq_along(overview$categorical_summary)){cat("\n",names(overview$categorical_summary)[i],":\n")print(overview$categorical_summary[[i]])}}}
# R/01-data-exploration.R (continued)#' Assess data quality#'#' @param data Data frame to assess#' @return Data quality reportassess_data_quality<-function(data){quality_report<-list(completeness=assess_completeness(data),consistency=assess_consistency(data),accuracy=assess_accuracy(data),validity=assess_validity(data))return(quality_report)}#' Assess data completeness#'#' @param data Data frame#' @return Completeness metricsassess_completeness<-function(data){total_cells<-nrow(data)*ncol(data)missing_cells<-sum(is.na(data))completeness<-list(total_cells=total_cells,missing_cells=missing_cells,completeness_rate=(total_cells-missing_cells)/total_cells,columns_with_missing=names(data)[colSums(is.na(data))>0],rows_with_missing=sum(rowSums(is.na(data))>0),missing_patterns=identify_missing_patterns(data))return(completeness)}#' Identify missing value patterns#'#' @param data Data frame#' @return Missing value patternsidentify_missing_patterns<-function(data){missing_matrix<-is.na(data)# Find columns that are always missing togethermissing_correlations<-cor(missing_matrix)missing_correlations[is.na(missing_correlations)]<-0# Find rows with similar missing patternsmissing_patterns<-table(apply(missing_matrix,1,paste,collapse=""))return(list(missing_correlations=missing_correlations,missing_patterns=missing_patterns))}#' Assess data consistency#'#' @param data Data frame#' @return Consistency metricsassess_consistency<-function(data){consistency<-list(duplicate_rows=sum(duplicated(data)),inconsistent_categories=identify_inconsistent_categories(data),outlier_columns=identify_outlier_columns(data))return(consistency)}#' Identify inconsistent categories#'#' @param data Data frame#' @return Inconsistent categoriesidentify_inconsistent_categories<-function(data){categorical_cols<-sapply(data,function(x)is.character(x)||is.factor(x))inconsistencies<-list()for(colinnames(data)[categorical_cols]){values<-data[[col]]unique_values<-unique(values[!is.na(values)])# Check for case inconsistenciescase_insensitive<-tolower(unique_values)if(length(unique_values)!=length(unique(case_insensitive))){inconsistencies[[col]]<-"Case inconsistencies detected"}# Check for whitespace inconsistenciestrimmed_values<-trimws(unique_values)if(length(unique_values)!=length(unique(trimmed_values))){inconsistencies[[col]]<-c(inconsistencies[[col]],"Whitespace inconsistencies detected")}}return(inconsistencies)}#' Identify columns with outliers#'#' @param data Data frame#' @return Outlier informationidentify_outlier_columns<-function(data){numeric_cols<-sapply(data,is.numeric)outlier_info<-list()for(colinnames(data)[numeric_cols]){values<-data[[col]][!is.na(data[[col]])]if(length(values)>0){Q1<-quantile(values,0.25)Q3<-quantile(values,0.75)IQR<-Q3-Q1lower_bound<-Q1-1.5*IQRupper_bound<-Q3+1.5*IQRoutliers<-values[values<lower_bound|values>upper_bound]if(length(outliers)>0){outlier_info[[col]]<-list(count=length(outliers),percentage=length(outliers)/length(values)*100,values=outliers)}}}return(outlier_info)}
# R/03-visualization-exploration.R#' Create comprehensive distribution plots#'#' @param data Data frame#' @param variables Variables to plot#' @return List of distribution plotscreate_distribution_plots<-function(data,variables=NULL){if(is.null(variables)){numeric_cols<-sapply(data,is.numeric)variables<-names(data)[numeric_cols]}plots<-list()for(varinvariables){if(var%in%names(data)){plots[[var]]<-create_single_distribution_plot(data,var)}}return(plots)}#' Create single distribution plot#'#' @param data Data frame#' @param variable Variable to plot#' @return Distribution plotcreate_single_distribution_plot<-function(data,variable){p<-ggplot2::ggplot(data,aes_string(x=variable))+ggplot2::geom_histogram(aes(y=..density..),bins=30,alpha=0.7,fill="steelblue")+ggplot2::geom_density(alpha=0.5,color="red",size=1)+ggplot2::geom_vline(aes_string(xintercept=paste0("mean(",variable,", na.rm = TRUE)")),color="green",linetype="dashed",size=1)+ggplot2::geom_vline(aes_string(xintercept=paste0("median(",variable,", na.rm = TRUE)")),color="orange",linetype="dashed",size=1)+ggplot2::theme_minimal()+ggplot2::labs(title=paste("Distribution of",variable),x=variable,y="Density")return(p)}#' Create box plots for multiple variables#'#' @param data Data frame#' @param variables Variables to plot#' @return Box plotcreate_box_plots<-function(data,variables){# Reshape data for box plotplot_data<-data[,variables,drop=FALSE]plot_data$id<-1:nrow(plot_data)plot_data_long<-tidyr::pivot_longer(plot_data,cols=all_of(variables),names_to="variable",values_to="value")p<-ggplot2::ggplot(plot_data_long,aes(x=variable,y=value))+ggplot2::geom_boxplot(aes(fill=variable),alpha=0.7)+ggplot2::geom_jitter(alpha=0.3,width=0.2)+ggplot2::theme_minimal()+ggplot2::labs(title="Box Plots of Variables",x="Variable",y="Value")+ggplot2::theme(legend.position="none")return(p)}
# R/03-visualization-exploration.R (continued)#' Create scatter plot matrix#'#' @param data Data frame#' @param variables Variables to include#' @return Scatter plot matrixcreate_scatter_plot_matrix<-function(data,variables){numeric_data<-data[,variables,drop=FALSE]# Create pairs plotp<-GGally::ggpairs(numeric_data,lower=list(continuous=GGally::wrap("points",alpha=0.3)),upper=list(continuous=GGally::wrap("cor",size=3)),diag=list(continuous=GGally::wrap("densityDiag",alpha=0.7)))return(p)}#' Create correlation heatmap#'#' @param cor_matrix Correlation matrix#' @return Correlation heatmapcreate_correlation_heatmap<-function(cor_matrix){# Convert to long formatcor_data<-reshape2::melt(cor_matrix)p<-ggplot2::ggplot(cor_data,aes(x=Var1,y=Var2,fill=value))+ggplot2::geom_tile()+ggplot2::scale_fill_gradient2(low="blue",high="red",mid="white",midpoint=0,limit=c(-1,1))+ggplot2::theme_minimal()+ggplot2::labs(title="Correlation Heatmap",x="",y="",fill="Correlation")+ggplot2::theme(axis.text.x=element_text(angle=45,hjust=1))return(p)}#' Create time series plots#'#' @param data Data frame#' @param time_var Time variable#' @param value_vars Value variables#' @return Time series plotscreate_time_series_plots<-function(data,time_var,value_vars){plots<-list()for(varinvalue_vars){p<-ggplot2::ggplot(data,aes_string(x=time_var,y=var))+ggplot2::geom_line()+ggplot2::geom_point(alpha=0.5)+ggplot2::theme_minimal()+ggplot2::labs(title=paste("Time Series of",var),x=time_var,y=var)plots[[var]]<-p}return(plots)}
# R/04-advanced-exploration.R (continued)#' Perform clustering analysis#'#' @param data Data frame#' @param variables Variables to include#' @param method Clustering method#' @return Clustering resultsperform_clustering_analysis<-function(data,variables,method="kmeans"){numeric_data<-data[,variables,drop=FALSE]# Remove rows with missing valuescomplete_data<-numeric_data[complete.cases(numeric_data),]if(nrow(complete_data)<2){return(NULL)}# Scale datascaled_data<-scale(complete_data)if(method=="kmeans"){# Determine optimal number of clustersoptimal_k<-determine_optimal_clusters(scaled_data)# Perform k-means clusteringcluster_result<-kmeans(scaled_data,centers=optimal_k,nstart=25)results<-list(method="kmeans",optimal_k=optimal_k,clusters=cluster_result$cluster,centers=cluster_result$centers,withinss=cluster_result$withinss,totss=cluster_result$totss,betweenss=cluster_result$betweenss)}elseif(method=="hierarchical"){# Perform hierarchical clusteringdist_matrix<-dist(scaled_data)hclust_result<-hclust(dist_matrix)# Cut tree to get clustersoptimal_k<-determine_optimal_clusters(scaled_data)clusters<-cutree(hclust_result,k=optimal_k)results<-list(method="hierarchical",optimal_k=optimal_k,clusters=clusters,hclust_result=hclust_result)}return(results)}#' Determine optimal number of clusters#'#' @param data Scaled data#' @return Optimal number of clustersdetermine_optimal_clusters<-function(data){max_k<-min(10,nrow(data)-1)if(max_k<2){return(2)}# Calculate within-cluster sum of squares for different kwss<-numeric(max_k)for(kin1:max_k){wss[k]<-sum(kmeans(data,centers=k,nstart=25)$withinss)}# Find elbow pointdiffs<-diff(wss)optimal_k<-which.max(diffs)+1return(optimal_k)}