Peter H.
Peter H.

Reputation: 2164

Using purrr::invoke() to supply different arguments to function.

I want to run the kmeans() function in R with different values of k (kmeans(x = iris[1:4], centers = k)). I know how to do this with dplyr or the do.call() function, however I can't get it to work with purrr::invoke() (I'm quite sure that invoke is the right function for this task). I could of course just use the dplyr approach (see this link), but it annoys me that I can't get it to work with purrr.

In the purrr::invoke() function reference, the following code-example is included:

# Or the same function with different inputs:
invoke_map("runif", list(list(n = 5), list(n = 10)))
#> [[1]]
#> [1] 0.67176682 0.05861411 0.99706914 0.14903547 0.51855664
#> 
#> [[2]]
#>  [1] 0.84612005 0.71826972 0.24131402 0.54704337 0.83480182 0.02795603
#>  [7] 0.46938430 0.80568003 0.81405131 0.40391100
#> 

When i try to do this with kmeans i get the following

> invoke(kmeans, list(list(centers = 1), list(centers = 2)), x = iris[1:4])
Error in sample.int(m, k) : invalid 'size' argument

I have also tried

> invoke(kmeans, list(centers = 1:5), x = iris[1:4])
Error in (function (x, centers, iter.max = 10L, nstart = 1L, 
algorithm = c("Hartigan-Wong",  : must have same number of columns in 'x' and 'centers'

as a reality-check, i also tried doing a similar thing with paste

> invoke(paste, list(list(sep = "a"), list(sep = "b")), "word1", "word2")
[1] "a b word1 word2"

where i would've expected word1aword2 and word1bword2. I have been reading all the function references and I'm currently not sure how to solve this problem.

Upvotes: 0

Views: 558

Answers (2)

Aurèle
Aurèle

Reputation: 12839

Why are you "quite sure that invoke is the right function for this task"?

A simple map does:

set.seed(123) ; res1 <- invoke_map(kmeans, transpose(list(centers = 1:10)), x = iris[1:4])

set.seed(123) ; res2 <- map(1:10, kmeans, x = iris[1:4])

identical(res1, res2)
# [1] TRUE

Upvotes: 3

Peter H.
Peter H.

Reputation: 2164

I've figured out what went wrong. First of all, the correct function to use in this case is invoke_map() and not invoke(). When using this function (as also specified in the function reference -.-), the problem can be solved with the following code:

invoke_map(kmeans, list(list(centers = 1), list(centers = 2)), x = iris[1:4])

This can however be quite tedious to write if you want multiple centers, so i came up with the following solution which im quite happy with. Hope this can help someone else!

invoke_map(kmeans, transpose(list(centers = 1:10)), x = iris[1:4])

Upvotes: 0

Related Questions