如何用pivot_longer将树木属性宽表转为单树一行的长表
解决宽表转长表的
pivot_longer使用问题 首先修正你的测试数据代码(原代码存在格式问题,调整为更规范的tidyverse写法):
library(tidyverse) # 修正后的测试数据 test <- tibble( Plot_n = c("Plot1", "Plot2", "Plot3"), Tree1_spp = c("Abc", "Cde", "Efg"), Tree1_dbh1 = c(10, 15, 20), Tree1_dbh2 = c(15, 20, 25), Tree1_planted_or_not = c(1, 0, 1), Tree2_spp = c("Efg", "Cde", "Abc"), Tree2_dbh1 = c(25, 20, 15), Tree2_dbh2 = c(20, 15, 10), Tree2_planted_or_not = c(1, 0, 1) )
接下来是正确的pivot_longer调用,核心是用精准的正则拆分列名:
test_long <- test %>% pivot_longer( cols = -Plot_n, # 保留样地列,其余列转长格式 names_to = c("tree", ".values"), # 第一个捕获组存树木标识,第二个存属性名 names_pattern = "^(Tree\\d+)_(.*)$" # 正则拆分逻辑:TreeX + 属性部分 ) # 查看转换结果 test_long
原代码问题分析
你之前用的正则^([^_\n]+_).*(.*)有两个关键错误:
- 第一个捕获组
[^_\n]+_会把Tree1_(包含下划线)作为tree列的值,不符合需求; - 中间多余的
.*会打乱属性名的捕获逻辑,导致无法正确识别planted_or_not这类带下划线的属性。
正则表达式解释
^(Tree\\d+)_(.*)$的具体含义:
^:匹配列名开头(Tree\\d+):捕获树木标识(比如Tree1、Tree2),对应tree列_:匹配列名中的固定下划线分隔符(.*):捕获下划线后的所有内容(比如spp、dbh1、planted_or_not),作为新的属性列名$:匹配列名结尾
最终结果结构
转换后的长表完全符合你的要求:
| Plot_n | tree | spp | dbh1 | dbh2 | planted_or_not |
|---|---|---|---|---|---|
| Plot1 | Tree1 | Abc | 10 | 15 | 1 |
| Plot1 | Tree2 | Efg | 25 | 20 | 1 |
| Plot2 | Tree1 | Cde | 15 | 20 | 0 |
| Plot2 | Tree2 | Cde | 20 | 15 | 0 |
| Plot3 | Tree1 | Efg | 20 | 25 | 1 |
| Plot3 | Tree2 | Abc | 15 | 10 | 1 |
内容的提问来源于stack exchange,提问作者Rhett
相关产品推荐
相关产品推荐

