Вычисление меры важности с использованием пакета VIP на модели пастернака - PullRequest
2 голосов
/ 05 мая 2020

Я пытаюсь вычислить важность функции с помощью vi_firm () на логистической модели c регрессии, созданной в пастернаке. Для регулярного выражения я буду использовать набор данных iris и попытаюсь предсказать, является ли наблюдение сетосой или нет.

iris1 <- iris %>%
  mutate(class  = case_when(Species == 'setosa' ~ 'setosa',
                            TRUE ~ 'other'))
iris1$class = as.factor(iris1$class)

#set up logistic regression model
iris.lr = logistic_reg(
  mode="classification",
  penalty=NULL,
  mixture=NULL
) %>%
  set_engine("glmnet")

iris.fit = iris.lr %>%
  fit(class ~. , data = iris1)

library(vip)
vip::vi_firm(iris.fit, feature_names = features, train = iris1, type = 'classification')

Это дает

Error: Did you mean to use `new_data` instead of `newdata`?

Я также пытаюсь создать графики частичной зависимости, используя partial из связанного пакета pdp. Я получаю ту же ошибку.

Ответы [ 2 ]

2 голосов
/ 15 мая 2020

Для регуляризованных моделей, подобных тем, которые подходят для gl mnet, вы можете захотеть придерживаться специфичной для модели c оценки важности (по умолчанию vi()). Также обратите внимание на две вещи:

  • вам нужно указать, какое значение lambda вы хотите вычислить важность переменной (я просто выбрал случайным образом одно здесь для этого примера)
  • подобранный объект gl mnet находится в iris_fit$fit, внутри объекта пастернака
library(tidymodels)
#> ── Attaching packages ────────────────────────────────────────── tidymodels 0.1.0 ──
#> ✓ broom     0.5.6      ✓ recipes   0.1.12
#> ✓ dials     0.0.6      ✓ rsample   0.0.6 
#> ✓ dplyr     0.8.5      ✓ tibble    3.0.1 
#> ✓ ggplot2   3.3.0      ✓ tune      0.1.0 
#> ✓ infer     0.5.1      ✓ workflows 0.1.1 
#> ✓ parsnip   0.1.1      ✓ yardstick 0.0.6 
#> ✓ purrr     0.3.4
#> ── Conflicts ───────────────────────────────────────────── tidymodels_conflicts() ──
#> x purrr::discard()  masks scales::discard()
#> x dplyr::filter()   masks stats::filter()
#> x dplyr::lag()      masks stats::lag()
#> x ggplot2::margin() masks dials::margin()
#> x recipes::step()   masks stats::step()

iris1 <- iris %>%
  mutate(class  = case_when(Species == 'setosa' ~ 'setosa',
                            TRUE ~ 'other'),
         class = factor(class)) %>%
  select(-Species)


iris_mod <- logistic_reg(
  penalty = NULL,
  mixture = NULL
) %>%
  set_engine("glmnet")

iris_fit <- iris_mod %>%
  fit(class ~ ., data = iris1)

library(vip)
#> 
#> Attaching package: 'vip'
#> The following object is masked from 'package:utils':
#> 
#>     vi

vi(iris_fit$fit,
   lambda = iris_fit$fit$lambda[10])
#> # A tibble: 4 x 3
#>   Variable     Importance Sign 
#>   <chr>             <dbl> <chr>
#> 1 Sepal.Width        3.35 POS  
#> 2 Sepal.Length       0    NEG  
#> 3 Petal.Width       -2.97 NEG  
#> 4 Petal.Length      -3.98 NEG

Создано 14.05.2020 с помощью пакета (v0.3.0)

1 голос
/ 28 мая 2020

Для объектов «gl mnet» правильный аргумент должен быть s, а не lambda, для согласованности с coef.glmnet (однако вызов этого с vi() в настоящее время вызывает ошибку из-за частичного сопоставления с аргументом scale --- я сделаю sh исправление в эти выходные; https://github.com/koalaverse/vip/issues/103). Также, начиная с версии 0.2.2, vi_model должен работать напрямую с объектами model_fit. Итак, правильный вызов здесь должен быть:

> vi_model(iris_fit, s = iris_fit$fit$lambda[10]). #
# A tibble: 4 x 3
  Variable     Importance Sign 
  <chr>             <dbl> <chr>
1 Sepal.Length      0     NEG  
2 Sepal.Width       0     NEG  
3 Petal.Length     -0.721 NEG  
4 Petal.Width       0     NEG 

Что касается vi_firm() и pdp::partial(), проще всего создать свою собственную оболочку предсказания. В документации по каждой функции должно быть много деталей, и это больше примеров в нашей предстоящей статье (https://github.com/koalaverse/vip/blob/master/rjournal/RJwrapper.pdf), но вот базовый пример c:

> # Data matrix (features only)
> X <- data.matrix(subset(iris1, select = -class))
> 
> # Prediction wrapper for partial dependence
> pfun <- function(object, newdata) {
+   # Return averaged prediciton for class of interest
+   mean(predict(object, newx = newdata, s = iris_fit$fit$lambda[10], 
+        type = "link")[, 1L])
+ }
> 
> # PDP-based VI
> features <- setdiff(names(iris1), "class")
> vip::vi_firm(
+   object = iris_fit$fit, 
+   feature_names = features, 
+   train = X, 
+   pred.fun = pfun
+ )
# A tibble: 4 x 2
  Variable     Importance
  <chr>             <dbl>
1 Sepal.Length       0   
2 Sepal.Width        0   
3 Petal.Length       1.27
4 Petal.Width        0   
> 
> # PDP
> pd <- pdp::partial(iris_fit$fit, "Petal.Length", pred.fun = pfun, 
+                    train = X)
> head(pd)
  Petal.Length      yhat
1     1.000000 1.0644756
2     1.140476 0.9632228
3     1.280952 0.8619700
4     1.421429 0.7607172
5     1.561905 0.6594644
6     1.702381 0.5582116
...