动态拟合两条直线并在 R 中获取这些直线之间的交叉点
Dynamically fitting two straight lines and getting the crossing point between those lines in R
我有一个像
这样的光谱反射率数据
library(hsdar)
library(tidyverse)
##Create some data
parameter <- data.frame(N = seq(1, 1.5, 0.05), LAI = seq(1,6,0.5))
spec <- PROSAIL(parameterList=parameter)
然后我计算了数据的一阶导数
d1 <- derivative.speclib(spec)
我使用以下代码从 d1 object 中提取了数据帧
d1_df <- d1@spectra@spectra_ma
d1_wav <- d1@wavelength
colnames(d1_df) <- d1_wav
#Plotting of the data
matplot(d1_wav,t(d1_df[1:11,]),type='l', xlim = c(660, 800), ylim=c(-0.01,+0.01), xlab='Wavelength /nm',ylab='Reflectance')
然后我将 far-red(680 到 700 nm)和 NIR(725 到 760 nm)区域子集化为
d1_df %>% as.data.frame() %>%
setNames(paste0("WV_", names(.))) %>%
mutate(ID = seq.int(nrow(.))) %>%
select(281:301, ID) %>%
pivot_longer(cols = -ID) %>%
separate(name, c("chr", "wv"), convert = T)
d1_df %>% as.data.frame() %>%
setNames(paste0("WV_", names(.))) %>%
mutate(ID = seq.int(nrow(.))) %>%
select(326:361, ID) %>%
pivot_longer(cols = -ID) %>%
separate(name, c("chr", "wv"), convert = T)
现在如何对两个区域分别拟合两条直线,得到下图中每个ID对应的两条直线交点的x?
这个问题没有唯一的答案,因为没有唯一的反射线(每个 ID 都有自己的反射线,因此有自己唯一的交叉点)。如果我们像这样获取您的子集数据:
region_A <- d1_df %>% as.data.frame() %>%
setNames(paste0("WV_", names(.))) %>%
mutate(ID = seq.int(nrow(.))) %>%
select(290:301, ID) %>%
pivot_longer(cols = -ID) %>%
separate(name, c("chr", "wv"), convert = T) %>%
mutate(ID = factor(ID))
region_B <- d1_df %>% as.data.frame() %>%
setNames(paste0("WV_", names(.))) %>%
mutate(ID = seq.int(nrow(.))) %>%
select(332:350, ID) %>%
pivot_longer(cols = -ID) %>%
separate(name, c("chr", "wv"), convert = T) %>%
mutate(ID = factor(ID))
绘制出来,我们看到:
p <- ggplot(region_A, aes(x = wv, y = value, group = ID)) +
geom_line() +
geom_line(data = region_B)
p
如果我们推断这些线,我们可以看到它们以不同的波长交叉:
p <- p + geom_smooth(method = "lm", formula = y ~ x, fullrange = TRUE,
aes(colour = factor(ID)), se = FALSE) +
geom_smooth(method = "lm", formula = y ~ x, fullrange = TRUE,
data = region_B, aes(colour = factor(ID)), se = FALSE) +
coord_cartesian(ylim = c(0, 0.0125))
p
我们可以像这样对每条线进行线性回归:
modA <- lm(value ~ wv * ID, data = region_A)
modB <- lm(value ~ wv * ID, data = region_B)
我们可以定义一个函数,当两个模型在特定波长下的预测相同时,returns 0,如下所示:
meet_at <- function(X, ID)
{
A <- predict(modA, newdata = list(wv = X, ID = ID))
B <- predict(modB, newdata = list(wv = X, ID = ID))
abs(A - B)
}
这使我们能够使用 optimise
函数为两条线中的每一条找到交叉点和 return 一个不错的结果数据框,如下所示:
df <- do.call(rbind, lapply(unique(region_A$ID), function(i) {
wv <- optimize(meet_at, c(700, 740), ID = i)$minimum
value <- predict(modA, newdata = list(wv = wv, ID = i))
data.frame(wv, value, ID = as.character(i))
}))
df
#> wv value ID
#> 1 708.8861 0.004254394 1
#> 11 710.4923 0.005915650 2
#> 12 712.1372 0.007343448 3
#> 13 713.6095 0.008527553 4
#> 14 714.8414 0.009483770 5
#> 15 715.8220 0.010241372 6
#> 16 716.5676 0.010833544 7
#> 17 717.1078 0.011292029 8
#> 18 717.4764 0.011644701 9
#> 19 717.7071 0.011914912 10
#> 110 717.8309 0.012121712 11
如果我们在绘图上绘制这些点,我们就知道这些结果是正确的:
p + geom_vline(data = df, aes(xintercept = wv, colour = ID)) +
geom_point(data = df)
所以你的问题的答案是根据 ID
在 708 和 718 nm 之间的波长范围内发生交叉,具体细节根据 df
我有一个像
这样的光谱反射率数据library(hsdar)
library(tidyverse)
##Create some data
parameter <- data.frame(N = seq(1, 1.5, 0.05), LAI = seq(1,6,0.5))
spec <- PROSAIL(parameterList=parameter)
然后我计算了数据的一阶导数
d1 <- derivative.speclib(spec)
我使用以下代码从 d1 object 中提取了数据帧
d1_df <- d1@spectra@spectra_ma
d1_wav <- d1@wavelength
colnames(d1_df) <- d1_wav
#Plotting of the data
matplot(d1_wav,t(d1_df[1:11,]),type='l', xlim = c(660, 800), ylim=c(-0.01,+0.01), xlab='Wavelength /nm',ylab='Reflectance')
然后我将 far-red(680 到 700 nm)和 NIR(725 到 760 nm)区域子集化为
d1_df %>% as.data.frame() %>%
setNames(paste0("WV_", names(.))) %>%
mutate(ID = seq.int(nrow(.))) %>%
select(281:301, ID) %>%
pivot_longer(cols = -ID) %>%
separate(name, c("chr", "wv"), convert = T)
d1_df %>% as.data.frame() %>%
setNames(paste0("WV_", names(.))) %>%
mutate(ID = seq.int(nrow(.))) %>%
select(326:361, ID) %>%
pivot_longer(cols = -ID) %>%
separate(name, c("chr", "wv"), convert = T)
现在如何对两个区域分别拟合两条直线,得到下图中每个ID对应的两条直线交点的x?
这个问题没有唯一的答案,因为没有唯一的反射线(每个 ID 都有自己的反射线,因此有自己唯一的交叉点)。如果我们像这样获取您的子集数据:
region_A <- d1_df %>% as.data.frame() %>%
setNames(paste0("WV_", names(.))) %>%
mutate(ID = seq.int(nrow(.))) %>%
select(290:301, ID) %>%
pivot_longer(cols = -ID) %>%
separate(name, c("chr", "wv"), convert = T) %>%
mutate(ID = factor(ID))
region_B <- d1_df %>% as.data.frame() %>%
setNames(paste0("WV_", names(.))) %>%
mutate(ID = seq.int(nrow(.))) %>%
select(332:350, ID) %>%
pivot_longer(cols = -ID) %>%
separate(name, c("chr", "wv"), convert = T) %>%
mutate(ID = factor(ID))
绘制出来,我们看到:
p <- ggplot(region_A, aes(x = wv, y = value, group = ID)) +
geom_line() +
geom_line(data = region_B)
p
如果我们推断这些线,我们可以看到它们以不同的波长交叉:
p <- p + geom_smooth(method = "lm", formula = y ~ x, fullrange = TRUE,
aes(colour = factor(ID)), se = FALSE) +
geom_smooth(method = "lm", formula = y ~ x, fullrange = TRUE,
data = region_B, aes(colour = factor(ID)), se = FALSE) +
coord_cartesian(ylim = c(0, 0.0125))
p
我们可以像这样对每条线进行线性回归:
modA <- lm(value ~ wv * ID, data = region_A)
modB <- lm(value ~ wv * ID, data = region_B)
我们可以定义一个函数,当两个模型在特定波长下的预测相同时,returns 0,如下所示:
meet_at <- function(X, ID)
{
A <- predict(modA, newdata = list(wv = X, ID = ID))
B <- predict(modB, newdata = list(wv = X, ID = ID))
abs(A - B)
}
这使我们能够使用 optimise
函数为两条线中的每一条找到交叉点和 return 一个不错的结果数据框,如下所示:
df <- do.call(rbind, lapply(unique(region_A$ID), function(i) {
wv <- optimize(meet_at, c(700, 740), ID = i)$minimum
value <- predict(modA, newdata = list(wv = wv, ID = i))
data.frame(wv, value, ID = as.character(i))
}))
df
#> wv value ID
#> 1 708.8861 0.004254394 1
#> 11 710.4923 0.005915650 2
#> 12 712.1372 0.007343448 3
#> 13 713.6095 0.008527553 4
#> 14 714.8414 0.009483770 5
#> 15 715.8220 0.010241372 6
#> 16 716.5676 0.010833544 7
#> 17 717.1078 0.011292029 8
#> 18 717.4764 0.011644701 9
#> 19 717.7071 0.011914912 10
#> 110 717.8309 0.012121712 11
如果我们在绘图上绘制这些点,我们就知道这些结果是正确的:
p + geom_vline(data = df, aes(xintercept = wv, colour = ID)) +
geom_point(data = df)
所以你的问题的答案是根据 ID
在 708 和 718 nm 之间的波长范围内发生交叉,具体细节根据 df