map() into an argument that is not the first argument - r

I have a function that takes multiple arguments (simple reproducible example below):
return_numbers <- function(first = 1, last = 10){
seq(first, last)
}
If I then have a vector that I want to map(), for example:
x <- c(5, 6, 7)
It's quite easy to map() the vector x into the first argument of the function:
map(x, return_numbers)
[[1]]
[1] 5 6 7 8 9 10
[[2]]
[1] 6 7 8 9 10
[[3]]
[1] 7 8 9 10
But I can't work out how to map x into the second argument (last = ).
I referred to Hadley Wickham's Advanced R:
https://adv-r.hadley.nz/functionals.html#change-argument
and tried this, but I must be doing something wrong:
map(x, ~ return_numbers(x, last = .x))
My desired output would be:
[[1]]
[1] 1 2 3 4 5
[[2]]
[1] 1 2 3 4 5 6
[[3]]
[1] 1 2 3 4 5 6 7

This should work:
map(x, ~return_numbers(last = .))

You can also mention the first argument explicitly :
return_numbers <- function(first = 1, last = 10){
seq(first, last)
}
x <- c(5, 6, 7)
purrr::map(x, return_numbers, first=1)
#> [[1]]
#> [1] 1 2 3 4 5
#>
#> [[2]]
#> [1] 1 2 3 4 5 6
#>
#> [[3]]
#> [1] 1 2 3 4 5 6 7
Created on 2019-11-10 by the reprex package (v0.3.0)

Related

R Split a Vector to Overlapping Sub-Vectors and Conjoin the First and the Last Elements

I want to split a vector to follow these three(3) conditions using R:
Have an equal length of l
Overlap with a constant value ov
The first element and the last element alone of the parent vector should be for the last chunk (with just the two elements).
I got the below R code to meet the first two conditions as follows
ts = 1:10
l = 7
ov = l -1
library(tidyverse)
anil <- function(ts, l, ov){
seq_len((length(ts) - ov) %/% (l - ov) +1) %>%
as.data.frame() %>%
setNames('id') %>%
mutate(start = accumulate(id, ~ .x + l - ov),
end = pmin(start + l - 1, length(ts)),
start = pmin(start, end - l + 1)) %>%
filter(!duplicated(paste(start, end, sep = '-'))) %>%
transmute(desired = map2(start, end, ~ ts[.x:.y])) %>%
as.list
}
anil(ts, l, ov)
I got this result:
>$desired[[1]]
[1] 1 2 3 4 5 6 7
>$desired[[2]]
[1] 2 3 4 5 6 7 8
>$desired[[3]]
[1] 3 4 5 6 7 8 9
>$desired[[4]]
[1] 4 5 6 7 8 9 10
I need help to meet the `third condition.
I want my result to look like this:
>$desired[[1]]
[1] 1 2 3 4 5 6 7
>$desired[[2]]
[1] 2 3 4 5 6 7 8
>$desired[[3]]
[1] 3 4 5 6 7 8 9
>$desired[[4]]
[1] 4 5 6 7 8 9 10
>$desired[[5]]
[1] 1 10
Maybe we can use the following code with embed + asplit + range
c(
asplit(embed(ts, l)[seq(1, length(ts) - l + 1, l - ov), l:1], 1),
list(range(ts))
)
which gives
[[1]]
[1] 1 2 3 4 5 6 7
[[2]]
[1] 2 3 4 5 6 7 8
[[3]]
[1] 3 4 5 6 7 8 9
[[4]]
[1] 4 5 6 7 8 9 10
[[5]]
[1] 1 10
Append with the range of 'ts' in summarise before the as.list
anil <- function(ts, l, ov){
seq_len((length(ts) - ov) %/% (l - ov) +1) %>%
as.data.frame() %>%
setNames('id') %>%
mutate(start = accumulate(id, ~ .x + l - ov),
end = pmin(start + l - 1, length(ts)),
start = pmin(start, end - l + 1)) %>%
filter(!duplicated(paste(start, end, sep = '-'))) %>%
transmute(desired = map2(start, end, ~ ts[.x:.y])) %>%
summarise(desired = c(desired, list(range(ts)))) %>%
as.list
}
-testing
anil(ts, l, ov)
$desired
$desired[[1]]
[1] 1 2 3 4 5 6 7
$desired[[2]]
[1] 2 3 4 5 6 7 8
$desired[[3]]
[1] 3 4 5 6 7 8 9
$desired[[4]]
[1] 4 5 6 7 8 9 10
$desired[[5]]
[1] 1 10

New df in R pulling from large existing df

In R, am trying to take this df I have called "gorilla" and create four new dfs by column identifiers. The "gorilla" spreadsheet has a column called "order", and this column has values that are either 1, 2, 3, and 4. I want to create a new df with "1" values only, and another one with "2" values only, etc. What is the best way to do this?
If you do:
list2env(setNames(split(gorilla, gorilla$order), paste0("gorilla", 1:4)),
envir = globalenv())
Then you will have the 4 data frames in your workspace, called gorilla1, gorilla2, gorilla3 and gorilla4
For example, if we have this dataset:
set.seed(100)
gorilla <- data.frame(data = rnorm(10), order = sample(4, 10, TRUE))
gorilla
#> data order
#> 1 -0.50219235 3
#> 2 0.13153117 4
#> 3 -0.07891709 2
#> 4 0.88678481 1
#> 5 0.11697127 4
#> 6 0.31863009 3
#> 7 -0.58179068 3
#> 8 0.71453271 4
#> 9 -0.82525943 2
#> 10 -0.35986213 1
We can do:
list2env(setNames(split(gorilla, gorilla$order), paste0("gorilla", 1:4)),
envir = globalenv())
#> <environment: R_GlobalEnv>
And now we can see we have these objects available:
gorilla1
#> data order
#> 4 0.8867848 1
#> 10 -0.3598621 1
gorilla2
#> data order
#> 3 -0.07891709 2
#> 9 -0.82525943 2
gorilla3
#> data order
#> 1 -0.5021924 3
#> 6 0.3186301 3
#> 7 -0.5817907 3
gorilla4
#> data order
#> 2 0.1315312 4
#> 5 0.1169713 4
#> 8 0.7145327 4
Note though that it is probably best in most circumstances to keep the data frames in a list:
gorillas <- split(gorilla, gorilla$order)
That way, you can just access gorillas[[1]] , gorillas[[2]] etc
An optioin with group_split
library(dplyr)
gorillas <- gorilla %>%
group_split(order)

Get object and indices from subsetting call

Basically, I would like to create an R function separate_call that gets an argument like x[ind] and returns x and ind (so, from the parent environment):
x <- 1:10
ind <- 2:3
separate_call(x[ind]) ## should return `list(1:10, 2:3)`
I know that I need to use non-standard evaluation and some tree parsing but I'm not familiar enough with these two concepts. Any help would be appreciated.
Looking at the code of pryr:::tree and experimenting a little bit, I found a solution:
separate_call <- function(call) {
call.sep <- as.list(substitute(call))
parent_env <- parent.frame()
x <- eval(call.sep[[2]], parent_env)
ind <- eval(call.sep[[3]], parent_env)
list(x, ind)
}
Verification:
> x <- 1:10
> ind <- 2:3
> separate_call(x[ind])
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 2 3
> separate_call(x[1:2])
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 1 2
I am adding this solution, not very elegant, see if this fits your need.
separate_call <- function(m){
dprse <- deparse(substitute(m)) ##deparsing the data: to make it as string
lyst <- strsplit(dprse,"\\[|\\]")[[1]] ##removing the square brackets to sparate contents of m
lapply(lyst, function(y)eval(parse(text = y), envir = parent.frame()))
}
I hope this works, I tried it by calling it in three different ways
separate_call(1:10[ind])
separate_call(x[2:3])
separate_call(1:10[2:3])
They all gave me same response
> separate_call(1:10[ind])
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 2 3
> separate_call(x[2:3])
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 2 3
> separate_call(1:10[2:3])
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 2 3

How to make a sequences from a range

I am trying to make a sequences from a range from the output of range.
> range(wines$quality)
[1] 3 8
> seq(3, 8)
[1] 3 4 5 6 7 8
> seq(range(wines$quality))
[1] 1 2
but I am trying to get put the output of range 3, 8 into seq to get the list of 3, 4, 5, 6, 7 ,8 why is giving me a list with 1 2? How do a make it behave as I want?
Another option:
do.call(seq, as.list(range(wines$quality)))
# [1] 3 4 5 6 7 8
You problem right now is you are passing a two element vector as one argument, when seq expects two one element arguments in order for it to do what you want.
do.call calls seq with each of the items in as.list... as an argument.
I am sure there is a fancier way to do it but why not just:
x <- range(wine$quality)
seq(x[1], x[2])
Some possible solutions, though the eval parse is more fooling around:
set.seed(10)
x <- rpois(20, 10)
y <- range(x); y[1]:y[2]
seq(y[1], y[2])
eval(parse(text = paste(range(x), collapse=":")))
## > y <- range(x); y[1]:y[2]
## [1] 5 6 7 8 9 10 11 12 13 14 15
## > seq(y[1], y[2])
## [1] 5 6 7 8 9 10 11 12 13 14 15
## > eval(parse(text = paste(range(x), collapse=":")))
## [1] 5 6 7 8 9 10 11 12 13 14 15

Constant subset of a variable length list for some list[[x]] in R

Imagine the following data:
listA
[[1]]
[1] 1 2 3 4 5 6 7
[[2]]
[1] 1 2 3 4 5 6
[[3]]
[1] 1 2 3 4 5
How to select:
listA[[1:2]][1:4]
Using 1:2 there is not allowed, so is there any way to select these when it is known that this selection exists (both the 1:2 and 1:4 parts)?
What I would like returned:
listA
[[1]]
[1] 1 2 3 4
[[2]]
[1] 1 2 3 4
What about just using lapply,
R> l = list(A = 1:6, B=1:4, C = 1:5)
R> lapply(l[1:2], "[", 1:4)
$A
[1] 1 2 3 4
$B
[1] 1 2 3 4
You probably have to use lapply.
lapply(listA, function(x) x[1:4])
If your actual list is longer, you can access the first two elements of listA by listA[1:2]. So this should work:
lapply(listA[1:2], function(x) x[1:4])

Resources