ARTICLE · 1188478
拿到一份Excel数据,我用AI+R做了10项体检,发现5类隐藏问题(附代码)
一份数据,从能读取到能分析,中间究竟差了多少步?
上一篇文章,我分享了《用AI写R代码,为什么数据分析还是做不好?这5个坑,我反复见到》。
其中有一个观点,我想再强调一次:
AI能写R代码,不代表它能保证数据分析结果正确。
文章发布后,我也一直在思考一个问题:
如果读者已经知道数据分析需要避坑,那么下一步,应该怎么做?
我的答案是:拿一份真实数据,完整跑一遍。
今天,我用一个公开数据集,结合AI和R语言,带大家完成一次从数据体检、问题修复到结果输出的实战。
不讲复杂理论,不堆砌几十个R包。
我们只做一件事:
让一份数据,从“能打开”,变成“能检查、能分析、能复现”。
全文包含可运行的R代码。建议先收藏,后续可以对照自己的数据逐项检查。
01. 准备一份真实数据
今天使用的是R语言 modeldata 包中的 attrition 数据集。
这是一个常用于教学的员工流失分析数据集,包含1470条员工记录、31个变量。
例如:
Age:年龄Department:部门MonthlyIncome:月收入JobSatisfaction:工作满意度OverTime:是否加班Attrition:是否离职
我们的研究问题是:
员工流失与哪些特征存在关联?
注意,这是一项探索性分析。我们可以研究变量之间的关联,但不能仅凭这些数据得出因果结论。
首先加载数据。
library(tidyverse)library(modeldata)data("attrition", package = "modeldata")df <- attritiondim(df)names(df)glimpse(df)正常情况下,可以看到1470行、31列。
但这里有一个问题:
原始数据相对规整,不方便演示常见的数据质量错误。
因此,我专门制作一份教学用问题数据。
注意:以下缺失值、重复记录、异常值和错误编码均为人为注入,并不是说原始数据本身存在这些问题。
set.seed(20261015)df_dirty <- df# 问题1:年龄出现缺失值idx_age <- sample( seq_len(nrow(df_dirty)), size = 50)df_dirty$Age[idx_age] <- NA# 问题2:收入出现不合理值idx_income <- sample( seq_len(nrow(df_dirty)), size = 10)df_dirty$MonthlyIncome[idx_income] <- -999# 问题3:加班字段出现异常编码df_dirty$OverTime <- as.character( df_dirty$OverTime)idx_ot <- sample( seq_len(nrow(df_dirty)), size = 20)df_dirty$OverTime[idx_ot] <- "Unknown"# 问题4:增加重复记录df_dirty <- bind_rows( df_dirty, df_dirty[1:15, ])# 问题5:年龄字段被错误转换为字符df_dirty$Age <- as.character( df_dirty$Age)# 导出教学用Excelwritexl::write_xlsx( df_dirty,"attrition_dirty.xlsx")如果没有安装 writexl,可以先执行:
install.packages("writexl")现在,我们得到一份包含5类典型问题的Excel数据。
接下来,不直接建模,而是先进行数据体检。
02. 用AI+R完成10项数据体检
我建议拿到任何一份新数据,都先检查以下10项。
这里特别提醒:
不是所有问题都能靠一行R代码自动判断。
例如,异常值是否应该删除、缺失值采用什么处理方法、统计模型是否合理,都需要结合业务背景。
下面先运行一段基础检查代码。
library(tidyverse)library(readxl)df_check <- read_excel("attrition_dirty.xlsx")# 1. 数据规模dim(df_check)# 2. 变量名称names(df_check)# 3. 数据结构glimpse(df_check)# 4. 缺失值数量colSums(is.na(df_check))# 5. 完全重复记录数量sum(duplicated(df_check))# 6. 年龄字段检查class(df_check$Age)# 7. 收入范围检查summary(df_check$MonthlyIncome)# 8. 加班分类检查table( df_check$OverTime, useNA = "ifany")# 9. 离职情况table( df_check$Attrition, useNA = "ifany")# 10. 查看数据摘要summary(df_check)通过这轮检查,我们能够识别出前面人为注入的5类问题:
年龄缺失、收入异常编码、加班类别异常、重复记录、年龄类型错误。
这里还有一个细节:
由于我们将年龄字段转成了字符,读取Excel后,R不会自动知道它原本应该是数值变量。
这就是为什么我反复强调:
数据分析不能只依赖AI生成代码,还必须理解字段的业务含义。
03. 修复5类问题:不要一上来就删除数据
发现问题之后,接下来就是清洗。
但清洗数据,并不是简单地把所有异常记录删除。
我们需要先制定规则。
今天采用以下教学策略:
完全重复记录:删除重复副本; 年龄字段:恢复数值类型; 年龄缺失:保留缺失,并用非缺失样本的中位数演示简单插补; 收入中的 -999:视为人为设置的缺失编码,转换为NA;加班中的 Unknown:保留为明确的未知类别,不擅自判断为“Yes”或“No”。
执行代码:
df_clean <- df_check %>% distinct() %>% mutate( Age = as.numeric(Age), MonthlyIncome = if_else( MonthlyIncome == -999,NA_real_, as.numeric(MonthlyIncome) ), OverTime = factor( OverTime, levels = c("No","Yes","Unknown" ) ) )# 演示年龄中位数插补age_median <- median( df_clean$Age, na.rm = TRUE)df_clean <- df_clean %>% mutate( Age = replace_na( Age, age_median ) )这里必须强调两个专业问题。
第一,收入中的-999为什么转成NA?
因为我们在教学数据生成阶段,明确知道它是人为设置的异常编码。
如果换成真实业务数据,就必须先确认字段字典或业务规则,不能看到负数就随意删除。
第二,为什么年龄采用中位数插补?
这是为了演示基本操作,不代表中位数插补适用于所有研究。
真实科研中,应结合缺失比例、缺失机制和分析目的选择方法,必要时考虑多重插补及敏感性分析。
如果后续要训练机器学习模型,涉及从数据学习参数的插补、标准化和特征选择,应该在训练集或交叉验证的相应训练折内完成,避免数据泄漏。
正确的数据清洗,不是让数据变得好看,而是让每一步处理都有依据。
04. 清洗之后,开始做描述性统计
数据准备完成后,我们先回答一个简单问题:
不同加班状态下,员工流失比例是否存在差异?
这里选择 OverTime 和 Attrition 两个变量。
summary_table <- df_clean %>% filter( OverTime %in% c("Yes", "No") ) %>% count( OverTime, Attrition ) %>% group_by(OverTime) %>% mutate( proportion = n / sum(n) ) %>% ungroup()print(summary_table)这段代码可以计算不同加班组内部的离职人数和比例。
接下来绘制图表。
ggplot( summary_table, aes( x = OverTime, y = proportion, fill = Attrition )) + geom_col( position = "fill" ) + scale_y_continuous( labels = scales::percent ) + labs( title = "不同加班状态下的员工流失构成", x = "是否加班", y = "组内比例", fill = "是否离职" ) + theme_minimal( base_size = 14 )注意:这里展示的是描述性关联,不代表加班一定导致员工离职。
如果要进一步分析关联强度,还需要结合变量类型、研究设计、潜在混杂因素等,选择合适的统计方法。
另外,Unknown 类别在此被排除在分组比较之外,正式分析时应报告排除规则及对应样本量。
05. AI在这个工作流中,应该扮演什么角色?
很多人使用AI做数据分析,习惯直接输入:
“帮我分析这份数据。”
这个提问太宽泛。
我更推荐把AI作为数据分析助手,让它协助完成明确的任务,同时保留人的审核环节。
例如,下面这段提示词可以反复使用。
AI+R数据体检通用Prompt:
你是一名具有统计学和R语言经验的数据分析助手。我正在使用R语言分析一份Excel数据。请按照以下步骤协助我:1. 检查数据结构与字段类型2. 统计各变量缺失值数量和比例3. 检查完全重复记录4. 识别可能存在的异常数值5. 检查分类变量的异常编码6. 输出连续变量的描述性统计7. 检查目标变量的类别分布8. 提醒可能存在的数据泄漏风险9. 给出适合当前研究问题的分析建议10. 生成可复现的R代码要求:- 优先使用tidyverse生态- 不得虚构数据或统计结果- 不得擅自删除异常样本- 对每个清洗步骤解释原因- 对不确定的业务规则明确提出问题- 代码应尽量完整、可运行- 区分数据事实、统计假设和分析建议这段Prompt真正有价值的地方,不是让AI一次性输出更多代码。
而是给AI建立清晰的工作边界。
让AI执行具体任务,让人负责关键判断。
这才是AI+R工作流应该发挥的作用。
06. 最后一步:把分析过程变成可复现报告
做完数据清洗和统计分析,还不算结束。
因为科研和实际工作中,分析结果往往需要交给导师、同事或客户。
如果只有一堆零散的R代码,后续修改、复查和复现都很困难。
我建议使用Quarto组织分析报告。
一个基础报告可以包含:
analysis-report.qmd1. 研究问题2. 数据来源3. 数据体检4. 数据清洗规则5. 描述性统计6. 数据可视化7. 分析结论与局限性通过Quarto,可以把代码、图表、文字解释和分析结果整合在同一份文档中。
例如,在配置好Quarto环境后:
quarto render analysis-report.qmd --to html就可以生成HTML报告。
需要注意,这里的命令是报告生成示例。要得到完整报告,还需要先编写对应的 .qmd 文件。
对我而言,真正完整的数据分析交付,不只是得到几张图。
而是能够提供:
数据说明 + 清洗规则 + 可运行代码 + 分析结果 + 可复现报告。
07. 从会写R代码,到拥有一套自己的RAI工作流
回顾今天的案例,我们做了什么?
第一步,准备公开数据,并构造教学问题。
第二步,完成10项基础检查。
第三步,识别并处理5类人为注入的数据质量问题。
第四步,完成描述性统计和可视化。
第五步,使用AI辅助检查代码与分析思路。
第六步,建立可复现报告的组织方式。
整个过程可以概括为:
研究问题 → 数据体检 → 数据清洗 → 统计分析 → 可视化 → 报告交付。
这也是我一直在探索的RAI工作流。
过去13年,我一直在使用R语言解决数据分析问题。
进入AI时代后,我越来越确信:
真正值得积累的,不只是某一段R代码,而是一套能够反复使用、不断优化的数据分析方法。
AI让编程更高效。
R语言让分析更加灵活。
而完整的工作流,才能让我们持续解决真实问题。
08. 免费领取:AI+R数据体检与分析工作流
为了方便大家跟着本文实操,我准备整理一份:
《AI+R数据体检与分析工作流 V1.0》
计划包含:
公开案例数据与教学用问题数据 数据体检R代码 数据清洗R代码 描述性统计与绘图示例 AI辅助数据分析Prompt 可复现报告模板
联系我们,回复「工作流」,获取资料领取说明。
如果你还没有领取上一篇文章中的《AI+R数据分析10项体检清单》,也可以回复 「体检」。
最后,我想问大家一个问题:
如果有一套工具,可以让你导入自己的Excel数据,自动完成基础数据检查,并生成可编辑的R分析报告,你最希望它解决什么问题?
A. 自动发现数据质量问题
B. 自动生成数据清洗R代码
C. 辅助选择统计分析方法
D. 自动生成科研图表
E. 自动整理可复现分析报告
欢迎在评论区回复A、B、C、D或E。
你的真实需求,将帮助我决定下一步优先开发哪些功能。
AI时代,真正有价值的不是写出更多代码,而是用更可靠的工作流,完成更多有意义的数据分析。
—— RAI王博士















































































