Повышение производительности цикла For L в R для вычисления всех значений Shapley - PullRequest
1 голос
/ 27 июня 2019

В настоящее время я работаю над циклом For в R. Если я запускаю цикл For для своих собственных данных, это занимает много времени, и я верю, потому что я сделал что-то неэффективное в своем коде. Не могли бы вы помочь мне улучшить его?

# Loop through the samples, explaining one instance at a time.
shap_values <- vector("list", nrow(X))  # initialize the results list.
system.time({
  for (i in seq_along(shap_values)) {
    set.seed(224)
    shap_values[[i]] <- iml::Shapley$new(predictor, x.interest = X[i, ],sample.size = 30)$results
    shap_values[[i]]$predicted_value <- iml::Shapley$new(predictor, x.interest = X[i, ],sample.size = 30)$y.hat.interest
    shap_values[[i]]$sample_num <- i  # identifier to track our instances.
  }
  data_shap_values <- dplyr::bind_rows(shap_values)  # collapse the list.
})

Я считаю, что моя проблема в

shap_values[[i]]$sample_num

переменная, так как я переделываю там вычисления предыдущих

shap_values[[i]]$predicted_value

переменная. Причина, по которой я добавил эту переменную, заключалась в том, что мне нужно было

$y.hat.interest

как часть нового фрейма данных (который называется «shap_values», а затем «data_shap_values»).

Воспроизводимый пример: (начинается с "Это важная часть:)

#Example Shapley
#https://cran.r-project.org/web/packages/iml/vignettes/intro.html

data("Boston", package  = "MASS")
head(Boston)

set.seed(42)
#install.packages("iml")
library("iml")
library("randomForest")
data("Boston", package  = "MASS")
rf = randomForest(medv ~ ., data = Boston, ntree = 50)

# We create a Predictor object, that holds the model and the data. 
# The iml package uses R6 classes: New objects can be created by calling Predictor$new()
X = Boston[which(names(Boston) != "medv")]
predictor = Predictor$new(rf, data = X, y = Boston$medv)

# Feature Importance
## Shifting each future, and measring how much the performance drops ## 
imp = FeatureImp$new(predictor, loss = "mae")
plot(imp)


# Shapley value. Assume that for 1 data point, the feature values play a game together, in which 
# they get the prediction as payout. Tells us how fairly distibute the payout among the feature values. 
View(X)
shapley = Shapley$new(predictor, x.interest = X[1,])
shapley$plot()

# Reuse the object to explain other data points 
shapley$explain(x.interest = X[2,])
shapley$plot()

# Results in data.frame form can be extracted like this: 
results = shapley$results
head(results)


# THIS IS THE IMPORTANT PART: 

# It might make sense for testing, to reduce the data: 
X = X[1:10,]

# Loop through the samples, explaining one instance at a time.
shap_values <- vector("list", nrow(X))  # initialize the results list.
system.time({
  for (i in seq_along(shap_values)) {
    set.seed(224)
    shap_values[[i]] <- iml::Shapley$new(predictor, x.interest = X[i, ],sample.size = 30)$results
    shap_values[[i]]$predicted_value <- iml::Shapley$new(predictor, x.interest = X[i, ],sample.size = 30)$y.hat.interest
    shap_values[[i]]$sample_num <- i  # identifier to track our instances.
  }
  data_shap_values <- dplyr::bind_rows(shap_values)  # collapse the list.
})

Обновление

По запросу @Ralf Stubner для профилирования цикла for:

enter image description here

1 Ответ

1 голос
/ 27 июня 2019

Вы удваиваете время выполнения, дважды вызывая imp::Shapely$new с одинаковыми параметрами.В качестве альтернативы вы можете создать объект один раз и извлечь два значения:

system.time({
    for (i in seq_along(shap_values)) {
        set.seed(224)
        shapley <- iml::Shapley$new(predictor, x.interest = X[i, ],sample.size = 30)
        shap_values[[i]] <- shapley$results
        shap_values[[i]]$predicted_value <- shapley$y.hat.interest
        shap_values[[i]]$sample_num <- i  # identifier to track our instances.
    }
    data_shap_values <- dplyr::bind_rows(shap_values)  # collapse the list.
})

Если у вас достаточно ОЗУ для хранения ваших данных несколько раз, вы можете также попробовать параллельную обработку, используя parallel, foreach или future.apply.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...