[PYTHON] SIGNATE [1st _Beginner Limited Competition] Participation au ciblage des clients de la banque

Participation au [1st_Beginner Limited Competition] Bank Customer Targeting de SIGNATE, un site de concours d'analyse de la science des données.

Depuis que j'ai été promu avec succès à Intermidiate, j'ai écrit un article basé sur mes notes et mes réflexions, dans l'espoir que plus de personnes puissent facilement participer au concours.

Qu'est-ce que SIGNATE

Un concours de science des données organisé par une société japonaise, SIGNATE.

Le ministère de l'Économie, du Commerce et de l'Industrie, My Navi, NTT, Sansan, etc. participent également

Vous pouvez le considérer comme la version japonaise de kaggle.

Le forum n'étant pas actif, il semble que les participants n'aient pas beaucoup tendance à échanger des opinions et des informations «pour le moment». Le forum bougeait un peu à la fin de ce concours de débutant, donc ça peut changer à partir de maintenant.

(À propos, Vidéo officielle ), L'intonation correcte semble être "Sig (↑) Ney (→) To (↓)" Est-ce la même chose que la tangente de la fonction triangulaire?)

Qu'est-ce que la compétition limitée Débutant?

Compétition réservée aux débutants prévue tous les mois, c'est le premier événement mémorable Si vous dépassez un certain score (AUC est de 0,85 cette fois) par une évaluation absolue au lieu de la concurrence, vous pouvez être promu à un intermédiaire de grade supérieur.

Veuillez consulter le Site officiel pour plus de détails.

Comment promouvoir pour le moment

Exploité par Benchmark Score Script ) Est publié

Si vous prédisez cela 100 fois avec un nombre aléatoire approprié pour l'instruction, puis prenez la moyenne, l'AUC sera de 0,854, vous pouvez donc la promouvoir.


output_df = pd.DataFrame()
for i in range(100):
    #Diviser les données de test à partir des données d'entraînement
    X_train , X_valid , y_train , y_valid = train_test_split(X_train_origin,y_train_origin,test_size = 0.3 , random_state = i , stratify=y_train_origin)
    #Le modèle utilisé est LGB (sans réglage des paramètres)
    lgb_train = lgb.Dataset(X_train,y_train,categorical_feature = categorical_features)
    lgb_eval = lgb.Dataset(X_valid , y_valid , reference = lgb_train , categorical_feature = categorical_features)
    params = {
        "objective":"binary"
    }

    model = lgb.train(
        params,lgb_train,
        valid_sets=[lgb_train,lgb_eval],
        verbose_eval = 10,
        num_boost_round = 1000,
        early_stopping_rounds=10
    )
    
    y_pred = model.predict(X_test_origin,num_iteration=model.best_iteration)
    output_df[i] = y_pred

submit_df["1"] = output_df.mean(axis = 1)

submit_df.to_csv('submit.csv',index=False,header=None)

__ Il s'avère que la stratégie de "calcul de la moyenne de plusieurs résultats de prédiction" est très puissante __

Ce que j'ai fait pour dépasser 0,860

Ce n'est pas intéressant, j'ai donc décidé de faire de mon mieux pour dépasser AUC 0,860.

Essais et erreurs grossièrement répétés avec la procédure suivante

Tabulation de base

Calculer des statistiques telles que la valeur moyenne et la valeur médiane en les regroupant par variable objectif Visualisation avec des histogrammes et des graphiques à barres J'ai également calculé le coefficient de corrélation, etc.

import pandas as pd
import matplotlib.pyplot as plt
pd.set_option('display.max_rows' ,500)
pd.set_option('display.max_columns', 100)

train_df = pd.read_csv("../../data/train.csv")

#Je vais combiner le mois avec le jour, alors je l'ai changé en nombre
#Décembre n'existe pas dans ces données
month_dict = {"jan":1,"feb":2,"mar":3,"apr":4,"may":5,"jun":6,"jul":7,"aug":8,"sep":9,"oct":10,"nov":11,"dec":12}
month_int = [train_df["month"][i] for i in range(len(train_df))]
train_df["month"] = month_int

#âge
#age
#Je m'inquiétais de savoir comment gérer plus de 60 ans, alors je l'ai roulé
#Converti à un peu plus de 60 ans, chaque adolescent jusqu'à 59 ans
age_list = list(train_df["age"])

new_age_list = []

for i in range(len(age_list)):
    if age_list[i] == 60:
        new_age_list.append(60)
    elif age_list[i] > 60:
        new_age_list.append(70)
    else:
        new_age_list.append(int(age_list[i]/10)*10)
train_df["age_round"] = new_age_list

train_df.describe()


numeric_col_list = ["age","balance","duration","campaign","pdays","previous"]

categorical_col_list  = [categorical_feature for categorical_feature in train_df.columns if categorical_feature not in numeric_col_list]
categorical_col_list.remove("id")

#Pour le numérique, regroupez par variable objectif pour calculer les statistiques
for target_col in numeric_col_list:
    print("\ntarget_col:",target_col)
    display(train_df.groupby("y")[target_col].describe())

#Pour catégoriel, regrouper par variable objectif et nombre
for target_col in categorical_col_list:
    print("\ntarget_col:",target_col)
    display(train_df.groupby(["y",target_col])[target_col].count())


#Visualisez et confirmez les valeurs moyennes et médianes
#Valeur moyenne et valeur médiane par 01 sur y
y0_df = train_df.query('y == 0')
y1_df = train_df.query('y == 1')

for target_col in numeric_col_list:
    
    #0,Valeur moyenne par 1
    y0_target_col_mean = y0_df[target_col].mean()
    y1_target_col_mean = y1_df[target_col].mean()

    #0,Médiane par 1
    y0_target_col_median = y0_df[target_col].median()
    y1_target_col_median = y1_df[target_col].median()

    #Réglage de l'axe vertical
    #1 du maximum des valeurs moyenne et médiane.1x est l'axe vertical
    #Le grossissement peut être n'importe quoi tant qu'il est facile à voir
    graph_y_length = (1.1*max(y0_target_col_mean,y1_target_col_mean,y0_target_col_median,y1_target_col_median))

    plt.title(target_col + ": mean")
    plt.ylabel(target_col)
    plt.ylim([0,graph_y_length],)
    plt.bar(["y0_mean","y1_mean"],[y0_target_col_mean,y1_target_col_mean])
    #plt.annotate(y0_target_col_mean,y0_target_col_mean)
    plt.show()

    plt.title(target_col + ": median")
    plt.ylabel(target_col)
    plt.ylim([0,graph_y_length],)
    plt.bar(["y0_median","y1_median"],[y0_target_col_median,y1_target_col_median],color = "green")
    plt.show()

#Saisissez l'image entière même avec un histogramme
for target_col in numeric_col_list:
    #Réglage de l'axe
    graph_x_length = 1.1*max(train_df[target_col])
    graph_y_length = len(y0_df)
    
    print("y0",target_col)
    plt.xlim([0,graph_x_length],)
    plt.ylim([0,graph_y_length],)
    plt.hist(y0_df[target_col],bins = 20)
    plt.show()
    
    graph_y_length = graph_y_length/10
    print("y1",target_col)
    plt.xlim([0,graph_x_length],)
    plt.ylim([0,graph_y_length],)
    plt.hist(y1_df[target_col],bins = 20)
    plt.show()
    
    
#Calcul du coefficient de corrélation
train_df.corr()

#Ne prenez que le coefficient de corrélation de la variable objective
train_df.corr()["y"]

J'ai également essayé de dessiner un graphique de ligne de pliage dans l'ordre chronologique, mais je vais l'omettre. Avec ce genre de sentiment, je me demandais quelle quantité de caractéristiques contribuerait de manière significative à la variable objective et si je pouvais créer une quantité de caractéristiques.

Confirmation des données brutes

J'ai confirmé qu'il y a des dates qui n'existent pas, comme environ 90 ans ou le 30 février. J'ai envisagé de le traiter ou de le supprimer, mais je l'ai utilisé tel quel

Ingénierie de la quantité de fonctionnalités

・ Les jours et le solde sont supprimés ・ Créez un drapeau de fin de mois -Créer une colonne de date qui combine le mois et le jour

De la tabulation de base et de la confirmation des données brutes Les quantités d'entités susceptibles d'avoir une forte influence sur la variable d'objectif sont traitées pour créer de nouvelles quantités d'entités. Je l'ai supprimé si je décidais que cela ne m'affecterait pas J'ai également évoqué l'importance des fonctionnalités décrites ci-dessous.

Tuning lightgbm avec optuna → Prédire 100 fois

optuna est une bibliothèque qui règle les hyperparamètres à l'aide de l'optimisation bayésienne Score plus élevé que la recherche de grille et la recherche aléatoire

J'ai évoqué les deux articles suivants

Introduction à optuna

Optimisation automatique des hyperparamètres par l'extension Optuna LightGBM Tuner

Le but est d'utiliser optuna pour lightgbm J'ai eu une erreur avec optuna 2.0 qui était déjà sur mon ordinateur, donc je l'ai exécuté avec optuna 1.3

import pandas as pd
import optuna
import functools
import warnings
warnings.simplefilter('ignore')


from sklearn.model_selection import train_test_split

#Ce mec est vraiment capable
import optuna.integration.lightgbm as lgb

from sklearn import preprocessing
from sklearn.model_selection import cross_val_score

%matplotlib 


#Lire les données
train_df = pd.read_csv("../../data/train.csv")
test_df = pd.read_csv("../../data/test.csv")
submit_df = pd.read_csv("../../data/submit_sample.csv",header = None)


#Remplacez les variables objectives fictives afin que les données d'entraînement et les données de test puissent être comprises
test_df["y"] = -999

#Combinez les données d'entraînement et les données de test
all_df = pd.concat([train_df,test_df])
del train_df , test_df

all_df.reset_index(inplace=True)


#Drapeau de fin de mois
month_list = list(all_df["month"])
day_list = list(all_df["day"])

end_of_month_flag = []
for i in range(len(all_df)):
    if day_list[i] in [30,31]:
        end_of_month_flag.append(1)
    elif day_list[i] == 29 and month_list[i] in ["feb","apr","jun","sep","nov"]:
        end_of_month_flag.append(1)
    elif day_list[i] == 28 and month_list[i] == "feb":
        end_of_month_flag.append(1)
    else:
        end_of_month_flag.append(0)
        
all_df["end_of_month_flag"] = end_of_month_flag


#Mois(colonne mois)À un numéro
month_dict = {"jan":1,"feb":2,"mar":3,"apr":4,"may":5,"jun":6,"jul":7,"aug":8,"sep":9,"oct":10,"nov":11,"dec":12}
month_int = [month_dict[all_df["month"][i]] for i in range(len(all_df))]
all_df["month"] = month_int

#month_création de colonne jour
#Je pense qu'il est normal de traiter l'arbre de décision comme int, car il n'a besoin que de connaître la relation de taille.
month_day = []
month_day = all_df["month"]*100 + all_df["day"]
all_df["month_day"] = month_day

#Supprimer les colonnes inutiles
del all_df["index"]
del all_df["id"]
del all_df["pdays"]
del all_df["balance"]

#Spécifiez le nom de colonne de la catégorie
categorical_features = ["job","marital","education","default","housing","loan","contact","month","poutcome","end_of_month_flag"]


#Encodage des étiquettes
#J'ai fait un encodage cible, mais le score n'a pas changé

for col in categorical_features:
  lbl = preprocessing.LabelEncoder()
  lbl.fit(all_df[col])
  lbl.transform(all_df[col])
  all_df[col] = lbl.transform(all_df[col])


#Division des données d'entraînement et des données de test
train_df = all_df[all_df["y"] != -999]
test_df = all_df[all_df["y"] == -999]

#Diviser en variables explicatives et variables objectives
origin_y_train = train_df["y"]
origin_X_train = train_df.drop(["y"],axis = 1)
origin_X_test = test_df.drop(["y"],axis = 1)

output_df = pd.DataFrame()

##Exécution à partir d'ici sur mon PC(Mémoire Core i5 de 10e génération 8 Go)Ensuite, cela a pris plus de 10 heures

for i in range(100):
    #Diviser les données de test à partir des données d'entraînement
    X_train , X_valid , y_train , y_valid = train_test_split(origin_X_train,origin_y_train,test_size = 0.3 , random_state = i , stratify=origin_y_train)
    #Création de l'ensemble de données
    lgb_train = lgb.Dataset(X_train,y_train,categorical_feature = categorical_features,free_raw_data=False)
    lgb_eval = lgb.Dataset(X_valid , y_valid , reference = lgb_train , categorical_feature = categorical_features,free_raw_data=False)
    params ={"objective":"binary",
             "metric":"auc"    
    }

    best_params, tuning_history = dict(), list()
    booster = lgb.train(params, lgb_train, valid_sets=[lgb_train,lgb_eval],
                        verbose_eval=0,
                        best_params=best_params,
                        tuning_history=tuning_history)

    print("Best Params:", best_params)
    print("Tuning history:", tuning_history)

    #Ajout d'un hyper paramètre avec l'ASC la plus élevée
    params.update(best_params)

    #Apprentissage
    model = lgb.train(
        params,lgb_train,
        valid_sets=[lgb_train,lgb_eval],
        verbose_eval = 10,
        num_boost_round = 1000,
        early_stopping_rounds=10
    )

    #Prédite par les données de compétition
    y_pred = model.predict(origin_X_test,num_iteration=model.best_iteration)

    output_df[i] = y_pred


submit_df = pd.read_csv("../../data/submit_sample.csv",header = None)
del submit_df[1]
submit_df["1"] = output_df.mean(axis = 1)
submit_df
submit_df.to_csv("../../output/result.csv",header=None,index=False)

#Au cours d'essais et d'erreurs, j'ai confirmé l'importance de la fonctionnalité et conçu la quantité de fonctionnalités.
lgb.plot_importance(model, height=0.5, figsize=(8,12))

__ Lorsque j'ai soumis ceci, l'AUC était de 0,859__

En outre, le résultat de la prédiction 100 fois en supprimant la colonne day et l'indicateur de fin de mois était de 0,859.

Lorsque j'ai pris la moyenne de ces __2 prédictions et les ai soumises, j'ai pu dépasser en toute sécurité 0,860 __ Toutes nos félicitations

image.png

Qu'est-ce que j'ai fait d'autre

J'ai essayé d'augmenter le score en optimisant les hyper paramètres d'un modèle en utilisant catboost, mais le score n'est que légèrement augmenté et cela ne vaut pas le temps de calcul. Il semblait optimiste de tourner lightgbm avec un nombre aléatoire approprié pour la déclaration, alors j'ai abandonné.

Ce que j'aurais aimé faire

Édition du modèle

J'aurais aimé avoir empilé xgboost et NN ensemble Après enquête, il semble que combiner plusieurs méthodes soit l'une des stratégies de route royale de la compétition.

J'étais satisfait d'avoir dépassé l'objectif de 0,860, alors je suis entré dans l'entrepôt.

Édition du code

J'ai pensé qu'il valait mieux faire du traitement des quantités de caractéristiques une fonction. Je veux pouvoir écrire du beau code même par essais et erreurs

finalement

Jusqu'à la fin Merci d'avoir lu Si vous avez des questions, des suggestions ou des améliorations difficiles à comprendre, n'hésitez pas à commenter.

Recommended Posts

SIGNATE [1st _Beginner Limited Competition] Participation au ciblage des clients de la banque
SIGNATE [1st _Beginner Limited Competition] Résolution du ciblage des clients bancaires
Signate_ Revue du 1er Concours Limité Débutant
[SIGNATE] Ciblage des clients de la banque @ apprentissage
Signer 2nd _Beginner Limited Competition Review
J'ai fréquenté l'école et j'ai participé pour la première fois au concours limité BEGINNER de SIGNATE.
J'ai participé à la compétition NFL de Kaggle