Closed Tulmot closed 6 years ago
El caso degenerado del que se habla en la issue:
In [95]: from sklearn import tree
...: X = [[0, 0],[0,1]]
...: Y = [[0,1],[1,1]]
...: clf = tree.DecisionTreeClassifier()
...: clf = clf.fit(X, Y)
...: clf
Out[95]:
DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
max_features=None, max_leaf_nodes=None,
min_impurity_split=1e-07, min_samples_leaf=1,
min_samples_split=2, min_weight_fraction_leaf=0.0,
presort=False, random_state=None, splitter='best')
In [96]: clf.predict([[0,0]])
Out[96]: array([[ 0., 1.]])
In [97]: clf.predict_proba([[0,0]])
Out[97]: [array([[ 1., 0.]]), array([[ 1.]])]
El problema viene de que está considerando que la segunda salida solo tiene un valor.
No considera problemas multilabel, sino problemas con varias clases de salida, cada clase podría tener un número diferente de valores. Por ejemplo, podríamos tener que los valores de una de las salidas fueran [4,7,10] y entonces nos devuelve un array con 3 valores.
He solucionado el problema como dijimos utilizando el predict, subo el código y si podeis mirarlo a ver si os parece correcto como lo he hecho, y ya después cierro la tarea. El código esta en base_random_oracles
Ahora entiendo cómo está funcionando @jjrodriguez, yo lo que pensaba era que el problema venía por pocas clases pero veo que viene por lo que comentas. Gracias.
@Tulmot no veo que en predict_proba se esté llamando al predict_proba de los clasificadores base. Creo que la idea era llamar al predict solo en los casos en los que el predict_proba no devolvía lo que esperamos.
Por otro lado no veo que en predict_proba se inicialice _classifiers_prediction. Si llamas a predict_proba despues de llamar a predict, estará inicializado, pero se puede llamar a predict_proba sin haber llamado a predict antes.
Tengo el siguiente código, el problema es que en una de las iteraciones el shape es (1,2) pero uno de los arrays tiene un elemento, adjunto foto para que se entienda mejor: Lo que pone de (1,2) es el shape. Entonces en los oráculos que tienen shape (1,1) me los hace bien pero en este caso que he dicho no se si tendre que poner otra condición o como.
def predict_proba(self, X):
"""The predicted class probabilities of an input sample is computed as
the mean predicted class probabilities of the base estimators in the
ensemble.
Parameters
----------
X : It's a matrix of form = [n_instances, n_features]
The training input samples. Sparse matrices are accepted only if
they are supported by the base estimator.
Returns
-------
p : It's a matrix of form = [n_samples, n_classes]
The class probabilities of the input samples. The order of the
classes corresponds to that in the attribute `classes_`.
"""
def predict_prob(num):
"""Según el numero devolvemos una probabilidad o otra """
if num == 1:
return [[0., 1.]]
else:
return [[1., 0.]]
def list_predict_proba(inst_oracles):
"""Predecimos la probabilidad de cada una de las instancias con el
oraculo correspondiente mas cercano"""
oracle_near = inst_oracles[n_features:]
instance = inst_oracles[:n_features]
oracle_near = list(oracle_near)
index_classifier = oracle_near.index(1)
prediction_proba=self._classifiers_train[index_classifier].predict_proba(
[instance])
print(prediction_proba[0].shape)
if(prediction_proba[0].shape==(1,1)):
call_predict=self._classifiers_train[index_classifier].predict(
[instance])
print(list(np.asarray(list(map(
predict_prob, call_predict[0])))))
return list(np.asarray(list(map(
predict_prob, call_predict[0]))))
else:
print(self._classifiers_train[index_classifier].predict_proba(
[instance]))
return self._classifiers_train[index_classifier].predict_proba(
[instance])
n_features = X.shape[1]
m_oracle = np.concatenate((X, self._nearest_oracle(X)), axis=1)
self._classifiers_prediction_proba = list(map(
list_predict_proba, m_oracle))
self._classifiers_prediction_proba=np.concatenate((
self._classifiers_prediction_proba), axis=1)
self._classifiers_prediction_proba = np.asarray(
self._classifiers_prediction_proba)
convert_array=lambda prob : np.asarray(prob)
self._classifiers_prediction_proba=list(map(convert_array,self._classifiers_prediction_proba))
return self._classifiers_prediction_proba
En vez de comprobar el shape, puedes utilizar esta instrucción que te da el elemento más pequeño de la lista que le pasas
min(lista, key=len)
Te entedido hacerlo así:
if(min(prediction_proba[0], key=len).shape[0]==1):
call_predict=self._classifiers_train[index_classifier].predict(
[instance])
print(list(np.asarray(list(map(
predict_prob, call_predict[0])))))
return list(np.asarray(list(map(
predict_prob, call_predict[0]))))
else:
print(self._classifiers_train[index_classifier].predict_proba(
[instance]))
return self._classifiers_train[index_classifier].predict_proba(
[instance])
De todas formas sigo en las mismas
Nose porque pero el elemento que tiene 1 no le detecta porque me dice que el tamaño es 2
Haz commit del código completo para que podamos ver qué esta haciendo tu clase al completo, sino solo por fragmentos es muy difícil. ¿El if está funcionando bien?
El if nose porque en la iteración 2 me si que tiene un array con tamaño 1 y me lo devuelve bien, pero en la iteración 4 que vuelve a salir un array con tamaño uno, me dice que el más pequeño tiene longitud dos por ello no entra en el if y va al else y falla.
La diferencia es que en la iteración 2 el array de tamaño 1 sale en la posición 0: Mientras que en la iteración 4 sale en la posición 2 y 4:
Voy a darle una vuelta a ver si veo el fallo de todas formas pongo el código por si ves tu antes el fallo:
def list_predict_proba(inst_oracles):
"""Predecimos la probabilidad de cada una de las instancias con el
oraculo correspondiente mas cercano"""
oracle_near = inst_oracles[n_features:]
instance = inst_oracles[:n_features]
oracle_near = list(oracle_near)
index_classifier = oracle_near.index(1)
prediction_proba=self._classifiers_train[index_classifier].predict_proba(
[instance])
print(min(prediction_proba[0], key=len).shape[0])
if(min(prediction_proba[0], key=len).shape[0]==1):
call_predict=self._classifiers_train[index_classifier].predict(
[instance])
print(list(np.asarray(list(map(
predict_prob, call_predict[0])))))
return list(np.asarray(list(map(
predict_prob, call_predict[0]))))
else:
print(prediction_proba)
return prediction_proba
n_features = X.shape[1]
m_oracle = np.concatenate((X, self._nearest_oracle(X)), axis=1)
self._classifiers_prediction_proba = list(map(
list_predict_proba, m_oracle))
#print(self._classifiers_prediction_proba)
self._classifiers_prediction_proba=np.concatenate((
self._classifiers_prediction_proba), axis=1)
self._classifiers_prediction_proba = np.asarray(
self._classifiers_prediction_proba)
convert_array=lambda prob : np.asarray(prob)
self._classifiers_prediction_proba=list(map(convert_array,self._classifiers_prediction_proba))
#print(self._classifiers_prediction_proba)
return self._classifiers_prediction_proba
Estás cogiendo solamente la primera posición...
if(min(prediction_proba[0], key=len).shape[0]==1):
Deberías coger:
if(min(prediction_proba[0], key=len)==1):
El problema es que si lo pongo asi lo que me devuelve
(min(prediction_proba[0], key=len)
es un array es decir por ejemplo [0. , 1.] por eso hacia el .shape para obtener el tamaño de ese array...
y de todas formas tampoco lo hace bien porque me devuelve:
he comprobado que eso siempre me devuelve la primera posición, no me devuelve el más pequeño de todos
De acuerdo, había visto mal el paréntesis. Yo probé ayer la función min y me funcionaba con una lista de arrays, haz la prueba desde jupyter o ipython para ver cuál puede ser el problema.
con esto funciona:
prediction_proba=[[ 1., 0.], [ 0., 1.], [ 1.], [ 1., 0.], [ 1.]]
print(min(prediction_proba, key=len))
el problema es que yo tengo:
prediction_proba=[[[ 1., 0.]], [[ 0., 1.]], [[ 1.]], [[ 1., 0.]], [[ 1.]]]
print(min(prediction_proba, key=len))
voy a probar en jupyter a ver si consigo de alguna manera obtenerlo.
Si no se me ocurre recorrer la lista y como al recorrer la lista tendria algo como [[ 1., 0.]] y voy quedandome con la lista del tamaño mas pequeño que al final será [[ 1.]]
Quizás con print(min(prediction_proba, key=(lambda x:len(x[0]))))
¡Eso mismo estaba probando yo ahora mismo Juanjo! Y a mi me funciona correctamente.
Me funciona pero porque eso siempre me devuelve longitud 1, entonces siempre entra al if
Código:
def predict_proba(self, X):
"""The predicted class probabilities of an input sample is computed as
the mean predicted class probabilities of the base estimators in the
ensemble.
Parameters
----------
X : It's a matrix of form = [n_instances, n_features]
The training input samples. Sparse matrices are accepted only if
they are supported by the base estimator.
Returns
-------
p : It's a matrix of form = [n_samples, n_classes]
The class probabilities of the input samples. The order of the
classes corresponds to that in the attribute `classes_`.
"""
def predict_prob(num):
"""Según el numero devolvemos una probabilidad o otra """
if num == 1:
return [[0., 1.]]
else:
return [[1., 0.]]
def list_predict_proba(inst_oracles):
"""Predecimos la probabilidad de cada una de las instancias con el
oraculo correspondiente mas cercano"""
oracle_near = inst_oracles[n_features:]
instance = inst_oracles[:n_features]
oracle_near = list(oracle_near)
index_classifier = oracle_near.index(1)
prediction_proba=self._classifiers_train[index_classifier].predict_proba(
[instance])
print((min(prediction_proba, key=(lambda x:len(x[0])))).shape[0])
print(prediction_proba)
if((min(prediction_proba, key=(lambda x:len(x[0])))).shape[0]):
call_predict=self._classifiers_train[index_classifier].predict(
[instance])
return list(np.asarray(list(map(
predict_prob, call_predict[0]))))
else:
return prediction_proba
n_features = X.shape[1]
m_oracle = np.concatenate((X, self._nearest_oracle(X)), axis=1)
self._classifiers_prediction_proba = list(map(
list_predict_proba, m_oracle))
#print(self._classifiers_prediction_proba)
self._classifiers_prediction_proba=np.concatenate((
self._classifiers_prediction_proba), axis=1)
self._classifiers_prediction_proba = np.asarray(
self._classifiers_prediction_proba)
convert_array=lambda prob : np.asarray(prob)
self._classifiers_prediction_proba=list(map(convert_array,self._classifiers_prediction_proba))
#print(self._classifiers_prediction_proba)
return self._classifiers_prediction_proba
Salida: 1 [array([[ 1.]]), array([[ 1.]]), array([[ 1., 0.]]), array([[ 1., 0.]]), array([[ 1., 0.]])] 1 [array([[ 1., 0.]]), array([[ 0., 1.]]), array([[ 1., 0.]]), array([[ 1., 0.]]), array([[ 0., 1.]])]
Son dos iteraciones diferentes la primera deberia devolver 1 y la segunda 2 pero como veis el 1 que aparece encima de los arrays es el tamaño siempre devuelve 1
print(array([[ 1., 0.]]).shape[0])
1
print(array([[ 1., 0.]]).shape)
(1, 2)
¿Es shape[0]
lo que quieres?
vale..fallo mio, ya funciona correctamente.
Cierro y ahora subo el código.
El comentario para el que no he visto respuesta:
_ @Tulmot no veo que en predict_proba se esté llamando al predict_proba de los clasificadores base. Creo que la idea era llamar al predict solo en los casos en los que el predict_proba no devolvía lo que esperamos.
Por otro lado no veo que en predict_proba se inicialice _classifiers_prediction. Si llamas a predict_proba despues de llamar a predict, estará inicializado, pero se puede llamar a predictproba sin haber llamado a predict antes.
pero como lo tengo hecho ahora si que puedo llamar al predict proba antes de llamar al predict:
if((min(prediction_proba, key=(lambda x: len(x[0])))).shape[1]):
call_predict = self._classifiers_train[
index_classifier].predict([instance])
return list(np.asarray(list(map(
predict_prob, call_predict[0]))))
else:
return prediction_proba
Porque en el caso que me ocurrar el error de que una de las longitudes es 1, dentro de ese if llamo al predict, entonces entiendo que aunque no lo inicialice nunca va a fallar porque da igual que no haya ejecutado anteriormente predict.
OK
Encontramos un error cuando realizamos iteraciones sobre el método predict_proba de la clase Random Oracles, ya que como lo probamos con un árbol cuando en una de las iteraciones si tiene el mismo labelset devuelve una predicción con tamaño uno, por lo tanto para corregir esto lo que hacemos es calcular las probabilidades con el método predict, ya que este si funciona correctamente.