Recibí algunas solicitudes sobre el soporte de restricciones monótonas en cierta función con respecto a la salida,
es decir, cuando se fijan otras características, obligar a que la predicción sea monótona aumentando con respecto a la característica especificada determinada. Estoy abriendo este número para ver el interés general sobre esta función. Puedo agregar esto si hay suficiente interés en esto,
Necesitaría la ayuda de voluntarios de la comunidad para probar la función beta y contribuir con documentos y tutoriales sobre el uso de esta función. Responde el problema si estás interesado.
Se proporciona una versión experimental en https://github.com/dmlc/xgboost/pull/1516. Para usar esto antes de que se fusione, clone el repositorio https://github.com/tqchen/xgboost ,
Active las siguientes opciones (probablemente sea posible a través de python, r API)
monotone_constraints = "(0,1,1,0)"
Hay dos argumentos
monotone_constraints
es una lista en la longitud del número de características, 1 indica monótona creciente, - 1 significa decreciente, 0 significa sin restricción. Si es más corto que el número de funciones, se rellenará 0.Actualmente solo se admite el algoritmo codicioso exacto en varios núcleos. Aún no disponible en versión distribuida
@tqchen Recibí una solicitud en el trabajo hoy para construir algunos GBM con restricciones monótonas para probar el rendimiento de algunos otros modelos. Esto sería con una pérdida por desviación de tweedie, por lo que tendría que optar por una función de pérdida personalizada tal como está hoy.
En cualquier caso, parece una buena oportunidad para ayudar y trabajar al mismo tiempo.
Basado en la charla aquí , GBM (R Package) solo refuerza la monotonicidad localmente.
¿Podría aclarar cómo XGBoost aplica restricciones monótonas?
Sería genial si XGBoost pudiera hacer cumplir las restricciones globales.
No entiendo lo que quiere decir con restricción local o global, ¿puede darnos más detalles?
Lo siento, pego el enlace incorrecto, aquí está el correcto (Enlace)
Cada árbol solo puede seguir una restricción monótona en cierto subconjunto de la característica interesada, por lo que muchos árboles en conjunto pueden crear una violación de la monotonicidad general en todo el rango de esa característica.
De acuerdo, a mi entender, se aplica a nivel mundial. Le invitamos a probarlo.
Acabo de hacer algunas pruebas simples de restricción de monotonicidad en el contexto de una regresión univariante. Puede encontrar el código y una documentación muy breve aquí:
Algunas observaciones iniciales:
Resulta que introduzco un error en el caso de la restricción = -1. Presioné una solución, compruebe si la versión más reciente funciona bien. Compruebe también si funciona cuando hay varias restricciones
@tqchen Probé tu solución para el error de decresing, parece que está funcionando ahora.
Confirmemos si hay una disminución de velocidad en comparación con la versión original en algunos de los conjuntos de datos estándar, luego podemos fusionarlos en
@tqchen Probé un modelo de dos variables, una con una restricción creciente y otra con una disminución:
params_constrained = params.copy()
params_constrained['updater'] = "grow_monotone_colmaker,prune"
params_constrained['monotone_constraints'] = "(1,-1)"
Los resultados son buenos
Intentaré encontrar un poco de tiempo para hacer algunas pruebas de cronometraje esta tarde.
Hice una actualización a # 1516 para permitir la detección automática de opciones montone, ahora el usuario solo necesita pasar monotone_constraints = "(0,1,1,0)"
, verifique si funciona.
Combinaré esto si las pruebas de velocidad van bien, y pasemos a la siguiente etapa para agregar tutoriales
@madrury @ XiaoxiaoWang87
Se agregaron pruebas para el caso multivariado aquí:
no constraint: 964.9 microseconds per iteration
with constraint: 861.7 microseconds per iteration
(comente si tiene una mejor manera de hacer la prueba de velocidad)
Check failed: (wleft) <= (wright)
al jugar con diferentes hiperparámetros.Ejecuté un par de experimentos de cronometraje en un cuaderno jupyter.
Primera prueba: algunos datos simulados simples. Hay dos características, una creciente y otra decreciente, pero con una pequeña onda sinusoidal superpuesta para que cada característica no sea realmente monótona.
X = np.random.random(size=(N, K))
y = (5*X[:, 0] + np.sin(5*2*pi*X[:, 0])
- 5*X[:, 1] - np.cos(5*2*pi*X[:, 1])
+ np.random.normal(loc=0.0, scale=0.01, size=N))
A continuación, se muestran los resultados de sincronización de xgboosts con y sin restricciones monótonas. Apagué la parada anticipada y aumenté un número determinado de iteraciones para cada una.
Primero sin restricciones monótonas:
%%timeit -n 100
model_no_constraints = xgb.train(params, dtrain,
num_boost_round = 2500,
verbose_eval = False)
100 loops, best of 3: 246 ms per loop
Y aquí con limitaciones de monotonicidad
%%timeit -n 100
model_with_constraints = xgb.train(params_constrained, dtrain,
num_boost_round = 2500,
verbose_eval = False)
100 loops, best of 3: 196 ms per loop
Segunda prueba: datos de California hHousing de sklearn. Sin restricciones
%%timeit -n 10
model_no_constraints = xgb.train(params, dtrain,
num_boost_round = 2500,
verbose_eval = False)
10 loops, best of 3: 5.9 s per loop
Aquí están las restricciones que utilicé
print(params_constrained['monotone_constraints'])
(1,1,1,0,0,1,0,0)
Y el momento para el modelo restringido
%%timeit -n 10
model_no_constraints = xgb.train(params, dtrain,
num_boost_round = 2500,
verbose_eval = False)
10 loops, best of 3: 6.08 s per loop
@ XiaoxiaoWang87 He presionado a otro RP para que pierda el control de wleft y wright, por favor vea que funciona.
@madrury ¿También se puede comparar con la versión anterior de XGBoost sin la función de restricción?
@tqchen Seguro. ¿Puedes recomendar un hash de confirmación para compararlo? ¿Debería usar el compromiso antes de agregar las restricciones monótonas?
Sí, el anterior servirá
@tqchen Al reconstruir la versión actualizada, recibo algunos errores que no tenía antes. Espero que la razón te salte claramente.
Si trato de ejecutar el mismo código que antes, obtengo una excepción, aquí está el rastreo completo:
XGBoostError Traceback (most recent call last)
<ipython-input-14-63a9f6e16c9a> in <module>()
8 model_with_constraints = xgb.train(params, dtrain,
9 num_boost_round = 1000, evals = evallist,
---> 10 early_stopping_rounds = 10)
/Users/matthewdrury/anaconda/lib/python2.7/site-packages/xgboost-0.6-py2.7.egg/xgboost/training.pyc in train(params, dtrain, num_boost_round, evals, obj, feval, maximize, early_stopping_rounds, evals_result, verbose_eval, learning_rates, xgb_model, callbacks)
201 evals=evals,
202 obj=obj, feval=feval,
--> 203 xgb_model=xgb_model, callbacks=callbacks)
204
205
/Users/matthewdrury/anaconda/lib/python2.7/site-packages/xgboost-0.6-py2.7.egg/xgboost/training.pyc in _train_internal(params, dtrain, num_boost_round, evals, obj, feval, xgb_model, callbacks)
72 # Skip the first update if it is a recovery step.
73 if version % 2 == 0:
---> 74 bst.update(dtrain, i, obj)
75 bst.save_rabit_checkpoint()
76 version += 1
/Users/matthewdrury/anaconda/lib/python2.7/site-packages/xgboost-0.6-py2.7.egg/xgboost/core.pyc in update(self, dtrain, iteration, fobj)
804
805 if fobj is None:
--> 806 _check_call(_LIB.XGBoosterUpdateOneIter(self.handle, iteration, dtrain.handle))
807 else:
808 pred = self.predict(dtrain)
/Users/matthewdrury/anaconda/lib/python2.7/site-packages/xgboost-0.6-py2.7.egg/xgboost/core.pyc in _check_call(ret)
125 """
126 if ret != 0:
--> 127 raise XGBoostError(_LIB.XGBGetLastError())
128
129
XGBoostError: [14:08:41] src/tree/tree_updater.cc:18: Unknown tree updater grow_monotone_colmaker
Si cambio todo por el argumento de palabra clave que implementó, también obtengo un error:
TypeError Traceback (most recent call last)
<ipython-input-15-ef7671f72925> in <module>()
8 monotone_constraints="(1)",
9 num_boost_round = 1000, evals = evallist,
---> 10 early_stopping_rounds = 10)
TypeError: train() got an unexpected keyword argument 'monotone_constraints'
elimine el argumento del actualizador y mantenga los argumentos de restricción monótonos en los parámetros, ahora que el actualizador de restricciones monótonas se activa automáticamente cuando se presentan restricciones monótonas
@tqchen Mi amigo @amontz me ayudó a entender eso inmediatamente después de publicar el mensaje. Había interpretado su comentario como pasar monotone_constraints
como un kwarg a .train
.
Funciona con esos ajustes. Gracias.
@madrury ¿puedes confirmar la velocidad?
También @madrury y @ XiaoxiaoWang87, dado que esta función está a punto de fusionarse, sería genial si pudiera coordinar la creación de un tutorial que presente esta función a los usuarios.
No podemos llevar directamente ipy notebook al repositorio principal. pero las imágenes se pueden enviar a https://github.com/dmlc/web-data/tree/master/xgboost y se pueden reducir al repositorio principal.
También necesitamos cambiar la conversión de cadenas de la interfaz de front-end, de modo que int tuple se pueda convertir al formato de tuplas de cadenas que pueda ser aceptado por el backend.
@ hetong007 para cambios en R y @slundberg para Julia
@tqchen Julia está actualmente adjunta a la versión 0.4 de XGBoost, así que la próxima vez que necesite usarlo y tener tiempo reservado, actualizaré los enlaces si nadie más lo ha hecho para entonces. En ese momento, este cambio también se puede agregar.
Aquí está la comparación entre modelos _sin_ una restricción monótona desde antes de la implementación hasta después.
Confirmar 8cac37 : antes de la implementación de la restricción monótona. '
Datos simulados : 100 loops, best of 3: 232 ms per loop
Datos de California : 10 loops, best of 3: 5.89 s per loop
Confirmar b1c224 : después de la implementación de la restricción monótona.
Datos simulados : 100 loops, best of 3: 231 ms per loop
Datos de California : 10 loops, best of 3: 5.61 s per loop
La aceleración para California después de la implementación me parece sospechosa, pero la intenté dos veces en cada sentido y es consistente.
Me encantaría intentar escribir un tutorial. Revisaré la documentación existente y armaré algo en los próximos días.
Esto es genial, el RP ahora está oficialmente fusionado con el maestro. Esperando ver el tutorial
Gracias @madrury. Espero que llegue. Hágame saber en qué puedo ayudar. Ciertamente estaría dispuesto a tener más estudios sobre este tema.
Lo mejoraré mañana. Solo tengo curiosidad sobre la razón de comunicarme con C ++ a través de una cadena en lugar de una matriz.
Estoy probando desde R. Genere aleatoriamente datos de dos variables e intento hacer una predicción.
Sin embargo, encontré que
monotone_constraints
hace que la predicción sea ligeramente diferente.Por favor, indíquelo si cometí algún error.
El código para reproducirlo (probado en la última versión de github , no desde drat
):
set.seed(1024)
x1 = rnorm(1000, 10)
x2 = rnorm(1000, 10)
y = -1*x1 + rnorm(1000, 0.001) + 3*sin(x2)
train = cbind(x1, x2)
bst = xgboost(data = train, label = y, max_depth = 2,
eta = 0.1, nthread = 2, nrounds = 10,
monotone_constraints = '(1,-1)')
pred = predict(bst, train)
ind = order(train[,1])
pred.ord = pred[ind]
plot(train[,1], y, main = 'with constraint')
pred.ord = pred[order(train[,1])]
lines(pred.ord)
bst = xgboost(data = train, label = y, max_depth = 2,
eta = 0.1, nthread = 2, nrounds = 10)
pred = predict(bst, train)
ind = order(train[,1])
pred.ord = pred[ind]
plot(train[,1], y, main = 'without constraint')
pred.ord = pred[order(train[,1])]
lines(pred.ord)
La restricción se realizó en el pedido parcial. Por lo tanto, la restricción solo se aplica si estamos moviendo el eje montone, manteniendo el otro eje fijo
@ hetong007 Para hacer mis parcelas yo
seq
en R.colmeans
en R.Aquí está el código de Python que usé para los gráficos que incluí arriba, debería convertirse fácilmente a un código R equivalente.
def plot_one_feature_effect(model, X, y, idx=1):
x_scan = np.linspace(0, 1, 100)
X_scan = np.empty((100, X.shape[1]))
X_scan[:, idx] = x_scan
left_feature_means = np.tile(X[:, :idx].mean(axis=0), (100, 1))
right_feature_means = np.tile(X[:, (idx+1):].mean(axis=0), (100, 1))
X_scan[:, :idx] = left_feature_means
X_scan[:, (idx+1):] = right_feature_means
X_plot = xgb.DMatrix(X_scan)
y_plot = model.predict(X_plot, ntree_limit=bst.best_ntree_limit)
plt.plot(x_scan, y_plot, color = 'black')
plt.plot(X[:, idx], y, 'o', alpha = 0.25)
Así es como hago las gráficas de dependencia parcial (para un modelo arbitrario):
Código:
def plot_partial_dependency(bst, X, y, f_id):
X_temp = X.copy()
x_scan = np.linspace(np.percentile(X_temp[:, f_id], 0.1), np.percentile(X_temp[:, f_id], 99.5), 50)
y_partial = []
for point in x_scan:
X_temp[:, f_id] = point
dpartial = xgb.DMatrix(X_temp[:, feature_ids])
y_partial.append(np.average(bst.predict(dpartial)))
y_partial = np.array(y_partial)
# Plot partial dependence
fig, ax = plt.subplots()
fig.set_size_inches(5, 5)
plt.subplots_adjust(left = 0.17, right = 0.94, bottom = 0.15, top = 0.9)
ax.plot(x_scan, y_partial, '-', color = 'black', linewidth = 1)
ax.plot(X[:, f_id], y, 'o', color = 'blue', alpha = 0.02)
ax.set_xlim(min(x_scan), max(x_scan))
ax.set_xlabel('Feature X', fontsize = 10)
ax.set_ylabel('Partial Dependence', fontsize = 12)
¡Gracias por la orientación! Me di cuenta de que cometí un error tonto en la trama. Aquí hay otra prueba con datos univariados, el gráfico parece estar bien:
set.seed(1024)
x = rnorm(1000, 10)
y = -1*x + rnorm(1000, 0.001) + 3*sin(x)
train = matrix(x, ncol = 1)
bst = xgboost(data = train, label = y, max_depth = 2,
eta = 0.1, nthread = 2, nrounds = 100,
monotone_constraints = '(-1)')
pred = predict(bst, train)
ind = order(train[,1])
pred.ord = pred[ind]
plot(train[,1], y, main = 'with constraint', pch=20)
lines(train[ind,1], pred.ord, col=2, lwd = 5)
bst = xgboost(data = train, label = y, max_depth = 2,
eta = 0.1, nthread = 2, nrounds = 100)
pred = predict(bst, train)
ind = order(train[,1])
pred.ord = pred[ind]
plot(train[,1], y, main = 'without constraint', pch=20)
lines(train[ind,1], pred.ord, col=2, lwd = 5)
@ hetong007 Entonces, el objetivo en la interfaz R es permitir al usuario pasar la matriz R además de las cadenas
monotone_constraints=c(1,-1)
Háganos saber cuando sea RP el tutorial
@ hetong007 También eres más que bienvenido para hacer una versión de r-blogger
@tqchen Lo siento chicos, he estado en un viaje de trabajo durante la semana.
Envié un par de solicitudes de extracción con un tutorial de restricción monótona. Por favor déjeme saber lo que piensa, estoy contento con cualquier crítica o crítica.
Con suerte, es apropiado preguntar esto aquí: ¿funcionará ahora si actualizamos usando el git clone --recursive https://github.com/dmlc/xgboost
habitual?
Pregunto cuando vi el nuevo tutorial, pero nada nuevo sobre un cambio en el código en sí. ¡Gracias a todos!
sí, la nueva función se fusiona antes de fusionar el tutorial
Hola,
No estoy seguro de que hayas implementado con éxito la montonicidad global, por lo que he visto en tu código, corresponde más a una monotonicidad local.
Aquí hay un ejemplo simple que rompe la monotonicidad:
'
gl <- data.frame (y = c (2, rep (6,100), 1, rep (11,100)),
x1 = c (rep (1,101), rep (2,101)), x2 = c (1, rep (2,100), 1, rep (2,100)))
biblioteca (xgboost)
set.seed (0)
XGB <- xgboost (data = data.matrix (df [, - 1]), label = df [, 1],
objetivo = " reg: lineal ",
bag.fraction = 1, nround = 100, monotone_constraints = c (1,0),
eta = 0,1)
sans_corr <- data.frame (x1 = c (1,2,1,2), x2 = c (1,1,2,2))
sans_corr $ prediction <- predecir (XGB, data.matrix (sans_corr))
'
Espero que mi comprensión de su código y mi ejemplo no sea falso
Actualmente, esta función no está en la API de Sklearn. ¿Puede usted o alguien ayudar a agregarlo? ¡Gracias!
¿Es posible imponer una monotonicidad general a una variable, sin especificar si debería ser creciente o decreciente?
@davidADSP puede hacer una verificación de correlación de
Esta característica parece no ser válida cuando 'tree_method': 'hist'. @tqchen ¿ alguna ayuda? Gracias a todos.
¿Cómo funciona la restricción para objetivos multiclase como mlogloss? ¿Se admite la restricción de monotonicidad para la pérdida multiclase? Si es así, ¿cómo se hace cumplir? (En cuanto a cada clase hay un árbol)
¿Existe algún documento técnico sobre el algoritmo de monoticidad aplicado en XGBOOST? ¿Es global o local? Los medios locales específicos para ciertos nodos, pero los nodos en otras partes del árbol pueden crear una violación de la monotonicidad general. También puede alguien ayudarme a comprender la línea L412-417 . Por qué "w" está acotado: superior e inferior. Cómo esto ayuda a mantener la monotonicidad. Línea 457 - ¿Por qué se usa "mid"?
Comentario más útil
Actualmente, esta función no está en la API de Sklearn. ¿Puede usted o alguien ayudar a agregarlo? ¡Gracias!