Использование purrr::invoke() для передачи различных аргументов функции.

Я хочу запустить функцию kmeans() в R с разными значениями k (kmeans(x = iris[1:4], centers = k)). Я знаю, как это сделать с помощью dplyr или функции do.call(), однако я не могу заставить ее работать с purrr::invoke() (я совершенно уверен, что для этой задачи подходит функция invoke). Конечно, я мог бы просто использовать подход dplyr (см. эту ссылку), но меня раздражает, что я не могу заставить его работать с муррр.

В справочник по функциям purrr::invoke() включен следующий пример кода:

# 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
#> 

Когда я пытаюсь сделать это с помощью kmeans, я получаю следующее

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

я тоже пробовал

> 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'

в качестве проверки я также пытался проделать то же самое с paste

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

где я ожидал word1aword2 и word1bword2. Я прочитал все ссылки на функции, и в настоящее время я не уверен, как решить эту проблему.


person Peter H.    schedule 06.12.2017    source источник


Ответы (2)


Почему вы «совершенно уверены, что функция вызова подходит для этой задачи»?

Простой map делает:

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
person Aurèle    schedule 06.12.2017
comment
Ссылка на функцию смутила меня. В нем говорилось, что эта пара функций упрощает объединение функции и списка параметров для получения результата. аргумент не назван. - person Peter H.; 07.12.2017
comment
Можно действительно возразить, что в этом решении есть некоторая нечистота, поскольку оно основано на аргументах позиционирования: оно работает, потому что centers является вторым аргументом kmeans после x, а поскольку x указано в ..., оно эквивалентно mapping partial(kmeans, x = iris[1:4]), из которых первый аргумент равен centers. Извините, если я добавляю путаницы. - person Aurèle; 07.12.2017
comment
Нет, на самом деле это имеет большой смысл, спасибо за объяснение, как это работает! Я понял, что могу указать имя с помощью анонимной функции. map(1:10, ~kmeans(centers = .x, x = iris[1:4])). Это, возможно, сделало бы его более читабельным. - person Peter H.; 07.12.2017
comment
Конечно, я тоже собирался это предложить. Это также дело вкуса. - person Aurèle; 07.12.2017

Я понял, что пошло не так. Во-первых, в данном случае правильно использовать функцию invoke_map(), а не invoke(). При использовании этой функции (как указано в справочнике по функциям -.-) проблема может быть решена с помощью следующего кода:

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

Однако это может быть довольно утомительно писать, если вам нужно несколько центров, поэтому я придумал следующее решение, которым я вполне доволен. Надеюсь, это может помочь кому-то еще!

invoke_map(kmeans, transpose(list(centers = 1:10)), x = iris[1:4])
person Peter H.    schedule 06.12.2017