事情是这样的。
上个月我做数据分析,需要处理一份有点恶心的问卷数据——列名是中文,值有的是数字有的是文本,还有大量空值。我实在不想自己一行行写 dplyr 清洗代码,于是决定:让AI来写。
我选了三个AI:ChatGPT、某国产免费模型(代号M)、以及Claude。每个给同样的任务,各用一天。
三天后,我差点把电脑砸了——不是气的,是怕的。
第一天:国产免费模型M——代码不完全错,但细节一塌糊涂
我先拿免费模型M开刀,反正不要钱,试试呗。
我把需求贴进去:
我有一个CSV文件,列名是“年龄”“收入”“城市”,需要: 1)删除年龄<18的行; 2)把收入列的空值填充为中位数; 3)把城市列里的“北京”“上海”“广州”统一成“一线”,其他改成“其他”。
它秒回了一段R代码:
ounter(lineounter(lineounter(lineounter(linedf <- read.csv("data.csv")df <- df[df$年龄 >= 18, ]df$收入[is.na(df$收入)] <- median(df$收入, na.rm = TRUE)df$城市 <- ifelse(df$城市 %in% c("北京","上海","广州"), "一线", "其他")
乍一看没问题,我复制、运行——
报错:
ounter(lineError: unexpected input in 'df$年龄'
问题出在非标准列名。在R里,包含中文或特殊字符的列名,最好用反引号包起来:df$`年龄`。
但更坑的是,我的CSV是 UTF-8-BOM 格式,read.csv() 读取后,列名前可能带有隐藏字符,导致 $年龄 无法正确匹配。
M的代码框架没错,但完全忽略了真实数据环境中的编码和列名问题。
你说它错吧,也不是;但你要真用它,会被坑到怀疑人生。
我给它的评价是:👉 “只会写示例代码,不会处理真实数据。”
第二天:ChatGPT——能跑,但默认“帮你做决定”
第二天我换了ChatGPT(GPT-4o)。我特地补充了一句:
注意中文列名处理
它给出的代码是这样的:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(linelibrary(dplyr)library(readr)df <- read_csv("data.csv")df <- df %>%filter(`年龄` >= 18) %>%mutate(`收入` = if_else(is.na(`收入`), median(`收入`, na.rm = TRUE), `收入`),`城市` = case_when(`城市` %in% c("北京", "上海", "广州") ~ "一线",TRUE ~ "其他"))
这次我一跑——完全正常。
但问题也随之出现。
⚠️ 问题1:它“默认帮你做了不可逆操作”
case_when() 里的 TRUE ~ "其他",意味着所有非一线城市都被覆盖成“其他”。在当前需求下没错,但它没有提醒这是覆盖操作,也没有保留原始列。
更稳的写法应该是新建一列:
ounter(linedf$城市_分类 <- ifelse(df$城市 %in% c("北京","上海","广州"), "一线", "其他")
⚠️ 问题2:代码“过度工程化”
它用了 read_csv()、if_else()、case_when(),这些都没错,但对简单任务来说有点“用力过猛”。新手容易看不懂、不敢改、一改就崩。
ChatGPT的问题不是写错,而是:👉 默认你是一个“会二次开发的人”
我最后改成了更直观的版本:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(linedf <- read.csv("data.csv", fileEncoding = "UTF-8-BOM", check.names = FALSE)df <- df[df$`年龄` >= 18, ]median_income <- median(df$`收入`, na.rm = TRUE)df$`收入`[is.na(df$`收入`)] <- median_incomedf$城市_分类 <- ifelse(df$`城市` %in% c("北京","上海","广州"), "一线", "其他")
更长,但——我敢改、敢查、敢debug。
第三天:Claude——最像“靠谱同事”的AI
第三天我试了Claude(Sonnet 3.5)。
它给的代码是:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(linedf <- read.csv("data.csv", fileEncoding = "UTF-8-BOM", check.names = FALSE)# 过滤年龄df <- df[df$`年龄` >= 18, ]# 填充收入缺失值median_income <- median(df$`收入`, na.rm = TRUE)df$`收入`[is.na(df$`收入`)] <- median_income# 城市分类(保留原字段)df$城市_分类 <- ifelse(df$`城市` %in% c("北京","上海","广州"), "一线", "其他")
没有炫技,没有复杂函数,但:
每一步都可读 每一步都可改 默认保留原数据
更关键的是,它额外提醒了一句:
建议检查年龄列是否存在异常值(如负数或大于120)
这一下就从“写代码”,变成了“懂数据”。
后来我又加了一个需求:
把收入分成低、中、高三档(按分位数)
它给出的代码:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(linedf$收入等级 <- cut(df$`收入`,breaks = quantile(df$`收入`, probs = c(0, 1/3, 2/3, 1), na.rm = TRUE),labels = c("低", "中", "高"),include.lowest = TRUE)
一次通过。
那天下午我很兴奋,但晚上冷静下来,有点后怕:
如果我一直依赖它,我还会debug吗? 如果它哪天不能用了,我还能独立写吗? 我现在的能力,到底是“我会”,还是“我会问”?
三天总结
免费模型M:能写结构,但不懂真实数据环境(编码、脏数据、列名问题)。 ChatGPT:能写对,但默认你是进阶用户(代码偏复杂、隐含决策多)。 Claude:最接近“有经验的同事”(稳、清晰、考虑数据问题)。
最后我的结论
我还是回去自己写代码了。
不是AI不行,而是:有些能力,必须长在自己身上。
AI可以帮你写代码、提供思路、快速试错。但它不能帮你理解数据、判断异常、建立数据直觉。
它更像是——一个放大器。你本来会一点,它让你更快;但如果你完全不会,它只会让你“看起来会”。
一句话总结:AI是拐杖,不是腿。
互动
你平时写代码最常用哪个AI?翻过最离谱的车是什么?
点个关注,下回见。
夜雨聆风