Using dplyr and conditional formatting to construct an ordinary differential equation from strings

末鹿安然 提交于 2019-12-11 00:23:04

问题


I am trying to create is a system of equations for a specific variable using dplyr and prod from a dataframe of strings to be used in an ordinary differential solver in R (deSolve). The location of the variable dictates the form of the equation and therefore I am using grep, filter_at, mutate_at, and apply.

Constructing the equation depends on the column of the string/variable of interest based off the following i.

  • If a variable is ever found as a product (P1,P2,P3) then multiply: +1 * Rate * R1c * R1 * R2c * R2 * R3c * R3 * (P1c or P2c or P3c)

  • What I am trying to convey with that last term (P1c or P2c or P3c) is that depending on where the variable is (P1,P2 or P3) then you need to multiply by the corresponding (P1c, P2c, or P3c), but not all of them

  • If a variable is found as a reactant (R1,R2,R3) then multiply -1 * Rate * R1c * R1 * R2c * R2 * R3c * R3
  • I then want to add everything together and set it equal to “dVariable”
    1. dVariable = Sum(all product expressions) + Sum(all Reactant expressions)

An example data frame that I have trimmed down is below.

structure(list(
    Reaction = c("k3", "k4", "k40", "k38", "k39", "k44"), 
    Rate = c("kHV_H2O2", "kHV_HO2-", "3", "27000000", "5500000000", "6600000000"), 
    R1c = c(1, 1, 1, 1, 2, 1), 
    R1 = c("H2O2", "HO2-", "HO2$", "$OH", "$OH", "$OH"), 
    R2c = c(NA, NA, 1, 1, NA, 1), 
    R2 = c(NA, NA, "H2O2", "H2O2", NA, "HO2$"), 
    R3c = c(NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_), 
    R3 = c(NA_character_, NA_character_, NA_character_, NA_character_, NA_character_, NA_character_), 
    P1c = c(2, 1, 1, 1, 1, 1), 
    P1 = c("$OH", "$OH", "O2", "HO2$", "H2O2", "O2"), 
    P2c = c(NA, 1, 1, 1, NA, 1), 
    P2 = c(NA, "O$-", "$OH", "H2O", NA, "H2O"), 
    P3c = c(NA, NA, 1, NA, NA, NA), 
    P3 = c(NA, NA, "H2O", NA, NA, NA)), 
    row.names = c(NA, -6L), class = c("tbl_df", "tbl", "data.frame"))

If we consider $OH as the species of interest, then:

  • in Row 1 $OH is first found as a product in P1 with a P1c of 2,
    therefore: +1 * (kHV_H2O2) * (1) * (H2O2) * (2)
  • In row 4 $OH is first found as a reactant in R1, therefore -1 * (27000000) * ($OH) * (1) * (H2O2) *(1)
  • Lastly, combining the two as a new variable gives

    d$OH = +1 * (kHV_H2O2)*(1)*(H2O2)*(2) - 1 * (27000000)*($OH)*(1)*(H2O2)*(1)

My approach has involved converting everything to a string, assigning numerical values to those strings, filtering the data depending on if the variable is in a select column, and then multiplying those column together, and then converting to a formula.

#Set the Reaction variable equal to the Rate Constant.  
for (i in seq(nrow(df2))) assign(df2$Reaction[i],df2$Rate[i])

#Drop Rate from main data frame
df2 <- df2 %>% mutate(Rate= NULL)

#Find the unique chemical species 
  # Drop all numbers and constnats 
    Species <- df2 %>% mutate(
      Rate = NULL, R1c = NULL, R2c = NULL, R3c = NULL, P1c = NULL, P2c = NULL, P3c = NULL, Reaction = NULL)
  #Uniques  
    Species <- unique(as.data.frame(c(as.matrix(Species))), drop = FALSE)
    names(Species) <- "Species"
  # Omit N/A and unknowns
    Species <- filter(Species, Species != "unknown")
    Species <- na.omit(Species)

# create new variable for each unique species for deltatime Step
Species <- Species %>% mutate(
  DeltaSpecies = paste0("d", as.character(Species),sep="")) 

#Multiply Each Equation
nms <- grep("^R|^Reaction$|c$", names(df2), value = TRUE)
nms2 <- grep("^R|^Reaction$", names(df2), value = TRUE)

Prod <- function(x) paste(sub("^(.*[[:punct:]].*)", "`\\1`", na.omit(x)), collapse = "*")   # if the string contains, begins, ends with a $,-,+ then put it in ' '

#Match Products and Reactants
Products <- df2 %>% filter_at(vars(P1,P2,P3,P1c,P2c,P3c), any_vars(. %in% as.character(Species$Species[[16]])))
Reactants <- df2 %>% filter_at(vars(R1,R2,R3,R1c,R2c,R3c), any_vars(. %in% as.character(Species$Species[[16]])))


Reactants_final <- paste(apply(Reactants[nms2], 1, Prod), collapse = " - ")
Products_final <- paste(apply(Products[nms], 1, Prod), collapse = " + ")


Combine <- paste(Products_final, Reactants_final, sep = " - ")
Formula <- as.formula(paste(Species$DeltaSpecies[[16]], Combine, sep = " ~ "))

I am falling short on how to conditionally make the product expression without using unnecessary variables, assigning values to strings/variables, and extracting a usable formula with variables in the form dX <- a*X + Y*Z to use in an ODE solver. I understand this is a long winded question, but I am just interested in tips to point me in the right direction to approach the problem (including exploring new functions). Would eval(parse be an approach to the problem to convert strings to variables, and assign values to them?

来源:https://stackoverflow.com/questions/58107163/using-dplyr-and-conditional-formatting-to-construct-an-ordinary-differential-equ

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!