Use an arrow assignment function as R purrr map2 - r

I have a list of rasters:
filelist <- as.list(c("rasterA", "rasterB") # name them
rasterlist <- lapply(filelist, function(x) raster::raster(x)) # read them in
And a list of CRSes corresponding to those rasters:
crslist <- as.list(c("crsA.Rds", "crsB.Rds")) # name them
crslist %<>% lapply(function(x) readRDS(x)) # read them in
To fill the #crs slot in a raster you use (e.g.):
raster::crs(rasterA) <- crsA
But I can't work out how to use this arrow assignment in a purrr::map2 call. The example in the R cheat sheet is map2(x, y, sum), but sum works on vectors, is directionless, and contains all of its terms within its brackets.
Reading the map2 help, I tried the formula format:
purrr::map2(rasterlist, crslist, ~ raster::crs(.x) <- .y)
But no dice:
Error in as_mapper(.f, ...) : object '.y' not found
Does anyone know how I'd do this? Currently I'm using a loop which is simple, but I'm trying to force myself to learn mapping and keep hitting these kinds of walls.
for (i in length(rasterlist)) {
crs(rasterlist[[i]]) <- crslist[[i]]
}
Thanks!
Starting condition:
After for loop:
After raster_assigner function instead:
Hopefully this is salvagable because I've got other use cases like this. Cheers!

We may need
purrr::map2(rasterlist, crslist, ~ {crs(.x) <- .y;.x})
It is not related to the raster - as the simple example below shows the same error
> map2(list(1, 2, 3), list(3, 4, 5), ~ names(.x) <- .y)
Error in as_mapper(.f, ...) : object '.y' not found
> map2(list(1, 2, 3), list(3, 4, 5), ~ {names(.x) <- .y; .x})
[[1]]
3
1
[[2]]
4
2
[[3]]
5
3
However this won't return an error in Map (but it is not correct because the output returned is without the names, unless we wrap it with {} and return the x
> Map(function(x, y) names(x) <- y, list(1, 2, 3), list(3, 4, 5))
[[1]]
[1] 3
[[2]]
[1] 4
[[3]]
[1] 5

Could do a dedicated function:
raster_assigner <- function(raster, crs_input){
raster::crs(raster) <- crs_input
raster
}
purrr::map2(rasterlist, crslist, raster_assigner)

Related

R - SparkR - referencing variable within `spark.lapply`

My goal is to convert some work using the usual lapply in R to using SparkR::spark.lapply. I'm not sure what the proper way to pass through extra variables into the function. lapply has the ... parameter to pass in extra arguments but spark.lapply does not.
Here's a toy example, where the list we map over isn't actually used, but it gets the point across. My particular case needs to use a sparse matrix so I'll use that in my example.
library(Matrix)
x <- Matrix(c(1, 0, 0, 2, 3, 4), nrow = 2, sparse = TRUE)
iter <- list(1, 1)
# using lapply
> lapply(iter, function(ii) nrow(x))
[[1]]
[1] 2
[[2]]
[1] 2
# sparkr
> library(SparkR)
> spark.lapply(iter, function(ii) nrow(x))
object 'x' not found
I am running this in Databricks, with R 4.2.2. So, how would I pass in other variables?
Thank you!

Change first input based on second input, applying a function, using purrrĀ“s map2

I'm wondering if it's possible to change, let's say .x based on .y applying map2() on the fly, applying a function.
Let's say I have two vectors with different lengths and want to fill shortest one with NA, in order to have same length in both vectors:
vec1 <- seq(1, 3, by = 2)
vec2 <- seq(2, 3, by = 2)
Both solutions are valid:
length(vec2) <- length(vec1)
`<-`(length(vec2), length(vec1))
But, what if I have vectors in lists, and want to apply purrr's map2?
l1 <- list(c(1,2), c(1,2))
l2 <- list(3, 3)
I have tried:
library(purrr)
map2(l1, l2, ~ `<-`(length(.y), length(.x)))
but does not work. Any ideas how to assign a value inside map2? Thank you, help much appreciated.
PS: I'm trying to avoid using loops!
You should call `length<-` rather than `<-`.
purrr::map2(l1, l2, ~ `length<-`(.y, length(.x)))
# [[1]]
# [1] 3 NA
#
# [[2]]
# [1] 3 NA
which is equivalent to
purrr::map2(l1, l2, ~ { length(.y) <- length(.x); .y })
Using a simple for loop
for(i in seq_along(l2)) length(l2[[i]]) <- length(l1[[i]])

Ryacas substitute but don't simplify or evaluate

I am using the Ryacas package in R and am trying to substitute variables for values but not simplify or solve the equation to show the working out. I have searched Stackoverflow, read the Ryacas documentation and have attempted to find this in the Yacas manual but have so far come up short. I think I am looking to turn simplification off to get the substituted equation and then on again to provide the final result.
Here is an example which provides only the result rather than the working:
library(Ryacas)
# a <- 2
# b <- 3
# c <- 4
eq <- ysym(('(a * b) / c'))
solution <- with_value(with_value(with_value(eq, 'a', 2), 'b', 3), 'c', 4)
tex(solution)
# "\\frac{3}{2}"
What I am trying to get as an output is:
# working out
# "\\frac{2 \times 3}{4}
as well as the actual solution:
# solution
# "\\frac{3}{2}"
Does anyone know whether there is a solution to this problem such as passing a command to yacas through yac_str or similar. I have tried translating to latex using the tex() command and then substituting after though the multiplication operators are removed and this means I need to find and replace them which becomes nasty when dealing with symbolics:
tex(eq)
# "\\frac{a b}{c}"
# substituting string values using stringi requires additional
# work to deal with the missing `*` between `a` and `b`
# "\\frac{2 3}{4}"
Whilst this can be done for simple expressions, there are numerous exceptions such as the variables a and c being present in \\frac etc.
I have also tried the TexForm command and substitute in various guises but am still not able to capture the unsimplified and unevaluated equation:
y_fn(substitute(with_value(eq, 'a', 2)), "TeXForm")
# "\\frac{2 b}{c}"
eval(substitute(with_value(eval(substitute(with_value(eq, 'a', 2))), 'b', 3)))
# y: 6/c
Any help appreciated.
You might need to customize this some more but this general approach can work if you are willing to do that.
We translate words to their values using gsubfn and handle the \times part at the end with gsub. Note that frac is not modified because we are matching words and frac it is not a word in the list given in the second arg to gsubfn.
library(magrittr)
library(gsubfn)
library(Ryacas)
eq <- ysym(('(a * b) / c'))
eq %>%
tex %>%
gsubfn("(\\w+)", list(a = 2, b = 3, c = 4), .) %>%
gsub("(\\d) (\\d)", "\\1 \\\\times \\2", .)
## [1] "\\frac{2 \\times 3}{4}"
Added
Take the first three code examples when searching for [r] Ryacas in stackoverflow and it worked on all of them. Note that these used the original version of Ryacas which is currently called Ryacas0 so I used that.
library(Ryacas0)
library(gsubfn)
library(magrittr)
tex_sub <- function(.x, ...) {
.x %>%
gsubfn("(\\w+)", list(...), .) %>%
gsub("(\\d) (\\d)", "\\1 \\\\times \\2", .)
}
# https://stackoverflow.com/questions/21858668/symbolic-matrix-multiplication-by-ryacas
x <- Sym("x")
mat1 <- List(
List(x, 2),
List(x^3, x))
mat2 <- List(
List(x, x),
List(3, 6 * x))
tt <- TeXForm(mat1 * mat2)
tex_sub(tt, x = 1)
###
# https://stackoverflow.com/questions/22739173/matrix-transpose-in-ryacas
u=Sym("u")
v=Sym("v")
w=Sym("w")
DG=List(List(w-v), List(u-w), List(v-u))
tt2 <- TeXForm(DG)
tex_sub(tt2, u = 2, v = 3, w = 4)
###
# https://stackoverflow.com/questions/49572184/how-to-derivate-using-ryacas
x <- Sym("x")
P <- Sym(1)
for (k in 1:3) {
P <- Simplify((1+k*x)*P + x*(1-x)*deriv(P, x))
print(P)
}
tt3 <- TeXForm(P)
tex_sub(tt3, x = 10)

How to use character as variable name in arguments? [R]

I am wondering how to tell R the string I used in the arguments of a function stands for a variable instead of the string itself. Specifically, I am dealing with 'Dict' package and run the following code as a trial.
library(Dict)
x = c(1,2)
d = dict(x = 1)
d$keys
# 'x'
What I want is c(1,2) to be the key instead of 'x'. The same problem goes for 'list', for example
y = 'happy'
l = list(y = 1)
names(l)
The result would be 'y'. Moreover, one can solve this situation by
names(l) <- y, but I don't think this is very efficient and clean.
Anyone has any idea how to do this in a one-line code? Thanks!
We could use setNames
out <- do.call(dict, setNames(rep(list(1), length(x)), x))
out$keys
[1] "1" "2"
Or we may use invoke or exec
library(purrr)
out <- invoke(dict, setNames(rep(1, length(x)), x))
out <- exec(dict, !!!setNames(rep(1, length(x)), x))
For the second case, also setNames works
setNames(list(1), y)
$happy
[1] 1
or we can use dplyr::lst
dplyr::lst(!! y := 1)
$happy
[1] 1

Margrittr pipe with matrix operations in R

I'm working on some functions that take a matrix as input and provide a matrix as output. Is it possible to use the magrittr pipe with matrices without using the . placeholder? Ideally, I'd like these functions to be piped into each other like a dplyr chain. The issue is that I'm constantly forgetting to specify the . placeholder and getting errors.
library(magrittr)
set.seed(123)
m <- matrix(rnorm(10), ncol = 2)
# This works perfectly:
layout_align_x <- function(n = nodes, anchor, m = matrix){
m[n, 1] <- m[anchor, 1]
return(m)}
# This also works perfectly:
layout_align_x(c(1,2), 3, m)
# And this also:
m %>% layout_align_x(c(1,2), 3, .)
# This returns error:
m %>% layout_align_x(c(1,2), 3)
#Error in m[anchor, 1] : incorrect number of dimensions
# The goal is:
m %>%
layout_align_x(c(1,2), 3) %>%
layout_align_x(c(3,4), 5)
Change your function to
layout_align_x <- function(m = matrix, n = nodes, anchor){
m[n, 1] <- m[anchor, 1]
return(m)
}

Resources