python - Cálculo de MAPE en H2o: Error: el tipo de columna provisto POSIXct es desconocido
loops prediction (3)
Siguiendo mi pregunta respondida: R o Python - haga un bucle con los datos de la prueba - Validación de la predicción las próximas 24 horas (96 valores cada día)
Quiero predecir el día siguiente utilizando el paquete H2o. Puede encontrar una explicación detallada de mi conjunto de datos en el mismo enlace anterior .
La dimensión de datos en H2o es diferente.
Entonces, después de hacer la predicción, quiero calcular el MAPE
Tengo que cambiar los datos de entrenamiento y pruebas al formato H2o
train_h2o <- as.h2o(train_data)
test_h2o <- as.h2o(test_data)
mape_calc <- function(sub_df) {
pred <- predict.glm(glm_model, sub_df)
actual <- sub_df$Ptot
mape <- 100 * mean(abs((actual - pred)/actual))
new_df <- data.frame(date = sub_df$date[[1]], mape = mape)
return(new_df)
}
# LIST OF ONE-ROW DATAFRAMES
df_list <- by(test_data, test_data$date, map_calc)
# FINAL DATAFRAME
final_df <- do.call(rbind, df_list)
El código superior funciona bien para la validación de predicción " No H2O " para el día siguiente y calcula el MAPE para cada día.
Intenté convertir el modelo predicho H2o al formato normal, pero de acuerdo con: https://stackoverflow.com/a/39221269/9341589 , no es posible.
Para hacer una predicción en H2O:
por ejemplo, digamos que queremos crear un modelo de bosque aleatorio
y <- "RealPtot" #target
x <- names(train_h2o) %>% setdiff(y) #features
rforest.model <- h2o.randomForest(y=y, x=x, training_frame = train_h2o, ntrees = 2000, mtries = 3, max_depth = 4, seed = 1122)
Luego podemos obtener la predicción para el conjunto de datos completo como se muestra a continuación.
predict.rforest <- as.data.frame(h2o.predict(rforest.model, test_h2o)
Pero en mi caso estoy tratando de obtener una predicción de un día utilizando mape_calc
NOTA: Cualquier pensamiento en R o Python será apreciado.
ACTUALIZACIÓN2 (ejemplo reproducible ): ** Siguiendo los pasos de @Darren Cook:
Proporcioné un ejemplo más simple: conjunto de datos de viviendas de Boston.
library(tidyverse)
library(h2o)
h2o.init(ip="localhost",port=54322,max_mem_size = "128g")
data(Boston, package = "MASS")
names(Boston)
[1] "crim" "zn" "indus" "chas" "nox" "rm" "age" "dis" "rad" "tax" "ptratio"
[12] "black" "lstat" "medv"
set.seed(4984)
#Added 15 minute Time and date interval
Boston$date<- seq(as.POSIXct("01-09-2017 03:00", format = "%d-%m-%Y %H:%M",tz=""), by = "15 min", length = 506)
#select first 333 values to be trained and the rest to be test data
train = Boston[1:333,]
test = Boston[334:506,]
#Dropped the date and time
train_data_finialized <- subset(train, select=-c(date))
test_data_finialized <- test
#Converted the dataset to h2o object.
train_h2o<- as.h2o(train_data_finialized)
#test_h2o<- as.h2o(test)
#Select the target and feature variables for h2o model
y <- "medv" #target
x <- names(train_data_finialized) %>% setdiff(y) #feature variables
# Number of CV folds (to generate level-one data for stacking)
nfolds <- 5
#Replaced RF model by GBM because GBM run faster
# Train & Cross-validate a GBM
my_gbm <- h2o.gbm(x = x,
y = y,
training_frame = train_h2o,
nfolds = nfolds,
fold_assignment = "Modulo",
keep_cross_validation_predictions = TRUE,
seed = 1)
mape_calc <- function(sub_df) {
p <- h2o.predict(my_gbm, as.h2o(sub_df))
pred <- as.vector(p)
actual <- sub_df$medv
mape <- 100 * mean(abs((actual - pred)/actual))
new_df <- data.frame(date = sub_df$date[[1]], mape = mape)
return(new_df)
}
# LIST OF ONE-ROW DATAFRAMES
df_list <- by(test_data_finialized, test_data_finialized$date, mape_calc)
final_df <- do.call(rbind, df_list)
Este es el error que estoy recibiendo ahora:
Error en .h2o.doSafeREST (h2oRestApiVersion = h2oRestApiVersion, urlSuffix = page,:
MENSAJE DE ERROR:
El tipo de columna proporcionado POSIXct es desconocido. No se puede continuar con el análisis debido a un argumento no válido.
¿Podría simplemente ser el formato de archivo que es el problema? Obtuve "el tipo de columna provisto POSIXct es desconocido" después de importar desde Excel y ejecutar:
hr_data_h2o <- as.h2o(hr_data)
split_h2o <- h2o.splitFrame(hr_data_h2o, c(0.7, 0.15), seed = 1234)
Cambié el archivo de origen a una pestaña delimitada (sin otros cambios) y el problema desapareció.
H2O se ejecuta en un proceso separado a R (ya sea que H2O esté en el servidor local o en un centro de datos distante). Los datos de H2O y los modelos de H2O se mantienen en ese proceso de H2O y no pueden ser vistos por R.
Lo que
dH <- as.h2o(dR)
hace es copiar un cuadro de datos R,
dR
, en el espacio de memoria del H2O.
El
dH
es entonces una variable R que describe el marco de datos H2O.
Es decir, es un puntero, o una manija;
No es el dato en sí.
Lo que
dR <- as.data.frame(dH)
hace es copiar los datos de la memoria del proceso H2O en la memoria del proceso R.
(
as.vector(dH)
hace lo mismo para cuando dH describe una sola columna)
Entonces, la forma más sencilla de modificar su
mape_calc()
, suponiendo que
sub_df
es un marco de datos R, es cambiar las primeras dos líneas de la siguiente manera:
mape_calc <- function(sub_df) {
p <- h2o.predict(rforest.model, as.h2o(sub_df))
pred <- as.vector(p)
actual <- sub_df$Ptot
mape <- 100 * mean(abs((actual - pred)/actual))
new_df <- data.frame(date = sub_df$date[[1]], mape = mape)
return(new_df)
}
Es decir, subir
sub_df
a H2O y dárselo a
h2o.predict()
.
Luego use
as.vector()
para descargar la predicción que se hizo.
Esto fue relativo a su código original. Así que mantén la versión original de esto:
# LIST OF ONE-ROW DATAFRAMES
df_list <- by(test_data, test_data$date, map_calc)
No uso
by()
directamente en
test_h2o
.
ACTUALIZACIÓN basada en la pregunta editada:
Hice dos cambios a su código de ejemplo.
Primero, quité la columna de fecha de
sub_df
.
Eso fue lo que estaba causando el mensaje de error.
El segundo cambio fue simplemente para simplificar el tipo de retorno; no es importante, pero terminó con la columna de fecha duplicada, antes.
mape_calc <- function(sub_df) {
sub_df_minus_date <- subset(sub_df, select=-c(date))
p <- h2o.predict(my_gbm, as.h2o(sub_df_minus_date))
pred <- as.vector(p)
actual <- sub_df$medv
mape <- 100 * mean(abs((actual - pred)/actual))
data.frame(mape = mape)
}
ASIDE:
h2o.predict()
es más eficiente cuando se trabaja en un lote de datos para hacer predicciones.
Poner
h2o.predict()
dentro de un bucle es un olor de código.
Sería mejor llamar
h2o.predict(rforest.model, test_h2o)
una vez, fuera del bucle, luego descargar las predicciones en R, y
cbind
a test_data, y luego usarlas en esos datos combinados.
ACTUALIZACIÓN Aquí está su ejemplo cambiado para que funcione de esa manera: (He agregado la predicción como una columna adicional a los datos de prueba; hay otras formas de hacerlo, por supuesto)
test_h2o <- as.h2o(subset(test_data_finialized, select=-c(date)))
p <- h2o.predict(my_gbm, test_h2o)
test_data_finialized$pred = as.vector(p)
mape_calc2 <- function(sub_df) {
actual <- sub_df$medv
mape <- 100 * mean(abs((actual - sub_df$pred)/actual))
data.frame(mape = mape)
}
df_list <- by(test_data_finialized, test_data_finialized$date, mape_calc2)
Debes notar que corre mucho más rápido.
ACTUALIZACIÓN ADICIONAL
:
by()
funciona agrupando los mismos valores de su segundo argumento y procesándolos juntos.
Como todas las marcas de tiempo son diferentes, está procesando una fila a la vez.
Busque en la biblioteca
xts
y, por ejemplo,
apply.daily()
para agrupar marcas de tiempo.
Pero para el caso simple de querer procesar por fecha, hay un simple truco.
Cambie su línea
by()
a:
df_list <- by(test_data_finialized, as.Date(test_data_finialized$date), mape_calc2)
El uso de
as.Date()
eliminará los tiempos.
Por lo tanto, todas las filas en el mismo día ahora tienen el mismo aspecto y se procesan juntas.
ASIDE 2: Obtendrás mejores respuestas si haces el infame .com/help/mcve . Entonces las personas pueden ejecutar su código y pueden probar sus respuestas. También suele ser mejor usar un conjunto de datos simple que todos tenemos, por ejemplo, el iris, en lugar de sus propios datos. (Puedes hacer una regresión en cualquiera de los primeros 4 campos; el uso del iris no siempre tiene que ser una predicción de la especie).
ASIDE 3
: puede hacer MAPE completamente dentro de H2O, ya que las funciones
abs()
y
mean()
funcionarán directamente en los marcos de datos H2O (al igual que muchas otras cosas; consulte el manual de H2O):
https://.com/a/43103229/841830
(No lo estoy marcando como un duplicado, ya que su pregunta era cómo adaptarse
by()
para usar con marcos de datos H2O, ¡no cómo calcular MAPE de manera eficiente!)
Parece que estás mezclando los tipos de datos R y H2O. Recuerde que la R de H2O es simplemente una API de R y no es lo mismo que la R. nativa. Esto significa que no puede aplicar una función R que espera un marco de datos R a un H2OFrame. Y tampoco puede aplicar una función H2O a un marco de datos R cuando espera un H2OFrame.
Como puede ver en la documentación de R, es una función que espera "un objeto R, normalmente un marco de datos, posiblemente una matriz", por lo que no puede pasar un marco H2O.
Del mismo modo, está pasando la
date = H2OFrame
a
data.frame()
.
Sin embargo, puede usar
as.data.frame()
para convertir un H2OFrame en un marco de datos R y luego realizar sus cálculos completamente en R.