[R] Applying function with separate dataframe (calibration file) supplying some inputs

Joshua Wiley jwiley.psych at gmail.com
Thu Oct 20 07:33:06 CEST 2011


Hi Nathan,

I honestly do not think that anything else will be much better than
merging the two datasets.  If the datasets are not merged, you
essentially have to apply your optode function to each vial, store the
results, then combine them all together.  This is innefficient.
Merging the datasets may be innefficient in a way, but once it is
done, your function can be applied to the entire dataset in one step.
If you have big data and the merge is slow, take a look at the
data.table package.  I have recently (not that it was bad before, I
just never really knew how much it could do) been quite impressed with
it.  As a whole other note, your optode function was quite difficult
to read, and I highly doubt you can confidently look at the code and
ensure there is not a typo, missed operator, etc. somewhere in that
block of formula code.  I attempted to clean it up some, though
perhaps not with 100% success.

#######################################
optode2 <- function(cal0, T0, cal100, T100, phase, temp) {
  dr <- pi/180
  f1 <- 0.801
  deltaPsiK <- (-0.08)
  deltaKsvK <- 0.000383
  m <- 22.9
  tan0T100 <- tan(((cal0 + deltaPsiK * (T100 - T0))) * dr)
  tan0Tm <- tan((cal0 + (deltaPsiK * (temp - T0))) * dr)
  tan100T100 <- tan(cal100 * dr)
  tanmTm <- tan(phase * dr)
  A <- tan100T100 / tan0T100 / m * 100^2

  B <- tan100T100 / tan0T100 * 100 + tan100T100 / tan0T100 / m *100 -
f1 / m * 100 - 100 + f1 * 100
  C <- tan100T100 / tan0T100 - 1
  KsvT100 <- (- B + (sqrt(B^2 - 4 * A * C))) / (2 * A)
  KsvTm <- KsvT100 + (deltaKsvK * (temp - T100))
  a <- tanmTm / tan0Tm / m * KsvTm^2
  b <- tanmTm / tan0Tm * KsvTm + tanmTm / tan0Tm / m * KsvTm - f1 / m
* KsvTm - KsvTm + f1 * KsvTm
  c <- tanmTm / tan0Tm - 1
  tot <- tanmTm / tan0T100
  big <- tot * KsvTm + tanmTm / tan0T100 / m * KsvTm - f1 / m * KsvTm
- KsvTm + f1 * KsvTm

  saturation <- (-big + (sqrt((big)^2-4 * (tanmTm / tan0T100 / m *
KsvTm^2) * (tot - 1)))) / (2 * (tot / m * KsvTm^2))
  return(saturation)
}

## Read in your example data
d1 <- read.table(textConnection("
vial cal0    T0  cal100  T100
1      61      18    28       18
2      60.8    18    27.1    18
3     60.2    18    28.3     18
4     59.8    18     27.2     18"), header = TRUE, stringsAsFactors = FALSE)
d2 <- read.table(textConnection("
vial   phase    temp   time
1       31            17.5    10
1       31.5          17.4    20
1       32.8          17.5    30
2      29.0           17.5     10
2      29.7           17.5     20
2      30.9           17.5     30
3      27.1           17.4     10
3      27.6           17.4     20
3      28.1           17.5     30
4      31.0           17.6     10
4      33.3           17.6     20
4     35.6            17.6     30"), header = TRUE, stringsAsFactors = FALSE)
closeAllConnections()

dat <- merge(d1, d2, by = "vial")
## optode wrapper
f <- function(d) optode2(d$cal0, d$T0, d$cal100, d$T100, d$phase, d$temp)

dat$oxygen <- f(dat)

dat
#######################################


Cheers,

Josh

On Wed, Oct 19, 2011 at 8:38 PM, Nathan Miller <natemiller77 at gmail.com> wrote:
> Hello,
>
> I am not entirely sure the subject line captures what I am trying to do, but
> hopefully this description of the problem will help folks to see my
> challenge and hopefully offer constructive assistance.
>
> I have an experimental setup where I measure the decrease in oxygen in small
> vials as an organism, such as an oyster, consumes the oxygen. Each vial is
> calibrated before the experiment and these calibrations are used to convert
> the raw data after the experiment into oxygen values. I end up with two
> dataframes. One has the calibration data and for example could look like
> this
>
> vial cal0    T0  cal100  T100
> 1      61      18    28       18
> 2      60.8    18    27.1    18
> 3     60.2    18    28.3     18
> 4     59.8    18     27.2     18
>
> The second is a data file which could look like this
>
>
> vial   phase    temp   time
> 1       31            17.5    10
> 1       31.5          17.4    20
> 1       32.8          17.5    30
> 2      29.0           17.5     10
> 2      29.7           17.5     20
> 2      30.9           17.5     30
> 3      27.1           17.4     10
> 3      27.6           17.4     20
> 3      28.1           17.5     30
> 4      31.0           17.6     10
> 4      33.3           17.6     20
> 4     35.6            17.6     30
>
> I have a complicated function (included at the bottom) that uses the
> calibration values and the raw data to calculate actual oxygen levels. It
> works great, but as its currently written it requires that each calibration
> be entered individually. I would rather apply the function based upon the
> vial number (applying the calibration for vial 1 to all vial 1 data,
> calibration for vial 2 to all vial 2 data).
>
> I have managed to do this by combining the two dataframes into one that
> looks like this
>
> data
> vial   phase    temp   time   cal0     T0    cal100  T100
> 1       31            17.5    10     61       18     28        18
> 1       31.5          17.4    20    61       18     28        18
> 1       32.8          17.5    30    61       18     28        18
> 1       33.6          17.5     40   61       18     28        18
> 2      29.0           17.5     10   60.8    18    27.1      18
> 2      29.7           17.5     20   60.8    18    27.1      18
> 2      30.9           17.5     30   60.8    18    27.1      18
> 3      27.1           17.4     10   60.2    18    28.3      18
> 3      27.6           17.4     20   60.2    18    28.3      18
> 3      28.1           17.5     30   60.2    18    28.3      18
> 4      31.0           17.6     10   59.8    18     27.2     18
> 4      33.3           17.6     20   59.8    18     27.2     18
> 4     35.6            17.6     30   59.8    18     27.2     18
>
> I have then used ddply to apply my function grouped by "vial"
>
> oxygen<-ddply(data,.(vial), function(d) optode(d$cal0, d$T0, d$cal100,
> d$T100, d$phase, d$temp))
>
> This works, but I do not like having to put the calibrations into the same
> dataframe as the data. Can anyone show me an example of how I could have a
> function reference a dataframe (like the calibration data) based upon a
> grouping variable (like "vial") and use that data as partial inputs to the
> function when it is applied to another dataframe (the actual data)? I don't
> necessarily need an example using my sample data or the function I have
> included here (as it is rather unwieldly). A simplified example of how to
> achieve this type of cross referencing would suffice and I can apply the
> principle to my current problem.
>
> Thanks so much,
> Nate
>
>
> optode<-function(cal0,T0,cal100,T100,phase,temp) {
>
>    f1=0.801
>    deltaPsiK=-0.08
>    deltaKsvK=0.000383
>    m=22.9
>    tan0T100=tan(((cal0+deltaPsiK*(T100-T0)))*pi/180)
>    tan0Tm=tan((cal0+(deltaPsiK*(temp-T0)))*pi/180)
>    tan100T100=tan(cal100*pi/180)
>    tanmTm=tan(phase*pi/180)
>    A=tan100T100/tan0T100*1/m*100^2
>
> B=tan100T100/tan0T100*100+tan100T100/tan0T100*1/m*100-f1*1/m*100-100+f1*100
>    C=tan100T100/tan0T100-1
>    KsvT100=(-B+(sqrt(B^2-4*A*C)))/(2*A)
>    KsvTm=KsvT100+(deltaKsvK*(temp-T100))
>    a=tanmTm/tan0Tm*1/m*KsvTm^2
>
> b=tanmTm/tan0Tm*KsvTm+tanmTm/tan0Tm*1/m*KsvTm-f1*1/m*KsvTm-KsvTm+f1*KsvTm
>    c=tanmTm/tan0Tm-1
>
> saturation=(-((tan(phase*pi/180))/(tan((cal0+(deltaPsiK*(temp-T0)))*pi/180))*(KsvT100+(deltaKsvK*(temp-T100)))+(tan(phase*pi/180))/(tan((cal0+(deltaPsiK*(temp-T0)))*pi/180))*1/m*(KsvT100+(deltaKsvK*(temp-T100)))-f1*1/m*(KsvT100+(deltaKsvK*(temp-T100)))-(KsvT100+(deltaKsvK*(temp-T100)))+f1*(KsvT100+(deltaKsvK*(temp-T100))))+(sqrt((((tan(phase*pi/180))/(tan((cal0+(deltaPsiK*(temp-T0)))*pi/180))*(KsvT100+(deltaKsvK*(temp-T100)))+(tan(phase*pi/180))/(tan((cal0+(deltaPsiK*(temp-T0)))*pi/180))*1/m*(KsvT100+(deltaKsvK*(temp-T100)))-f1*1/m*(KsvT100+(deltaKsvK*(temp-T100)))-(KsvT100+(deltaKsvK*(temp-T100)))+f1*(KsvT100+(deltaKsvK*(temp-T100)))))^2-4*((tan(phase*pi/180))/(tan((cal0+(deltaPsiK*(temp-T0)))*pi/180))*1/m*(KsvT100+(deltaKsvK*(temp-T100)))^2)*((tan(phase*pi/180))/(tan((cal0+(deltaPsiK*(temp-T0)))*pi/180))-1))))/(2*((tan(phase*pi/180))/(tan((cal0+(deltaPsiK*(temp-T0)))*pi/180))*1/m*(KsvT100+(deltaKsvK*(temp-T100)))^2))
>
>    print(saturation)
>
> }
>
>        [[alternative HTML version deleted]]
>
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
>



-- 
Joshua Wiley
Ph.D. Student, Health Psychology
Programmer Analyst II, ATS Statistical Consulting Group
University of California, Los Angeles
https://joshuawiley.com/



More information about the R-help mailing list