Растровые прогнозы не воспроизводят сеанс за сеансом, когда факторная переменная включена в модель

Этот вопрос связан с тем, который я опубликовал полтора года назад: Воспроизводимость результатов функции predict() - растровый пакет. Но поскольку у него не было примера, я создал новый вопрос также с обновленной информацией.

У меня есть несколько неясная проблема с воспроизведением моих прогнозов в растр. Я создаю модель gbm с числовыми переменными и одной факторной переменной. Затем я использую растровый пакет для прогнозирования растра, используя мою обученную модель. Прогнозы варьируются от сеанса к сеансу, но воспроизводятся в рамках одного сеанса R. Если я удаляю факторную переменную, результаты воспроизводятся от сеанса к сеансу. Кроме того, в приведенном ниже примере, если у меня больше уровней фактора в обучающих данных, чем в версии растровой переменной, я могу заставить его воспроизводить сеанс за сеансом. Что вызывает это и как я могу воспроизвести сеанс результатов в сеансе, включив факторную переменную?

# This code will not reproduce session to session, but does if I leave many many factor levels in newwine with the
# commented out code

library(breakDown)
library(gbm)
library(dplyr)
library(raster)

# leave in many levels and code will reproduce session to session
#newwine <- wine[1:500,c(1:3,6)]

# specify only levels which are in the below raster and code will not reproduce session to session
newwine <- wine[,c(1:3,6)] %>%
           filter(free.sulfur.dioxide == 3 | free.sulfur.dioxide == 10 | free.sulfur.dioxide == 15 |
                  free.sulfur.dioxide == 37 | free.sulfur.dioxide == 76)

head(newwine)

# make free.sulfur.dioxide as factor variable
newwine$free.sulfur.dioxide <- as.factor(newwine$free.sulfur.dioxide)
levels(newwine$free.sulfur.dioxide)

set.seed(123)
model <- gbm(fixed.acidity ~ ., data = newwine,
             distribution = "gaussian",
             bag.fraction = 0.50,
             n.trees = 1000,
             interaction.depth = 16,
             shrinkage = 0.016,
             n.minobsinnode = 10, verbose = FALSE)

summary(model)
plot(model, i.var = 3, n.trees = 1000)


# make some rasters for the predictor variables
free.sulfur.dioxide <- c(rep(3,times=10), rep(10, times = 10),
                         rep(15, times = 10), rep(37, times = 10),
                         rep(76, times = 10))

free.sulfur.dioxide.r <- raster(ext = extent(-10, 5, -10, 5), nrows = 5, ncols = 10)
values(free.sulfur.dioxide.r) <- free.sulfur.dioxide

set.seed(123)
volatile.acidity <- newwine %>%
                    dplyr::select(volatile.acidity) %>%
                    sample_n(50)
volatile.acidity <- as.vector(volatile.acidity)[,1]
volatile.acidity.r <- raster(ext = extent(-10, 5, -10, 5), nrows = 5, ncols = 10)
values(volatile.acidity.r) <- volatile.acidity

set.seed(123)
citric.acid <- newwine %>%
               dplyr::select(citric.acid) %>%
               sample_n(50)
citric.acid <- as.vector(citric.acid)[,1]
citric.acid.r <- raster(ext = extent(-10, 5, -10, 5), nrows = 5, ncols = 10)
values(citric.acid.r) <- citric.acid

# create a raster stack
r <- stack(free.sulfur.dioxide.r, volatile.acidity.r, citric.acid.r)
names(r) <- c("free.sulfur.dioxide", "volatile.acidity", "citric.acid")

###########################################################################################################################

# predict to a raster with raster predict
pred <- predict(r, model, n.trees = model$n.trees, format="GTiff")
writeRaster(pred, "prediction1.tif", overwrite = TRUE)

###########################################################################################################################

# close the session and reopen, run until line 61, then run below to make a new prediction, called prediction 2
pred <- predict(r, model, n.trees = model$n.trees, format="GTiff")
writeRaster(pred, "prediction2.tif", overwrite = TRUE)

# read in the previous prediction
prediction1 <- raster("prediction1.tif")
prediction2 <- raster("prediction2.tif")

# compare rasters built across sessions
compareRaster(prediction1, prediction2, values = TRUE)
summary(prediction1-prediction2)

# compare rasters built within same session
pred2 <- predict(r, model, n.trees = model$n.trees, format="GTiff")
compareRaster(pred, pred2, values = TRUE)

Однако приведенный ниже код не использует переменную factor и будет воспроизводить сеанс за сеансом.

### Same exercise but without setting the free sulfur dioxide to factor
## this code will reproduce session to session

library(breakDown)
library(gbm)
library(dplyr)
library(raster)

newwine <- wine[1:500,c(1:3)]

head(newwine)

set.seed(123)
model <- gbm(fixed.acidity ~ ., data = newwine,
             distribution = "gaussian",
             bag.fraction = 0.50,
             n.trees = 1000,
             interaction.depth = 16,
             shrinkage = 0.016,
             n.minobsinnode = 10, verbose = FALSE)

summary(model)

set.seed(123)
volatile.acidity <- newwine %>%
  dplyr::select(volatile.acidity) %>%
  sample_n(50)
volatile.acidity <- as.vector(volatile.acidity)[,1]
volatile.acidity.r <- raster(ext = extent(-10, 5, -10, 5), nrows = 5, ncols = 10)
values(volatile.acidity.r) <- volatile.acidity

set.seed(123)
citric.acid <- newwine %>%
  dplyr::select(citric.acid) %>%
  sample_n(50)
citric.acid <- as.vector(citric.acid)[,1]
citric.acid.r <- raster(ext = extent(-10, 5, -10, 5), nrows = 5, ncols = 10)
values(citric.acid.r) <- citric.acid

# create a raster stack
r <- stack( volatile.acidity.r, citric.acid.r)
names(r) <- c( "volatile.acidity", "citric.acid")

#######################################################################################################################

# predict to a raster with raster predict
pred <- predict(r, model, n.trees = model$n.trees, format="GTiff")
writeRaster(pred, "prediction1.tif", overwrite = TRUE)

#######################################################################################################################

# close the session and reopen to make a new prediction, called prediction 2
pred <- predict(r, model, n.trees = model$n.trees, format="GTiff")
writeRaster(pred, "prediction2.tif", overwrite = TRUE)

# read in the previous prediction
prediction1 <- raster("prediction1.tif")
prediction2 <- raster("prediction2.tif")

# compare rasters built across sessions
compareRaster(prediction1, prediction2, values = TRUE)
summary(prediction1-prediction2)

# compare rasters built within same session
pred2 <- predict(r, model, n.trees = model$n.trees, format="GTiff")
compareRaster(pred, pred2, values = TRUE)
summary(pred-pred2)

person user29609    schedule 28.04.2018    source источник
comment
Можете ли вы сгенерировать некоторые данные с помощью кода? Без примеров данных довольно сложно дать ответ. Тогда было бы также хорошо показать, чем отличаются результаты.   -  person Robert Hijmans    schedule 28.04.2018
comment
Привет, данные встроены в пакет breakDown. Когда вы загружаете библиотеку, становится доступным набор данных wine, что и используется в этом примере.   -  person user29609    schedule 28.04.2018
comment
Проблема, возможно, связана с принятым ответом здесь: stackoverflow.com/questions/25121725/. Я могу воспроизвести результаты для сеансов R, если подойду к модели с помощью gbm.fit() и задам x и y явно, а не использую формулу в gbm().   -  person user29609    schedule 28.04.2018
comment
Хорошо спасибо. Я постараюсь посмотреть на это (хотя я думаю, что никогда не следует сохранять сеансы).   -  person Robert Hijmans    schedule 28.04.2018
comment
Я не сохраняю сеанс, а делаю растровый прогноз, закрываю сеанс (не сохраняю), затем начинаю заново, чтобы сделать второй прогноз. Затем я сравниваю оба прогноза, считывая оба растра обратно. Они должны быть точно такими же, но немного отличаются. Сравниваю отличия с summary(prediction1 - prediction2).   -  person user29609    schedule 28.04.2018
comment
О, извините, я неправильно понял.   -  person Robert Hijmans    schedule 28.04.2018


Ответы (2)


arrow_upward
1
arrow_downward

Похоже, что эта проблема связана не с пакетом raster, а с пакетом gbm. Немного покопавшись, я обнаружил, что пакет gbm был потерян в марте 2017 года, и есть новый пакет gbm под названием gbm3 на github (пока недоступен в CRAN) https://github.com/gbm-developers/gbm3. Когда вы прогнозируете растр, вы используете любой метод прогнозирования, который требует ваш тип модели (например, predict.gbm() для gbm и predict.GBMFit() для gbm3. Кажется, predict.gbm() просто неправильно обрабатывает факторы, поступающие из растров в моделях. Это может быть или не быть ошибкой. , но в любом случае этот пакет больше не поддерживается gbm3 делает свое дело и воспроизводим.

# This code will reproduce session to session for the gbm3 model, but not for old gbm model

library(breakDown)
# install gbm3 from github
library(gbm3)
library(dplyr)
library(raster)

# specify only levels which are in the below raster
newwine <- wine[,c(1:3,6)] %>%
           filter(free.sulfur.dioxide == 3 | free.sulfur.dioxide == 10 | free.sulfur.dioxide == 15 |
                  free.sulfur.dioxide == 37 | free.sulfur.dioxide == 76)

head(newwine)

# make free.sulfur.dioxide as factor variable
newwine$free.sulfur.dioxide <- as.factor(newwine$free.sulfur.dioxide)
levels(newwine$free.sulfur.dioxide)

#set.seed(123)
# model <-  gbm(fixed.acidity ~ ., data = newwine, #gbm.fit(x = newwine[,2:4], y = newwine[,1],
#              distribution = "gaussian",
#              bag.fraction = 0.50,
#              n.trees = 1000,
#              interaction.depth = 16,
#              shrinkage = 0.016,
#              n.minobsinnode = 10, verbose = FALSE)
set.seed(123)
model <- gbmt(fixed.acidity ~ ., data = newwine, distribution = gbm_dist("Gaussian"))

summary(model)
plot(model, var_index = 3, num_trees = 1000)

# make some rasters for the predictor variables
free.sulfur.dioxide <- c(rep(3,times=10), rep(10, times = 10),
                         rep(15, times = 10), rep(37, times = 10),
                         rep(76, times = 10))

free.sulfur.dioxide.r <- raster(ext = extent(-10, 5, -10, 5), nrows = 5, ncols = 10)
values(free.sulfur.dioxide.r) <- free.sulfur.dioxide

set.seed(123)
volatile.acidity <- newwine %>%
                    dplyr::select(volatile.acidity) %>%
                    sample_n(50)
volatile.acidity <- as.vector(volatile.acidity)[,1]
volatile.acidity.r <- raster(ext = extent(-10, 5, -10, 5), nrows = 5, ncols = 10)
values(volatile.acidity.r) <- volatile.acidity

set.seed(123)
citric.acid <- newwine %>%
               dplyr::select(citric.acid) %>%
               sample_n(50)
citric.acid <- as.vector(citric.acid)[,1]
citric.acid.r <- raster(ext = extent(-10, 5, -10, 5), nrows = 5, ncols = 10)
values(citric.acid.r) <- citric.acid

# create a raster stack
r <- stack(free.sulfur.dioxide.r, volatile.acidity.r, citric.acid.r)
names(r) <- c("free.sulfur.dioxide", "volatile.acidity", "citric.acid")

###########################################################################################################################

# predict to a raster with raster predict
pred <- raster::predict(r, model, n.trees = 2000, format="GTiff")
writeRaster(pred, "prediction1.tif", overwrite = TRUE)

# predict to a vector with predict
v <- values(r)
v <- data.frame(v)
v$free.sulfur.dioxide <- as.factor(v$free.sulfur.dioxide)
vpred <- predict(model, v, n.trees = 2000)
write.table(vpred, "vector_predict.txt", row.names = FALSE, col.names = TRUE)

###########################################################################################################################

# close the session and reopen, run until #### line, then run below to make a new prediction, called prediction 2
pred <- raster::predict(r, model, n.trees = 2000, format="GTiff")
writeRaster(pred, "prediction2.tif", overwrite = TRUE)

# predict to a vector with predict
v <- values(r)
v <- data.frame(v)
v$free.sulfur.dioxide <- as.factor(v$free.sulfur.dioxide)
vpred <- predict(model, v, n.trees = 2000)
write.table(vpred, "vector_predict2.txt", row.names = FALSE, col.names = TRUE)

# read in the previous prediction
prediction1 <- raster("prediction1.tif")
prediction2 <- raster("prediction2.tif")

# compare rasters built across sessions
compareRaster(prediction1, prediction2, values = TRUE)
summary(prediction1-prediction2)

# compare rasters built within same session
pred2 <- raster::predict(r, model, n.trees = 2000, format="GTiff", factors = f)
compareRaster(pred, pred2, values = TRUE)

# compare the vector predictions
p1 <- read.delim("vector_predict.txt")
p2 <- read.delim("vector_predict2.txt")

plot(p1$x,p2$x)

summary(p1$x - p2$x)
person user29609    schedule 01.05.2018

arrow_upward
0
arrow_downward

Это не решение, а попытка закрыть проблему. Мне кажется, что это не связано с raster.

Когда я делаю:

v <- values(r)
pred <- predict(model, data.frame(v), n.trees = model$n.trees)
rpred <- predict(r, model, n.trees = model$n.trees)

Выйдите, сохраните сеанс, запустите новый сеанс и выполните:

library(gbm)
library(raster)
pred2 <- predict(model, data.frame(v), n.trees = model$n.trees )
rpred2 <- predict(r, model, n.trees = model$n.trees)

Я вижу, что значения pred и pred2 не совсем совпадают. (см. plot(pred, pred2). Однако значения pred2 и rpred2 одинаковы: plot(values(rpred2), pred2).

В качестве альтернативы, когда я сохраняю pred (saveRDS(pred, 'pred.rds') и загружаю его в новый сеанс pred1 <- readRDS(pred.rds), результаты не совсем такие же.

Мне кажется, что где-то в gbm происходит какая-то рандомизация, которая не контролируется set.seed.

person Robert Hijmans    schedule 28.04.2018
comment
Вы имеете в виду, что значения rpred и rpred2 одинаковы? - person user29609; 28.04.2018
comment
Нет, это не так, но они такие же, как pred и pred2. То есть кажется, что разница берет свое начало в gbm.predict; а не в raster::predict. - person Robert Hijmans; 29.04.2018
comment
А, хорошо, я это вижу. Однако, если я предсказываю данные обучения с помощью tpred <- predict(model, newwine, n.trees = model$n.trees, результаты будут одинаковыми каждый раз, когда я предсказываю в новом сеансе. Выполняет ли values() какие-либо преобразования в факторные переменные? - person user29609; 29.04.2018
comment
class(data.frame(v)$free.sulfur.dioxide) возвращает числовое значение. - person user29609; 29.04.2018
comment
Если я сделаю это: v <- values(r) v <- data.frame(v) v$free.sulfur.dioxide <- as.factor(v$free.sulfur.dioxide) vpred <- predict(model, v, n.trees = model$n.trees), он будет воспроизводить сеанс за сеансом. - person user29609; 29.04.2018
comment
мы также пытались прогнозировать из растрового стека со случайным лесом, и это воспроизводимо, поэтому похоже, что проблема была вызвана прогнозом gbm. - person user29609; 02.05.2018