数据清洗基本功:dplyr包的五虎将
咱们做质量控制分析,有个铁律:垃圾进,垃圾出。数据没洗干净,后面再漂亮的统计模型也是白搭。
我当年刚入行时,接手一批生产线的传感器数据。好家伙,几千行数据里,居然有列名带空格、缺失值写了个"9999"、日期格式混了三种。手工在Excel里改了三天,结果手一抖还拖歪了一列。从那以后,我就铁了心用R的dplyr包来管数据清洗。
今天咱们就聊dplyr里的五个核心函数——filter、select、mutate、arrange、summarise。掌握了这五个,你处理质控数据就能告别复制粘贴了。
4.1 filter():把垃圾行扔出去
filter() 的活儿很简单——按条件留下需要的行。就像在Excel里做筛选,但dplyr的语法更干净、可重复。
library(dplyr)
# 基础用法:筛选温度在20~30度之间的样本
clean_data <- raw_data %>%
filter(temperature >= 20, temperature <= 30)
参数说明:
- 第一个参数是数据框
- 后续参数写逻辑条件,多个条件默认是 AND 关系
- 如果想用 OR,写
|
我在项目中最常用的是这个场景:质量检测数据里经常有"预检记录"和"正式记录"混在一起。用filter(tag == "正式")一刀切掉预检数据,干净利落。
filter(!is.na(关键指标)) 这行代码能帮你过滤掉大量不完整记录。跑分析前,先确认缺失值如何处理。
多条件示例:
# 保留A类产品中,重量在100±2g且外观合格的行
valid_A <- products %>%
filter(category == "A",
weight >= 98, weight <= 102,
appearance == "合格")
4.2 select():别让无关列碍眼
数据框几百列的时候,你看得眼花?select() 就是你的"列减负工具"。
# 只保留批次号、检测时间和三个关键指标
narrow_data <- wide_data %>%
select(batch_id, test_time, hardness, thickness, gloss)
常用写法一览:
| 写法 | 含义 | 例子 |
|---|---|---|
select(col1, col2) |
保留指定列 | select(batch, value) |
select(-col1) |
剔除指定列 | select(-remark) |
select(starts_with("质量")) |
列名以"质量"开头 | select(starts_with("qc_")) |
select(contains("date")) |
列名包含"date" | select(contains("时间")) |
select(where(is.numeric)) |
只选数值型列 | 常用于批量计算 |
我记得有一次拿到供应商的数据,他们给了一个200多列的表格,里面还有5列叫"备注1"到"备注5"。我直接用select(-starts_with("备注"))清掉了,省了半小时手工删除。
select()不会更改原始数据框。如果你想把结果保存下来,必须赋值。data <- data %>% select(...)才是真正覆盖。
4.3 mutate():自己动手造新指标
原始数据里没有你想要的计算字段?mutate() 就是你的"造列器"。
# 计算偏差百分比和判定结果
qc_data <- sample_data %>%
mutate(
deviation_pct = (measured - nominal) / nominal * 100,
status = if_else(abs(deviation_pct) <= 5, "合格", "待复检")
)
几点实战经验:
- 新列可以引用同一条记录的其他列,也可以引用整个向量
- 想保留旧列同时加新列,直接写;
mutate()默认保留全部列 - 如果只想保留新列,用
transmute()
我在处理SPC数据时,经常需要算 "这个批次偏离规格中心多少"。一个 mutate(偏移量 = 平均值 - 规格中心) 就搞定。要是手工在Excel里拉公式,几十个文件够你拉一天。
# 多个转换一起做
spc_summary <- batch_stats %>%
mutate(
cp = (usl - lsl) / (6 * std_dev),
cpk = min(
(usl - mean) / (3 * std_dev),
(mean - lsl) / (3 * std_dev)
),
conclusion = case_when(
cpk >= 1.67 ~ "优秀",
cpk >= 1.33 ~ "良好",
cpk >= 1.00 ~ "一般",
TRUE ~ "需改进"
)
)
case_when() 做多条件判定时,条件按顺序匹配,命中第一个就停止。把最严格的条件写在最前面。
4.4 arrange():给数据排排队
数据默认都是按录入顺序排列的。做质控分析时,按时间排序是家常便饭。
# 按生产日期升序,同一天内按批次号降序
ordered_data <- production_log %>%
arrange(prod_date, desc(batch_no))
排序规则很简单:
- 默认升序(从小到大、从早到晚)
- 想降序:在外面套一层
desc() - 多个排序条件:依次写,越靠前的优先级越高
我碰到过一个坑:数据框的日期列存的是字符串("2024-01-15"这种),直接用arrange()排序会出现"2024-01-02"排在"2024-01-15"后面——因为字符串是按字典序比较的。得先mutate(date = as.Date(date))转成日期型再排序。
# 正确的日期排序姿势
sorted_by_date <- data %>%
mutate(test_date = as.Date(test_date, format = "%Y-%m-%d")) %>%
arrange(test_date)
arrange() 放在清洗的倒数第二步。先筛干净、选好列、算好指标,最后排个序,方便肉眼检查。
4.5 summarise():一句话出统计结果
这是dplyr里最有"分析味"的函数。它的作用是:把多行数据压缩成一行统计量。
# 计算整体合格率、均值和标准差
overall_summary <- inspection_data %>%
summarise(
总批次 = n(),
合格批次 = sum(result == "合格"),
合格率 = 合格批次 / 总批次 * 100,
平均强度 = mean(strength, na.rm = TRUE),
强度标准差 = sd(strength, na.rm = TRUE)
)
常用的汇总函数:
| 函数 | 含义 |
|---|---|
n() |
计数(当前组有多少行) |
sum() |
求和 |
mean() |
均值 |
sd() |
标准差 |
min() / max() |
最小值/最大值 |
你可能会问:如果我想按不同产品线分别算合格率呢?这就得配合 group_by() 了。这两个函数是天生搭档。
# 按生产线分组汇总
line_summary <- data %>%
group_by(生产线) %>%
summarise(
批次数量 = n(),
合格率 = mean(判定 == "合格", na.rm = TRUE) * 100,
.groups = "drop"
)
.groups = "drop",分组信息会保留在结果中。后续分析如果不小心再跟其他数据框操作,容易产生奇怪的问题。我建议每次都显式写出 .groups = "drop"。
4.6 案例:一个完整的清洗流程
来,咱们走一遍真实场景。假设你收到了三个月来每个批次的拉力测试数据,需要整理成按周分组的汇总报表。
# 原始数据 raw_data 包含:batch_id, prod_line, test_date,
# strength, thickness, result(合格/不合格)
clean_report <- raw_data %>%
# 第1步:只保留最近90天的有效检测
filter(!is.na(strength),
test_date >= Sys.Date() - 90) %>%
# 第2步:留有用字段
select(prod_line, test_date, strength, result) %>%
# 第3步:计算偏差指标
mutate(
周标签 = paste0(
format(test_date, "%Y"),
"-W",
format(test_date, "%V")
),
强度达标 = if_else(strength >= 50, TRUE, FALSE)
) %>%
# 第4步:按产线和周排序
arrange(prod_line, test_date) %>%
# 第5步:分组汇总
group_by(prod_line, 周标签) %>%
summarise(
检测数 = n(),
平均强度 = mean(strength, na.rm = TRUE),
强度标准差 = sd(strength, na.rm = TRUE),
合格率 = mean(强度达标, na.rm = TRUE) * 100,
.groups = "drop"
)
你看,用了五个函数配上管道操作,整个清洗和汇总流程一目了然。别人改天想复现你的结果,只要跑一遍这段代码就行。比你在Excel里点来点去强太多了。
好了,这一章就到这儿。数据洗干净了,下回咱们就能放心地画图做模型了。