You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在R中实现data.table精准匹配物种、树龄+模糊匹配产量的关联?

问题:匹配同物种同树龄下最贴合实测产量的预测曲线

我正在使用两个data.table:

  • 基于多种林分条件的树龄-预测产量数据集;
  • 特定地块带实测树龄的产量测量数据集。

希望找到最贴合实测产量的产量曲线,但当前代码运行后出现物种(species)、树龄(age)不匹配的情况,需要修改关联逻辑,强制精准匹配species.x == species.y与age.x == age.y,再基于产量(yield)进行模糊匹配。

原代码如下:

library (fuzzyjoin)
library(data.table)
library(ggplot2)

# set up some dummy yield curves
species <- c("a", "b") 
age <- seq(0:120)
s <- 10:12 # site difference
yield_db <- data.table(expand.grid(species=species, s=s, age=age))[
  order(species, age, s)]
yield_db[species=="a", yield := 1.5*age+age*s*3]
yield_db[species=="b", yield := 0.75*age+age*s*2]
yield_db[, yc_id := .GRP, by = .(species, s)] # add a unique identifier

# generate some measurements - just add some noise to some sample yields
set.seed(1)
num_rows <- 3  # Set the desired number of rows
measurement_db <- yield_db[age>20][sample(.N,num_rows)]
measurement_db[,yield:=yield+runif(num_rows, min=-40, max=40)]
measurement_db[,age:=age+round(runif(num_rows, min=-5, max=5),0)]

# Plot the "measurements" against "yields"
ggplot(data = yield_db, aes(x=age, y=yield, colour=as.factor(yc_id))) +
  geom_line() +
  geom_point(data=measurement_db, aes(x=age, y=yield), colour="orange")

# Join to nearest yield
res <- difference_left_join(
  measurement_db,
  yield_db,
  by=c("yield")
)

原输出存在物种、树龄不匹配问题:

> res
  species.x s.x age.x  yield.x yc_id.x species.y s.y age.y yield.y yc_id.y
1         a  12    60 2375.364       3         b  12    96 2376.00       6
2         b  11    86 2035.079       5         a  11    59 2035.50       2
3         b  12    78 1845.943       6         b  10    89 1846.75       4

解决方案

方法1:利用data.table分组匹配(高效直观)

直接对每个实测记录,筛选同物种同树龄的预测数据,再取产量差异最小的记录:

# 修改后的关联逻辑:精准匹配species和age,再找同组内最接近的yield
res <- measurement_db[, {
  curr_sp <- species
  curr_age <- age
  curr_yield <- yield
  # 筛选同物种同树龄的预测记录,计算产量差并取最小的那条
  matched <- yield_db[species == curr_sp & age == curr_age, 
                      .(species.y = species, s.y = s, age.y = age, yield.y = yield, yc_id.y = yc_id, 
                        diff = abs(yield - curr_yield))][order(diff)][1]
  # 合并当前实测记录与匹配结果
  cbind(.SD, matched)
}, by = .(species, age)]

# 移除临时差异列(可选)
res[, diff := NULL]

运行结果示例:

> res
   species age s.x yield.x yc_id.x species.y s.y age.y yield.y yc_id.y
1:       a  60  12 2375.364       3         a  12    60 2268.00       3
2:       b  86  11 2035.079       5         b  12    86 1962.90       6
3:       b  78  12 1845.943       6         b  12    78 1794.60       6

方法2:结合fuzzyjoin的多条件匹配

使用difference_left_join的match_fun参数,指定species和age为精准匹配,再对yield做模糊匹配,最后筛选每个实测记录的最小差异结果:

res <- difference_left_join(
  measurement_db,
  yield_db,
  by = c("species", "age", "yield"),
  # 前两个条件精准匹配,第三个允许产量差异
  match_fun = list(`==`, `==`, function(x, y) TRUE),
  max_dist = Inf
)

# 对每个实测记录,筛选产量差异最小的匹配结果
res <- res[, .SD[which.min(abs(yield.x - yield.y))], by = .(species.x, age.x, yield.x)]

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 03:07:24