Reshape und Group Array

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Lizzy
User
Beiträge: 48
Registriert: Mittwoch 30. Januar 2019, 15:22

Hallo,

ich habe einen array a1 mit Shape (153, ), der für jede Instanz den Wert 1, 2 oder 3 enthält (Ergebnis einer Klassifizierung in 3 Gruppen).

Dieser array a1 soll von folgender shape sein: n_classes * n_samples. Kann ich ihn irgendwie "re-shapen"?

Außerdem soll a1 gruppiert werden, und zwar erst nach class_id und dann nach row_id. Gibt es hier eine Möglichkeit?
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn der Shape so sein soll, warum ist der dann nicht gleich von vornherein so? Woher kommt `a1`?

Die zweite Frage ist ohne den Kontext zu kennen, völlig unverständlich.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Kopier die komplette Aufgabenstellung hier rein, inklusive Code etc pp und wir schauen mal, wie wir dabei helfen können.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Lizzy
User
Beiträge: 48
Registriert: Mittwoch 30. Januar 2019, 15:22

Das Ziel ist es, eine custom loss function im Rahmen einer gradient boosted Klassifizierung zu formulieren. Diese Funktion hat als Input einen Array a1 bzw. hier y_pred, der die folgenden 2 Voraussetzungen erfüllen muss:

- y_pred : array-like of shape = [n_samples * n_classes]: The predicted values.
- For multi-class task, the y_pred is group by class_id first, then group by row_id.

Mein y_pred hat aber eben die Shape (153, ), weil das einfach der Ergebnis Vektor eines normalen Decision Trees ist.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Wieviele n_samples und n_classes hast du denn?
Wenn es 51 Samples und 3 Klassen wären, ergäbe 51*3 ein Array mit Shape (153,)
Zu 2) Könnte es sein, dass damit gemeint ist, das in deinem y_pred Array die ersten 51 Werte für Klasse 1, die zweiten 51 Werte für Klasse 2 und die letzten 51 für Klasse 3 stehen?
Wenn du ein Numpy-Array mit Shape (153,) hast, kannst du das mit a1 = a1.reshape(row, column) in ein 2D Array wandeln.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Lizzy
User
Beiträge: 48
Registriert: Mittwoch 30. Januar 2019, 15:22

Ich habe 153 samples...daher sieht y_pred einfach folgendermaßen aus:

array([1, 2, 1, 2, 1, 1, 2, 2, 3, 2, 2, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 2,
3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 1,
3, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 1, 2, 3, 2, 2, 2, 2, 1, 1, 3,
1, 1, 3, 1, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2,
1, 2, 2, 2, 1, 2, 1, 2, 2, 3, 2, 2, 1, 2, 2, 2, 3, 1, 2, 2, 1, 1,
2, 1, 3, 2, 2, 3, 2, 2, 2, 2, 1, 3, 1, 2, 3, 3, 2, 1, 1, 2, 2, 3,
2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 2, 1, 2, 3, 2, 2, 2, 2])

Wenn ich versuche diesen in einen 153x3 array umzuwandeln, kommt eine Fehlermeldung.
Die einzige Möglichkeit die ich mir vorstellen könnte wäre für jede der 153 Instanzen 3 Einträge zu haben, 0 wenn sie der Klasse nicht zugeteilt sind und 1 wenn sie zugeteilt sind. Also ca. so:
1: 1 0 0
2: 0 1 0
3: 1 0 0
usw. Wäre das möglich?
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Wie versuchst du das und wie ist die Fehlermeldung?
Lizzy
User
Beiträge: 48
Registriert: Mittwoch 30. Januar 2019, 15:22

y_pred.reshape(153,3)

--> cannot reshape array of size 153 into shape (153,3)
__deets__
User
Beiträge: 14540
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist doch das hier, oder?

https://lightgbm.readthedocs.io/en/late ... learn.html

So wie ich das lese ist das entweder ein eindimensionales Array mit einer Klasse pro Sample. Oder es ist ein eindimensionales Array mit (anzahl der Klassen * Anzahl der samples) vielen Einträgen. Und dann kommen erstmal alle Einträge für klasse 1, dann alle für 2, etc. Ich VERMUTE (genaueres steht da nicht), dass dann Zugehörigkeit zu der gegebenen Klasse für Sample x halt eine 1 nach sich zieht. Oder eine 0 wenn nicht.

Ich persönlich finde deine Idee einer m*n Matrix intuitiver, aber das scheint nicht gefordert.

So oder so frage ich mich, warum das nicht klappt, denn so,wie ich das sehe hast du doch einfach 153 samples mit jeweils nur EINER Klasse. Das ist doch richtig. Multi-Class heißt doch “ein sample gehört zu mehr als einer Klasse “. Das hast du doch gar nicht vor,eigen?
__deets__
User
Beiträge: 14540
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nachtrag: so zu reshapen geht nicht. Reshaping arrangiert besetehende Einträge neu. Da kommen keine zu. Oder weg. Du willst die aber plötzlich verdreifachen. Das geht nicht. Aber wie gesagt: eigentlich stimmt dein Array. Warum glaubst du das geht nicht?
Lizzy
User
Beiträge: 48
Registriert: Mittwoch 30. Januar 2019, 15:22

@_deets_, ja genau das versuche ich zu implementieren!

Achso, ich hatte verstanden dass multiclass heißt, dass ich mehr als eine binäre Klassifizierung habe...das erklärt einiges :D Aber ja, dann müsste ich ja eigentlich die richtigen Shapes für meine Funktions-Parameter haben. Ich habe die beiden Funktionen folgendermaßen implementiert:

Code: Alles auswählen

def custom_asymmetric_objective(y_true, y_pred):
    margin = (y_true-y_pred).astype("float")
    grad = np.gradient(margin)
    hess = np.gradient(grad)
    return grad, hess


def custom_asymmetric_valid(y_true, y_pred):
    margin = (y_true - y_pred).astype("float")
    loss = margin*10
    return "custom_asymmetric_eval", np.mean(loss), False
    
    

Für die erste Funktion funktioniert alles:

Code: Alles auswählen

gbm = lightgbm.LGBMClassifier(random_state=33) 
gbm.set_params(**{'objective': custom_asymmetric_objective})
Sobald ich aber die fit Methode mit der 2. Funktion aufrufe:

Code: Alles auswählen

gbm.fit(
    X_train,
    y_train,
    eval_set=[(X_test, y_test)],
    eval_metric=custom_asymmetric_valid,
    verbose=False,
)
kommt die Fehlermeldung: operands could not be broadcast together with shapes (355,) (1065,)

Das versteh ich einfach nicht, die Voraussetzungen für die custom evaluation function sind meiner Ansicht nach nun erfüllt
__deets__
User
Beiträge: 14540
Registriert: Mittwoch 14. Oktober 2015, 14:29

Kannst du bitte den vollen Stacktrace Posten? So wird nicht klar wo genau die Fehlermeldung Auftritt.
Lizzy
User
Beiträge: 48
Registriert: Mittwoch 30. Januar 2019, 15:22

Code: Alles auswählen


--------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-43-d924b6c238ee> in <module>
     10     eval_set=[(X_test, y_test)],
     11     eval_metric=custom_asymmetric_valid,
---> 12     verbose=False,
     13 )

/anaconda3/lib/python3.6/site-packages/lightgbm/sklearn.py in fit(self, X, y, sample_weight, init_score, eval_set, eval_names, eval_sample_weight, eval_class_weight, eval_init_score, eval_metric, early_stopping_rounds, verbose, feature_name, categorical_feature, callbacks)
    698                                         verbose=verbose, feature_name=feature_name,
    699                                         categorical_feature=categorical_feature,
--> 700                                         callbacks=callbacks)
    701         return self
    702 

/anaconda3/lib/python3.6/site-packages/lightgbm/sklearn.py in fit(self, X, y, sample_weight, init_score, group, eval_set, eval_names, eval_sample_weight, eval_class_weight, eval_init_score, eval_group, eval_metric, early_stopping_rounds, verbose, feature_name, categorical_feature, callbacks)
    500                               verbose_eval=verbose, feature_name=feature_name,
    501                               categorical_feature=categorical_feature,
--> 502                               callbacks=callbacks)
    503 
    504         if evals_result:

/anaconda3/lib/python3.6/site-packages/lightgbm/engine.py in train(params, train_set, num_boost_round, valid_sets, valid_names, fobj, feval, init_model, feature_name, categorical_feature, early_stopping_rounds, evals_result, verbose_eval, learning_rates, keep_training_booster, callbacks)
    211                                     evaluation_result_list=None))
    212 
--> 213         booster.update(fobj=fobj)
    214 
    215         evaluation_result_list = []

/anaconda3/lib/python3.6/site-packages/lightgbm/basic.py in update(self, train_set, fobj)
   1759             if not self.__set_objective_to_none:
   1760                 self.reset_parameter({"objective": "none"}).__set_objective_to_none = True
-> 1761             grad, hess = fobj(self.__inner_predict(0), self.train_set)
   1762             return self.__boost(grad, hess)
   1763 

/anaconda3/lib/python3.6/site-packages/lightgbm/sklearn.py in inner(preds, dataset)
     50         argc = argc_(func)
     51         if argc == 2:
---> 52             grad, hess = func(labels, preds)
     53         elif argc == 3:
     54             grad, hess = func(labels, preds, dataset.get_group())

<ipython-input-41-852cbed7c251> in custom_asymmetric_objective(y_true, y_pred)
      1 def custom_asymmetric_objective(y_true, y_pred):
----> 2     margin = (y_true-y_pred).astype("float")
      3     grad = np.gradient(margin)
      4     hess = np.gradient(grad)
      5     return grad, hess

ValueError: operands could not be broadcast together with shapes (355,) (1065,)

ArtooDetoo
User
Beiträge: 60
Registriert: Dienstag 4. Dezember 2018, 16:57

Kann es sein, dass du ein One-Hot-Encoding brauchst?
__deets__
User
Beiträge: 14540
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na wenn du zwei Arrays voneinander subtrahieren willst, muessen die schon die gleiche Gestalt haben. Warum sind denn da ploetzlich 355 und 1065 da?

@ArtooDeetoo: nicht fuer den 1-Klasse-pro-Sample-Fall. Und selbst im mehrere-Klassen-pro-Sample-Fall ist das encoding nicht in Form eine Matrix von Feature-Vektor * Samples, sondern dieses komisch gruppierte wie in der Doku beschrieben.
Lizzy
User
Beiträge: 48
Registriert: Mittwoch 30. Januar 2019, 15:22

y_pred und y_true haben die gleiche Shape (153,)...Woher die 255 und 1065 kommen versteh ich leider nicht
Benutzeravatar
__blackjack__
User
Beiträge: 13109
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Lizzy: Wenn die die gleiche Form hätten würde die Ausnahme nicht kommen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14540
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der Fehler ist da ganz klar anderer Meinung - die Zeile ist margin = (y_true-y_pred).astype("float"), und der Shape-Check schlaegt eben fehl. Woher diese Daten nun kommen kannst nur du wissen, wir haben ja weder das ganze Programm noch deine Daten. Aber deine Annahme, dass die die gleiche Form haben stimmt nicht. Soviel kann man sagen.
Lizzy
User
Beiträge: 48
Registriert: Mittwoch 30. Januar 2019, 15:22

Ich habe sowohl y_pred.shape als auch y_true.shape getestet...es kommt bei beiden (153,) raus.

Kann es nicht an den übergebenen Parametern an die fit Funktion liegen? (X_train, y_train oder eval_set=[(X_test, y_test)] )?

Wobei die eigentlich auch alle die Voraussetzung erfüllen:

X_train: (array-like or sparse matrix of shape = [n_samples, n_features]) – Input feature matrix.
y_train: (array-like of shape = [n_samples]) – The target values (class labels in classification, real numbers in regression).
Zuletzt geändert von Lizzy am Montag 25. Februar 2019, 13:38, insgesamt 1-mal geändert.
Benutzeravatar
__blackjack__
User
Beiträge: 13109
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Lizzy: Das kann ganz einfach nicht sein, denn wenn bei beiden (153,) heraus käme, würdest Du die gezeigte Ausnahme nicht bekommen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten