如何优雅处理首两行含双标识的非规范数据?(tidy data整理)
优雅处理非规范数据为Tidy Data的方法
这种前两行包含元数据、后续是观测值的非规范格式确实容易让人卡壳——尤其是gather(现在叫pivot_longer)默认是处理单列名称的场景,硬写逻辑又太粗糙。我之前碰到过类似的情况,用tidyverse的工具组合可以很优雅地解决,完全不用hacky的操作:
首先先明确我们要的tidy目标:每一行对应一个独立观测,包含Variable(x1/x2/x3)、Date、Equip和Value四个字段,结构大概是这样:
| Variable | Date | Equip | Value |
|---|---|---|---|
| x1 | 12/16/18 | a | 1 |
| x1 | 12/17/18 | b | 2 |
| x2 | 12/16/18 | a | 3 |
| ... | ... | ... | ... |
具体步骤(用R的tidyverse实现)
1. 加载工具包并构造原始数据
先把你的示例数据转成可处理的数据框(如果是从文件读取,用read.table的时候注意不要把前两行当成表头):
library(tidyverse) # 模拟原始数据(如果是读文件,用read.table("your_data.txt", header = FALSE)) raw_data <- tibble( V1 = c(1, 2, 3, 4, 5), V2 = c("Date", "Equip", "x1", "x2", "x3"), V3 = c("12/16/18", "a", "1", "3", "5"), V4 = c("12/17/18", "b", "2", "4", "6") )
2. 提取并整理元数据
把前两行的Date和Equip信息转成列与属性的对应关系:
# 提取Date和对应列的映射 date_map <- raw_data %>% slice(1) %>% # 取第一行元数据 select(V3:V4) %>% # 只保留日期列 pivot_longer(everything(), names_to = "col", values_to = "Date") # 提取Equip和对应列的映射 equip_map <- raw_data %>% slice(2) %>% # 取第二行元数据 select(V3:V4) %>% pivot_longer(everything(), names_to = "col", values_to = "Equip") # 合并成完整的列属性映射表 col_metadata <- left_join(date_map, equip_map, by = "col")
3. 处理观测数据并关联元数据
把后面的观测值转成长格式,再和元数据关联得到tidy结果:
tidy_data <- raw_data %>% slice(3:n()) %>% # 跳过前两行元数据,只保留观测值 select(V2, V3, V4) %>% # 去掉无关的V1列 rename(Variable = V2) %>% # 重命名变量列 pivot_longer(cols = c(V3, V4), names_to = "col", values_to = "Value") %>% # 转成长格式 left_join(col_metadata, by = "col") %>% # 关联日期和设备信息 select(Variable, Date, Equip, Value) %>% # 调整列顺序到tidy结构 mutate(Value = as.numeric(Value)) # 把值转成数值型(按需)
运行完后tidy_data就是标准的tidy格式了,打印出来看看:
print(tidy_data) #> # A tibble: 6 × 4 #> Variable Date Equip Value #> <chr> <chr> <chr> <dbl> #> 1 x1 12/16/18 a 1 #> 2 x1 12/17/18 b 2 #> 3 x2 12/16/18 a 3 #> 4 x2 12/17/18 b 4 #> 5 x3 12/16/18 a 5 #> 6 x3 12/17/18 b 6
这个方法的优势在于完全依赖tidyverse的标准函数,没有硬编码列名或位置,哪怕你的数据列数变多(比如多几个日期/设备),代码也能直接复用,非常灵活。
内容的提问来源于stack exchange,提问作者Lloyd Christmas
相关产品推荐
相关产品推荐

