Tôi đang cố gắng điều chỉnh hàm phân rã theo hàm mũ cho các giá trị y trở thành âm ở giá trị x cao, nhưng không thể định cấu hình nls
chính xác chức năng của tôi .
Mục đích
Tôi quan tâm đến độ dốc của hàm phân rã ( theo một số nguồn ). Làm thế nào tôi có được độ dốc này không quan trọng, nhưng mô hình phải phù hợp với dữ liệu của tôi nhất có thể (nghĩa là tuyến tính hóa vấn đề có thể chấp nhận được , nếu sự phù hợp là tốt; xem "tuyến tính hóa"). Tuy nhiên, các công trình trước đây về chủ đề này đã sử dụng hàm phân rã theo cấp số nhân sau ( bài viết truy cập đóng của Stedmon et al., Phương trình 3 ):
nơi S
có độ dốc Tôi đang quan tâm, K
các yếu tố điều chỉnh để cho phép các giá trị âm và a
giá trị ban đầu cho x
(tức là đánh chặn).
Tôi cần phải làm điều này trong R, vì tôi đang viết một hàm chuyển đổi các phép đo thô của chất hữu cơ hòa tan chromophoric (CDOM) thành các giá trị mà các nhà nghiên cứu quan tâm.
Dữ liệu mẫu
Do tính chất của dữ liệu, tôi đã phải sử dụng PasteBin. Các dữ liệu ví dụ có sẵn ở đây .
Viết dt <-
và sao chép mã fom PasteBin vào bảng điều khiển R của bạn. I E
dt <- structure(list(x = ...
Dữ liệu trông như thế này:
library(ggplot2)
ggplot(dt, aes(x = x, y = y)) + geom_point()
Giá trị y âm diễn ra khi .
Đang cố gắng tìm giải pháp bằng cách sử dụng nls
Nỗ lực ban đầu bằng cách sử dụng nls
tạo ra một điểm kỳ dị, điều không nên ngạc nhiên khi thấy rằng tôi chỉ nhìn thấy các giá trị bắt đầu cho các tham số:
nls(y ~ a * exp(-S * x) + K, data = dt, start = list(a = 0.5, S = 0.1, K = -0.1))
# Error in nlsModel(formula, mf, start, wts) :
# singular gradient matrix at initial parameter estimates
Theo câu trả lời này , tôi có thể cố gắng tạo ra các tham số khởi động phù hợp tốt hơn để giúp nls
chức năng:
K0 <- min(dt$y)/2
mod0 <- lm(log(y - K0) ~ x, data = dt) # produces NaNs due to the negative values
start <- list(a = exp(coef(mod0)[1]), S = coef(mod0)[2], K = K0)
nls(y ~ a * exp(-S * x) + K, data = dt, start = start)
# Error in nls(y ~ a * exp(-S * x) + K, data = dt, start = start) :
# number of iterations exceeded maximum of 50
Hàm dường như không thể tìm thấy một giải pháp với số lần lặp mặc định. Hãy tăng số lần lặp:
nls(y ~ a * exp(-S * x) + K, data = dt, start = start, nls.control(maxiter = 1000))
# Error in nls(y ~ a * exp(-S * x) + K, data = dt, start = start, nls.control(maxiter = 1000)) :
# step factor 0.000488281 reduced below 'minFactor' of 0.000976562
Nhiều lỗi hơn. Chộp lấy nó! Chúng ta hãy buộc hàm cung cấp cho chúng ta một giải pháp:
mod <- nls(y ~ a * exp(-S * x) + K, data = dt, start = start, nls.control(maxiter = 1000, warnOnly = TRUE))
mod.dat <- data.frame(x = dt$x, y = predict(mod, list(wavelength = dt$x)))
ggplot(dt, aes(x = x, y = y)) + geom_point() +
geom_line(data = mod.dat, aes(x = x, y = y), color = "red")
Chà, đây chắc chắn không phải là một giải pháp tốt ...
Tuyến tính hóa vấn đề
Nhiều người đã tuyến tính hóa các hàm phân rã theo cấp số nhân của họ với một thành công (nguồn: 1 , 2 , 3 ). Trong trường hợp này, chúng tôi cần đảm bảo rằng không có giá trị y nào âm hoặc 0. Hãy tạo giá trị y tối thiểu càng gần 0 càng tốt trong giới hạn dấu phẩy động của máy tính :
K <- abs(min(dt$y))
dt$y <- dt$y + K*(1+10^-15)
fit <- lm(log(y) ~ x, data=dt)
ggplot(dt, aes(x = x, y = y)) + geom_point() +
geom_line(aes(x=x, y=exp(fit$fitted.values)), color = "red")
Tốt hơn nhiều, nhưng mô hình không theo dõi các giá trị y một cách hoàn hảo ở các giá trị x thấp.
Lưu ý rằng nls
hàm vẫn sẽ không quản lý để phù hợp với phân rã theo cấp số nhân:
K0 <- min(dt$y)/2
mod0 <- lm(log(y - K0) ~ x, data = dt) # produces NaNs due to the negative values
start <- list(a = exp(coef(mod0)[1]), S = coef(mod0)[2], K = K0)
nls(y ~ a * exp(-S * x) + K, data = dt, start = start)
# Error in nlsModel(formula, mf, start, wts) :
# singular gradient matrix at initial parameter estimates
Các giá trị âm có quan trọng không?
Các giá trị âm rõ ràng là một lỗi đo lường vì hệ số hấp thụ không thể âm. Vậy điều gì sẽ xảy ra nếu tôi làm cho các giá trị y trở nên tích cực? Đó là độ dốc tôi quan tâm. Nếu bổ sung không ảnh hưởng đến độ dốc, tôi nên giải quyết:
dt$y <- dt$y + 0.1
fit <- lm(log(y) ~ x, data=dt)
ggplot(dt, aes(x = x, y = y)) + geom_point() + geom_line(aes(x=x, y=exp(fit$fitted.values)), color = "red")
Chà, điều này không thành công lắm ... Giá trị x cao rõ ràng nên càng gần 0 càng tốt.
Câu hỏi
Tôi rõ ràng đang làm điều gì đó sai ở đây. Cách chính xác nhất để ước tính độ dốc cho hàm phân rã theo hàm mũ được trang bị trên dữ liệu có giá trị y âm sử dụng R là gì?
nls
hội tụ cho tôi bằng cách sử dụng các giá trị bắt đầu . Ngoài ra, bạn có thể sử dụng chức năng tự khởi động : . Điều đó hội tụ cho tôi quá.nls(y~SSasymp(x, Asym, r0, lrc), data = dt)