R语言数据清洗与整理
# 1. 读取数据# ------------------------------------------------------------ # 1. 设置文件路径 # ------------------------------------------------------------ file_path - G:/学生成绩/学生成绩NA.csv output_dir - G:/学生成绩/数据清洗结果 if (!dir.exists(output_dir)) { dir.create(output_dir, recursive TRUE) } # ------------------------------------------------------------ # 2. 检查文件是否存在 # ------------------------------------------------------------ if (file.exists(file_path)) { cat(文件存在可以读取。\n) } else { stop(文件不存在请检查路径是否正确。) } # ------------------------------------------------------------ # 3. 读取 CSV 文件 # ------------------------------------------------------------ student_score - read.csv( file file_path, header TRUE, # TRUE 表示第一行是列名 fileEncoding GB18030, # 防止中文乱码 check.names FALSE, # 不自动修改中文列名 na.strings c(, NA, NaN, N/A, 缺失, NULL) )#2. 基本查看cat(\n 数据前6行 head() \n) print(head(student_score)) cat(\n 数据结构 str() \n) str(student_score) cat(\n 描述性统计 summary() \n) print(summary(student_score)) cat(\n 数据维度 \n) cat(行数, nrow(student_score), \n) cat(列数, ncol(student_score), \n)# 3. 数据类型初步处理# 一般情况下“姓名”“学生ID”为字符型其余成绩列为数值型。# 如果成绩列因为缺失或特殊字符被读成字符型这里尝试转换为数值型。id_cols - c(姓名, 学生ID) score_cols - setdiff(names(student_score), id_cols) for (col in score_cols) { student_score[[col]] - suppressWarnings(as.numeric(student_score[[col]])) } cat(\n 类型转换后的数据结构 \n) str(student_score)# 4. 缺失值识别 is.na()cat(\n 缺失值逻辑矩阵前6行 is.na() \n) print(head(is.na(student_score)))# 5. 缺失值统计missing_count - colSums(is.na(student_score)) missing_rate - round( missing_count / nrow(student_score), 4 ) missing_summary - data.frame( 变量名 names(student_score), 缺失值个数 as.integer(missing_count), 缺失比例 missing_rate, check.names FALSE ) cat(\n 各变量缺失值统计 \n) print(missing_summary) missing_output_file - file.path(output_dir, 缺失值统计.csv) write.csv( missing_summary, file missing_output_file, row.names FALSE, fileEncoding GB18030 ) cat(\n缺失值统计结果已保存到\n) cat(missing_output_file, \n)# 6. 删除含缺失值的行student_score_delete_na - na.omit(student_score) cat(\n 删除缺失值后的数据维度 \n) cat(原始数据行数, nrow(student_score), \n) cat(删除缺失值后行数, nrow(student_score_delete_na), \n) delete_na_file - file.path(output_dir, 删除缺失值后的学生成绩.csv) write.csv( student_score_delete_na, file delete_na_file, row.names FALSE, fileEncoding GB18030 ) cat(\n删除缺失值后的数据已保存到\n) cat(delete_na_file, \n)# 7. 均值填充缺失值student_score_mean_fill - student_score numeric_cols - names(student_score_mean_fill)[sapply(student_score_mean_fill, is.numeric)] for (col in numeric_cols) { mean_value - mean(student_score_mean_fill[[col]], na.rm TRUE) student_score_mean_fill[[col]][is.na(student_score_mean_fill[[col]])] - mean_value } cat(\n 均值填充后的数据前6行 \n) print(head(student_score_mean_fill)) mean_fill_file - file.path(output_dir, 均值填充后的学生成绩.csv) write.csv( student_score_mean_fill, file mean_fill_file, row.names FALSE, fileEncoding GB18030 ) cat(\n均值填充后的数据已保存到\n) cat(mean_fill_file, \n)# 8. 中位数填充缺失值student_score_median_fill - student_score numeric_cols - names(student_score_median_fill)[sapply(student_score_median_fill, is.numeric)] for (col in numeric_cols) { median_value - median(student_score_median_fill[[col]], na.rm TRUE) student_score_median_fill[[col]][is.na(student_score_median_fill[[col]])] - median_value } cat(\n 中位数填充后的数据前6行 \n) print(head(student_score_median_fill)) median_fill_file - file.path(output_dir, 中位数填充后的学生成绩.csv) write.csv( student_score_median_fill, file median_fill_file, row.names FALSE, fileEncoding GB18030 ) cat(\n中位数填充后的数据已保存到\n) cat(median_fill_file, \n)# 9. 箱线图法识别异常值# 箱线图法基于 IQR # 下界 Q1 - 1.5 * IQR # 上界 Q3 1.5 * IQR # 小于下界或大于上界的值视为异常值。 outlier_result - data.frame( 变量名 character(), Q1 numeric(), Q3 numeric(), IQR numeric(), 下界 numeric(), 上界 numeric(), 异常值个数 integer(), 异常值 character(), check.names FALSE ) for (col in numeric_cols) { x - student_score[[col]] x_no_na - x[!is.na(x)] Q1 - quantile(x_no_na, 0.25) Q3 - quantile(x_no_na, 0.75) IQR_value - IQR(x_no_na) lower_bound - Q1 - 1.5 * IQR_value upper_bound - Q3 1.5 * IQR_value outliers - x_no_na[x_no_na lower_bound | x_no_na upper_bound] outlier_result - rbind( outlier_result, data.frame( 变量名 col, Q1 as.numeric(Q1), Q3 as.numeric(Q3), IQR as.numeric(IQR_value), 下界 as.numeric(lower_bound), 上界 as.numeric(upper_bound), 异常值个数 length(outliers), 异常值 paste(outliers, collapse ; ), check.names FALSE ) ) } cat(\n 箱线图法异常值识别结果 \n) print(outlier_result) outlier_file - file.path(output_dir, 箱线图异常值识别结果.csv) write.csv( outlier_result, file outlier_file, row.names FALSE, fileEncoding GB18030 ) cat(\n异常值识别结果已保存到\n) cat(outlier_file, \n)# 10. 绘制箱线图boxplot_dir - file.path(output_dir, 箱线图) if (!dir.exists(boxplot_dir)) { dir.create(boxplot_dir, recursive TRUE) } for (col in numeric_cols) { png_file - file.path(boxplot_dir, paste0(col, _箱线图.png)) png( filename png_file, width 800, height 600 ) boxplot( student_score[[col]], main paste0(col, 箱线图), ylab col, col lightblue, border gray30 ) dev.off() } cat(\n所有数值变量的箱线图已保存到\n) cat(boxplot_dir, \n)# 11. 生成异常值明细表outlier_detail - data.frame() for (col in numeric_cols) { x - student_score[[col]] x_no_na - x[!is.na(x)] Q1 - quantile(x_no_na, 0.25) Q3 - quantile(x_no_na, 0.75) IQR_value - IQR(x_no_na) lower_bound - Q1 - 1.5 * IQR_value upper_bound - Q3 1.5 * IQR_value outlier_index - which(!is.na(x) (x lower_bound | x upper_bound)) if (length(outlier_index) 0) { temp - data.frame( 行号 outlier_index, 姓名 student_score$姓名[outlier_index], 学生ID student_score$学生ID[outlier_index], 变量名 col, 异常值 student_score[[col]][outlier_index], 下界 as.numeric(lower_bound), 上界 as.numeric(upper_bound), check.names FALSE ) outlier_detail - rbind(outlier_detail, temp) } } cat(\n 异常值明细 \n) print(outlier_detail) outlier_detail_file - file.path(output_dir, 异常值明细表.csv) write.csv( outlier_detail, file outlier_detail_file, row.names FALSE, fileEncoding GB18030 ) cat(\n异常值明细表已保存到\n) cat(outlier_detail_file, \n)# 12. 最终提示cat(\n 数据清洗与异常值识别完成 \n) cat(结果文件夹\n) cat(output_dir, \n)