Reputation: 1503
I've constructed a data.frame using the inefficient code below. Can you improve it, noting that if you can think of a better starting point, please include that answer.
My code takes data from the first two data frames and combines them to give the third. The first data.frame is a grid of 1s and -1s representing low or high values. The second data.frame includes all the information for me to calculate the high or low values. Note that each column has similar calculations but the calculation may differ from column to column.
## Exampple Data for Question
## How to prepare a 3rd data.frame from two others
## Prepare 1st data.frame, a Yates table
A <- B <- C <- c(1,-1)
yates.1 <- expand.grid(A = A, B = B, C = C)
## Prepare 2nd data.frame with the reaction data
reaction.info <- data.frame(stringsAsFactors = FALSE,
factor.name = c("A", "B", "C"),
Component = c("Water", "SM", "Reagent"),
Mw = c(18, 36.5, 40),
centre.point = c(20, 1.4, 1.45),
positive.point = c(22, 1.54, 1.595),
negative.point = c(18, 1.26, 1.305))
## Prepare 3rd data.frame to be filled
reaction.quants <- as.data.frame(matrix(NA, dim(yates.1)[1], dim(yates.1)[2]))
names(reaction.quants) <- reaction.info[,2]
reaction.quants[yates.1[,1] == 1 ,1] <- round(5 * reaction.info[1,3] * reaction.info[1,5], 3)
reaction.quants[yates.1[,1] == -1 ,1] <- round(5 * reaction.info[1,3] * reaction.info[1,6], 3)
reaction.quants[yates.1[,2] == 1 ,2] <- round(5 * reaction.info[2,3] * reaction.info[2,5], 3)
reaction.quants[yates.1[,2] == -1 ,2] <- round(5 * reaction.info[2,3] * reaction.info[2,6], 3)
reaction.quants[yates.1[,3] == 1 ,3] <- round(5 * reaction.info[3,3] * reaction.info[3,5], 3)
reaction.quants[yates.1[,3] == -1 ,3] <- round(5 * reaction.info[3,3] * reaction.info[3,6], 3)
## three data.frames
yates
reaction.info
reaction.quants
Upvotes: 1
Views: 30
Reputation: 107687
Consider refactoring with ifelse
logic and filtered vectors using a user defined method since logic is very similar but across different columns:
convert_col <- function(nm) {
with(reaction.info,
ifelse(reaction.quants_new[[nm]] == 1,
round(5 * Mw[Component==nm] * positive.point[Component==nm], 3),
round(5 * Mw[Component==nm] * negative.point[Component==nm], 3)
)
)
}
# INITIALIZE DATA FRAME (CAN BE NESTED IN NEXT CALL)
reaction.quants_new <- setNames(data.frame(yates.1), reaction.info$Component)
# ADD COLUMNS (CAN ALSO USE TRANSFORM)
reaction.quants_new <- within(reaction.quants_new, {
Water <- convert_col("Water")
SM <- convert_col("SM")
Reagent <- convert_col("Reagent")
})
reaction.quants_new
# Water SM Reagent
# 1 1980 281.05 319
# 2 1620 281.05 319
# 3 1980 229.95 319
# 4 1620 229.95 319
# 5 1980 281.05 261
# 6 1620 281.05 261
# 7 1980 229.95 261
# 8 1620 229.95 261
identical(reaction.quants, reaction.quants_new)
# [1] TRUE
And with pipes available in R 4.1+ still using user-defined method:
reaction.quants_new <- data.frame(yates.1) |>
setNames(reaction.info$Component) |>
within({
Water <- convert_col("Water")
SM <- convert_col("SM")
Reagent <- convert_col("Reagent")
})
Upvotes: 1