Harnessing .f list names with purrr::pmap
The formula argument ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width
is passed to purrr::as_mapper
.
purrr::as_mapper(~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width)
# function (..., .x = ..1, .y = ..2, . = ..1)
# Sepal.Length + Sepal.Width + Petal.Length + Petal.Width
You can see that there's no direct way for this function to know what these variables are.
I can think of 3 ways around this. I'll use @zacdav's example as it's more compact and readable than yours:
named_list <- list(one = c(1, 1),
two = c(2, 2),
three = c(3, 3))
Explicit definition
You can define explicitly these variables as shown in @zacdav's answer it will work.
Explore the dots argument
There is a way to access the named arguments through the ...
parameter of the function returned by as_mapper
.
The arguments of the function are named when names are available, as the doc states in other words.
That explains why pmap(named_list, function(x,y,z) x+y+z)
will fail with error:
unused arguments (one = .l[[c(1, i)]], two = .l[[c(2, i)]], three = .l[[c(3, i)]])
See:
pmap(named_list, ~names(list(...)))
# [[1]]
# [1] "one" "two" "three"
#
# [[2]]
# [1] "one" "two" "three"
(pmap(unname(named_list), function(x,y,z) x+y+z)
on the other hand will work fine)
So this will work:
pmap(named_list, ~ with(list(...), one + two + three))
# [[1]]
# [1] 6
#
# [[2]]
# [1] 6
Use pryr::f
pryr
offers a neat shortcut for function definitions with pryr::f
:
library(pryr)
f(one + two + three)
# function (one, three, two)
# one + two + three
pmap(named_list, f(one + two + three))
# [[1]]
# [1] 6
#
# [[2]]
# [1] 6
#
Be careful however when using it, global variables will still show up as parameters and functions will or will not be included in parameters depending on how they're called. For example :
x <- 1
test <- mean
f(test(x) + lapply(iris,test2))
# function (iris, test2, x)
# test(x) + lapply(iris, test2)
So it's not a general approach and you should use it only with simple cases. the second approach, though a bit of a hack, will be general.
Moreover f
is ordering the parameters alphabetically, this should not be an issue when dealing with a named list, but be careful when dealing with partially named lists.
Use List Names as Row Names When Converting From pmap to pmap_dfr purrr
You could add a new column with rownames
of the list.
purrr::map_dfr(lst_df, ~{.x$ticker <- rownames(.x);.x})
Contrarily, if you use
df1 <- do.call(rbind, lst_df)
the rownames are maintained which can be converted to column names if needed
df1$ticker <- rownames(df1)
where
lst_df <- pmap(df, ~reqMktData(tws, twsOption(local = "", symbol = ..1,
expiry = ..2, strike = ..3, right = "P"),
eventWrapper = eWrapper.data(1), CALLBACK = snapShot))
setting list element names based on argument to `pmap`
From tidyverse
package, you can also use lst
function. lst
is used for creating list. It is like tibble
function to create tibble but for creating list. One of the difference with base list()
is that it automatically names the list.
It is in dplyr, exported from tibble.
For the example, I also replace base alist
by rlang::exprs
as it is equivalent. Indeed, both are ok.
library(tidyverse)
library(groupedstats)
set.seed(123)
# creating the dataframes
data_1 <- tibble::as.tibble(iris)
data_2 <- tibble::as.tibble(mtcars)
data_3 <- tibble::as.tibble(airquality)
# creating a list
purrr::pmap(
.l = list(
data = lst(data_1, data_2, data_3),
grouping.vars = rlang::exprs(Species, c(am, cyl), Month),
measures = rlang::exprs(c(Sepal.Length, Sepal.Width), wt, c(Ozone, Solar.R, Wind))
),
.f = groupedstats::grouped_summary
) %>%
str(1)
#> List of 3
#> $ data_1:Classes 'tbl_df', 'tbl' and 'data.frame': 6 obs. of 16 variables:
#> $ data_2:Classes 'tbl_df', 'tbl' and 'data.frame': 6 obs. of 17 variables:
#> $ data_3:Classes 'tbl_df', 'tbl' and 'data.frame': 15 obs. of 16 variables:
Created on 2018-11-02 by the reprex package (v0.2.1)
R purrr:::pmap: how to refer to input arguments by name?
You can use with(...)
to solve this :
pmap(args2, ~with(list(...),rnorm(n, mean, sd)))
# [[1]]
# [1] 2.733528
#
# [[2]]
# [1] 4.0967533 6.4926143 0.6083532
#
# [[3]]
# [1] 1.8836592 -0.2090425 -4.0030168 1.1834931 3.2771316
More explanations here: Harnessing .f list names with purrr::pmap
assigning `pmap` output to dataframes with pattern names
You can do it with map2
:
library(purrr)
res <- pmap(.l = list(
x = list(iris$Sepal.Length, mtcars$wt, anscombe$y4),
probs = list(seq(0, 1, 0.10)),
na.rm = list(TRUE)
), .f = stats::quantile)
map2(.x = paste0('df_', seq_along(res)), .y = res,
.f = ~ assign(.x, .y, envir = .GlobalEnv))
# > df_1
# 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%
# 4.30 4.80 5.00 5.27 5.60 5.80 6.10 6.30 6.52 6.90 7.90
# > df_2
# 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%
# 1.5130 1.9555 2.3490 2.7730 3.1580 3.3250 3.4400 3.5550 3.7700 4.0475 5.4240
# > df_3
# 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%
# 5.25 5.56 5.76 6.58 6.89 7.04 7.71 7.91 8.47 8.84 12.50
though I think it is better to keep the results in a list.
How to use purrr::pmap to invoke a user-defined function in R
Changing a couple of things in your code fixes this problem. First, your dataset shouldn't be read as a list, so you can take that out of list_1
.
list_1 <- list(list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
From there, you can phrase your pmap call like this to get the results you're after:
pmap(list_1, ~wrap_vr(df, ..1, ..2, ..3))
R: Repeating elements of a list for usage in purrr::pmap()
rep(list(c("onResume", "onPause")), times = 3)
should work. What seems to be issue?
If you need to repeat different vectors a different number of times, you can use map2
(Note the usage of flatten
to convert the final list-of-lists to a list of vectors):
map2( list(c("ACTIVITY_RESUME", "ACTIVITY_PAUSE"),
c("FRAGMENT_RESUME", "FRAGMENT_PAUSE"),
c("onResume", "onPause")),
1:3, ~rep(list(.x), .y) ) %>% purrr::flatten()
# [[1]]
# [1] "ACTIVITY_RESUME" "ACTIVITY_PAUSE"
#
# [[2]]
# [1] "FRAGMENT_RESUME" "FRAGMENT_PAUSE"
#
# [[3]]
# [1] "FRAGMENT_RESUME" "FRAGMENT_PAUSE"
#
# [[4]]
# [1] "onResume" "onPause"
#
# [[5]]
# [1] "onResume" "onPause"
#
# [[6]]
# [1] "onResume" "onPause"
Related Topics
How to Create a New Variable in a Data.Frame Based on a Condition
Add a New Column Between Other Dataframe Columns
Convert Latitude and Longitude Coordinates to Country Name in R
Ggplot: How to Set Default Color for All Geoms
Avoid Scientific Notation in Cut Function in R
How to Create a World Map in R with Specific Countries Filled In
Add Colored Arrow to Axis of Ggplot2 (Partially Outside Plot Region)
Documentation on Internal Variables in Ggplot, Esp. Panel
Shiny - Observe() Triggered by Dynamicaly Generated Inputs
Partially Color Histogram in R
Replace Specific Values Based on Another Dataframe
Should I Avoid Programming Packages with Pipe Operators
Minus Operation of Data Frames
Using R to Download Zipped Data File, Extract, and Import .Csv