0

I'm having a bit of trouble understanding how to write a function and extract parameters from a matrix in R. This is similar to Non linear fit in r but I haven't quite figured it out.

As an example, I've already used a linear fit to extract the y intercept and slope from the same data and apply those as a new columns in the matrix:

library(tidyverse)
library(lazyeval)

design.mat <- cbind(1,c(340,340.33,340.66,341,342,343,346,349,352,355,358,368,378,388,398)) #design matrix with x values of time points
response.mat <- t(ts_rw[,36:50]) # transform rows to columns and select relevant points
reg <- lm.fit(design.mat, response.mat)$coefficients #linear fit to time points, extract intercept and slope (coefficients)
ts_rw <- cbind(ts_rw, t(reg)) #re-transform (intercept and slope for each row are added in new columns)

where ts_rw is a large rowwise matrix with each column a time point and each row an individual

head(ts_rw)
individual X2      X3      X4      X5     X6     X7     X8     X9    X10    X11    X12    X13    X14    X15    X16    X17    X18
1      <NA>  0 0.77150 1.17260 1.62550 2.6667 3.0663 3.2323 3.3331 3.4293 3.5010 3.6000 3.6099 3.6941 4.1558 4.2500 4.3215 4.3215
2  PI665092  0 0.71872 1.00040 1.25040 1.9385 2.3136 2.5397 2.7147 2.8328 2.9164 3.0014 3.0828 3.1824 3.6377 3.7900 3.9024 4.0000
3  PI665092  0 0.58076 0.84209 1.03010 2.0000 2.6109 2.9331 3.1266 3.2663 3.3763 3.4662 3.5404 3.6437 4.0007 4.0794 4.1032 4.0828

with many more rows and columns.

As a simplified bit of data, from the columns of interest:

timepoints <- c(340,340.33,340.66,341,342,343,346,349,352,355,358,368,378,388,398)
row2 <- as.numeric(as.vector(ts_rw[2,36:50]))
row3 <- as.numeric(as.vector(ts_rw[3,36:50]))

print(timepoints)
[1] 340.00 340.33 340.66 341.00 342.00 343.00 346.00 349.00 352.00 355.00 358.00 368.00 378.00 388.00 398.00
print(row2)
 [1] 3.56900 1.69690 1.35020 1.19020 0.96450 0.86805 0.77572 0.75023 0.82184 0.85174 0.84638 0.84638 0.78600 0.74063 0.71467
print(row3)
 [1] 5.5473 3.6941 3.3142 3.1771 2.7650 2.6260 2.4220 2.4710 2.6328 2.6328 2.5301 2.5301 2.4710 2.4748 2.4443

The function for the non-linear fit is:

Value = a*(exp(-b*time))+c

I would like to apply this in place of the lm.fit, in order to extract a, b, and c for each individual. Any ideas on a good way to do this? Thank you.

---update

I think the trouble lies in implementing correct start values; if I try something like this:

x <- c(340,340.33,340.66,341,342,343,346,349,352,355,358,368,378,388,398)
y <- as.numeric(as.vector(ts_rw[2,36:50]))

df <- data.frame(x,y)
print(df)
        x       y
1  340.00 3.56900
2  340.33 1.69690
3  340.66 1.35020
4  341.00 1.19020
5  342.00 0.96450
6  343.00 0.86805
7  346.00 0.77572
8  349.00 0.75023
9  352.00 0.82184
10 355.00 0.85174
11 358.00 0.84638
12 368.00 0.84638
13 378.00 0.78600
14 388.00 0.74063
15 398.00 0.71467

m <- nls(y ~ I(a*(exp(-b*x))+c), data=df, start=list(a=max(y), b=6.4, c=0.8), alg="plinear",trace=T)
y_est<-predict(m,df$x)
plot(x,y)
lines(x,y_est)
summary(m)

attempting to calculate estimates for coefficients a,b, and c as in this question

summary(m)
Error in chol2inv(object$m$Rmat()) : 
  element (2, 2) is zero, so the inverse cannot be computed

The fit doesn't work out

enter image description here

17/12/20 addition:

Is there good way to implement nlsList with the design and response matrix approach? Something like

design.mat <- cbind(1,c(340,340.33,340.66,341,342,343,346,349,352,355,358,368,378,388,398)) 
response.mat <- t(ts_rw[,36:50]) 
reg <- nlsList(y ~ exp(-b *(x + d)),data=c(design.mat, response.mat),start=list(b=0.3, c = 0.5, d = -339))$coefficients 
ts_rw <- cbind(ts_rw, t(reg))

only in this the data argument is invalid as it's looking for a standard xy dataframe.

Update 17/12/20

Reshaped dataframe to use in nlslist model format. In case it may help someone, here's a summary of where things are at, starting with the initial few individuals from the dataframe (which had to be renamed individually to avoid the model grouping them as replicates):

ts_rw %>% head(5)

    accession X2      X3      X4      X5     X6     X7     X8     X9    X10    X11    X12    X13    X14    X15    X16
1     id_disc  0 0.77150 1.17260 1.62550 2.6667 3.0663 3.2323 3.3331 3.4293 3.5010 3.6000 3.6099 3.6941 4.1558 4.2500
2 PI665092_43  0 0.71872 1.00040 1.25040 1.9385 2.3136 2.5397 2.7147 2.8328 2.9164 3.0014 3.0828 3.1824 3.6377 3.7900
3 PI665092_44  0 0.58076 0.84209 1.03010 2.0000 2.6109 2.9331 3.1266 3.2663 3.3763 3.4662 3.5404 3.6437 4.0007 4.0794
4 NSL54162_43  0 0.41834 0.57771 0.73795 1.2189 1.6075 1.9582 2.3481 2.6006 2.7776 2.9443 3.0010 3.1266 3.6893 4.0000
5 NSL54162_44  0 0.23645 0.42549 0.63412 1.3080 1.6542 1.9132 2.1887 2.4286 2.6260 2.7776 2.9250 3.0012 3.6656 3.9297
     X17    X18    X19    X20    X21    X22    X23    X24    X25    X26    X27    X28    X29    X30    X31    X32
1 4.3215 4.3215 4.3102 4.3102 4.2883 4.2737 4.3030 4.2275 4.1664 4.1664 4.0921 4.0794 4.0794 4.0794 4.0794 4.0794
2 3.9024 4.0000 4.1032 4.1068 4.1104 4.1104 4.1248 4.1104 4.1032 4.0976 4.0009 4.0000 3.9065 3.9024 3.8193 3.7280
3 4.1032 4.0828 4.0828 4.1558 4.1833 4.2330 4.3649 4.4561 4.5465 4.5828 4.6664 4.7289 4.8193 4.8328 4.9034 5.0017
4 4.5411 5.0029 5.5473 5.9043 6.2219 6.5003 6.9043 7.1249 7.4437 7.5710 7.7771 7.8885 8.2500 8.4985 8.7504 9.2484
5 4.2737 4.6664 5.0038 5.3039 5.5038 5.5552 5.6249 5.6249 5.6041 5.6667 5.7036 5.8039 5.9979 6.1041 6.1104 6.2219
     X33     X34     X35     X36     X37     X38     X39     X40      X41     X42     X43     X44     X45     X46
1 4.0022  4.0022  4.0000  4.0022  1.4130  1.2761  1.2147  1.0331  0.93759 0.88252 0.86885 0.84830 0.80672 0.72985
2 3.7026  3.7026  3.6023  3.5690  1.6969  1.3502  1.1902  0.9645  0.86805 0.77572 0.75023 0.82184 0.85174 0.84638
3 5.1032  5.2036  5.3649  5.5473  3.6941  3.3142  3.1771  2.7650  2.62600 2.42200 2.47100 2.63280 2.63280 2.53010
4 9.8558 10.5000 11.3310 11.8000 11.0000 10.8330 10.8000 10.3330 10.28400 9.71380 9.42720 9.33280 9.14200 8.83280
5 6.2495  6.3333  6.5003  6.6667  6.2854  6.0000  6.0000  5.7503  5.62490 5.50380 5.30390 5.30390 5.30390 5.10320
      X47    X48     X49 npq_end npq_max npq_up_yint npq_slope_up npq_slope_down
1 0.62518 0.5408 0.48702 0.45223  4.3215  0.10449764    1.5837233     -2.5429803
2 0.84638 0.7860 0.74063 0.71467  4.1248  0.14077229    1.2092617     -2.2405433
3 2.53010 2.4710 2.47480 2.44430  5.5473  0.11330366    1.0048922     -2.2426498
4 8.75040 8.5701 8.33130 8.25000 11.8000  0.07942392    0.7117107     -0.9479913
5 5.18330 5.0921 5.00000 5.00170  6.6667  0.01161035    0.6279491     -0.6844091

###

ts_dark <- ts_rw[-c(2:35,51:54)] #subset out columns of interest for this model

#rename columns by time point (minutes)
colnames(ts_dark)[2:16] <- c("340","340.33","340.66","341","342","343","346","349","352","355","358","368","378","388","398")

#reshape to long format
ts_long <- ts_dark %>%
  melt(id.var="accession") %>%
  arrange(accession, variable)

ts_long$variable <- as.numeric(as.character(ts_long$variable)) #convert variable column from factor to numeric for model

#run model on all individuals
reg <- nlsList(value ~ exp(-b *(variable + d)) + c |accession, data=ts_long, start=list(b=0.3, c = 0.5, d = -339)) #fit model to dark time points, extract intercept and slope (coefficients)

The model only throws a singular gradient error for one individual and three "missing value or infinity" errors, out out 81.

chazmatazz
  • 133
  • 1
  • 9
  • Reshape your data and use [`nlsList`](https://www.rdocumentation.org/packages/nlme/versions/3.1-150/topics/nlsList). – Roland Nov 05 '20 at 14:19
  • Thanks, I've added some info. I'm having trouble understanding how to apply the model in general. Presumably if I can get it working for a single individual then nlsList can be easily applied to the rest of the matrix. – chazmatazz Nov 06 '20 at 10:10
  • 1
    You need a different model. Try, e.g., `m <- nls(y ~ exp(-b *(x + d)) + c, data=df, start=list(b=0.3, c = 0.5, d = -339),trace=T)`. – Roland Nov 08 '20 at 14:59

0 Answers0