I have data on the outside temperature
df1 <- read.table(text = "DT temp.out
'2023-01-18 00:00:00' 6.8
'2023-02-18 23:00:00' 1.5
'2023-03-04 00:00:00' 2.6
'2023-04-20 03:00:00' -5.0
'2023-06-21 05:00:00' 11.9
'2023-08-10 19:00:00' 6.2
'2023-08-21 23:00:00' -2.8
'2023-09-19 01:00:00' 5.7
'2023-11-3 07:00:00' 9.1
'2023-12-21 13:00:00' -19.8", header = TRUE) %>%
mutate (DT = as.POSIXct(DT))
For each observation I determine the value of the COP indicator. It depends on the value of tzas. Since (currently) I have two functions describing the COP value depending on tzas (60 and 30), I calculate the value for intermediate values using a proportion (linear relationship).
COP.licz <- function(tout) {
tzas = -0.78 * tout + 35.789
COP.60 = 0.026 * tout + 2.937
COP.30 = 0.0368 * tout + 3.46
(COP.30 - COP.60) / (60 - 30) * (tzas - 30) + COP.30
}
df1 <- df1 %>%
mutate (
tzas = -0.78 * temp.out + 35.789,
COP.chw = COP.licz (temp.out)
)
I get results left
> df1
DT temp.out COP.chw
1 2023-01-18 00:00:00 6.8 3.719882
2 2023-02-18 23:00:00 1.5 3.598219
3 2023-03-04 00:00:00 2.6 3.624767
4 2023-04-20 03:00:00 -5.0 3.427471
5 2023-06-21 05:00:00 11.9 3.822061
6 2023-08-10 19:00:00 6.2 3.706901
7 2023-08-21 23:00:00 -2.8 3.487919
8 2023-09-19 01:00:00 5.7 3.695929
9 2023-11-03 07:00:00 9.1 3.767771
10 2023-12-21 13:00:00 -19.8 2.950173
>
In the next version I have several (maybe more) COP functions (tzas): COP.60, COP.55, COP.50, COP.30. I want to use these additional functions in COP.chw calculations For example: temp.out is -19.8, therefore tzas is 51.233 COP.chw will be calculated from the proportion between the values of COP.50 and COP.60
Using if
or case_when
seems to be a very forceful solution.
Example dependencies/functions
COP.60 = 0.026 * tout + 2.937
COP.55 = 0.029 * tout + 2.907
COP.50 = 0.0315 * tout + 3.001
COP.30 = 0.0368 * tout + 3.46
You could use the following structure; Note that for tzas values less than 30 you would want to define another segment, as it currently returns null, as there is no matching blend.
df1 <- read.table(text = "DT temp.out
'2023-01-18 00:00:00' 6.8
'2023-02-18 23:00:00' 1.5
'2023-03-04 00:00:00' 2.6
'2023-04-20 03:00:00' -5.0
'2023-06-21 05:00:00' 11.9
'2023-08-10 19:00:00' 6.2
'2023-08-21 23:00:00' -2.8
'2023-09-19 01:00:00' 5.7
'2023-11-3 07:00:00' 9.1
'2023-12-21 13:00:00' -19.8", header = TRUE) %>%
mutate (DT = as.POSIXct(DT))
blend <- function(tzas,low_cut,low_val,high_cut,high_val){
(low_val - high_val) / (high_cut-low_cut) * (tzas - low_cut) + low_val
}
COP.licz_0 <- function(tout) {
tzas = -0.78 * tout + 35.789
COP.30 = 0.0368 * tout + 3.46
COP.50 = 0.0315 * tout + 3.001
COP.55 = 0.029 * tout + 2.907
COP.60 = 0.026 * tout + 2.937
which_cut <- as.integer(cut(tzas,breaks = c(30,50,55,60)))
r <- switch(which_cut,
blend(tzas,30,COP.30,50,COP.50),
blend(tzas,50,COP.50,55,COP.55),
blend(tzas,55,COP.55,60,COP.60)
)
r
}
COP.licz <- Vectorize(COP.licz_0,vectorize.args = "tout")
df1 <- df1 %>%
mutate (
tzas = -0.78 * temp.out + 35.789,
COP.chw1 = COP.licz (temp.out)
)
further comments : the issue of a list result, is by tzas falling outside of defined breaks and returning NULL, so it has the solution I mentioned in my post, define proper bounds with proper behaviour.. and then it wont go back to you as a list . yet, if you dont want to and want to have NA values in those spaces though you can add .
if(is.null(r)){
r <- NA_real_
}
r
to the end of COP.licz_0
function to turn nulls to numeric NA values