Home > front end >  create variables with map2 and qnorm
create variables with map2 and qnorm

Time:01-27

Given:

library(tidyverse)
df <- data.frame(est = c(1.36, -0.03),
                 std = c(0.16, 0.18))
df
#     est  std
# 1  1.36 0.16
# 2 -0.03 0.18

I want to do the following:

exp(df[1, 1]   qnorm(c( 0.025, 0.5, 0.975))*df[1, 2])
# [1] 2.847398 3.896193 5.331295
exp(df[2, 1]   qnorm(c( 0.025, 0.5, 0.975))*df[2, 2])
# [1] 0.6819537 0.9704455 1.3809802

To end up with the following df:

df_final
#     est  std        or        ll       ul
# 1  1.36 0.16 2.8473980 3.8961930 5.331295
# 2 -0.03 0.18 0.6819537 0.9704455 1.380980

I am not sure why this won't work:

df[c("or", "ll", "ul")] <- map2(df %>% select(est),
                               df %>% select(std), ~ exp(.x   qnorm(c( 0.025, 0.5, 0.975))*.y))

any ideas? thanks

CodePudding user response:

We may use pmap

library(purrr)
library(dplyr)
pmap_dfr(df, ~ exp(..1   qnorm(c(0.025, 0.5, 0.975)) * ..2) %>% 
        as.list %>% 
        setNames(c('or', 'll', 'ul'))) %>% 
  bind_cols(df, .)

-output

  est  std        or        ll       ul
1  1.36 0.16 2.8473985 3.8961933 5.331295
2 -0.03 0.18 0.6819537 0.9704455 1.380980

In the OP's post, it is selecting the column, which is still a data.frame/tibble with single column. Instead it should be extracted as a vector i.e. with pull. When we have a data.frame, the unit for looping is column and not rows i.e.

df[c("or", "ll", "ul") <-  map2(df %>% pull(est),
                               df %>% pull(std), 
     ~ exp(.x   qnorm(c( 0.025, 0.5, 0.975))*.y)) %>% 
       invoke(rbind, .)

Or may use dapply

library(collapse)
f1 <- function(x) setNames(exp(x[1]   
    qnorm(c(0.025, 0.5, 0.975)) * x[2]), c('or', 'll', 'ul'))
cbind(df, dapply(df, MARGIN = 1, f1))
  est  std        or        ll       ul
1  1.36 0.16 2.8473985 3.8961933 5.331295
2 -0.03 0.18 0.6819537 0.9704455 1.380980

CodePudding user response:

in base R you could use:

a <- exp(df[[1]]   t(qnorm(c( 0.025, 0.5, 0.975)) %o% df[[2]])) 
cbind(df, setNames(data.frame(a),c('or', 'll', 'ul')))

    est  std        or        ll       ul
1  1.36 0.16 2.8473985 3.8961933 5.331295
2 -0.03 0.18 0.6819537 0.9704455 1.380980
  •  Tags:  
  • Related