{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":59093,"databundleVersionId":7469972,"sourceType":"competition"}],"dockerImageVersionId":30635,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Created by yunsuxiaozi\n### Import necessary libraries","metadata":{}},{"cell_type":"code","source":"import pandas as pd#导入csv文件的库\nimport numpy as np#进行矩阵运算的库\nfrom lightgbm import LGBMClassifier#导入lgbm分类器\nimport dill#对对象进行序列化和反序列化(例如保存和加载树模型)\nfrom sklearn.model_selection import StratifiedKFold\nimport warnings#避免一些可以忽略的报错\nwarnings.filterwarnings('ignore')#filterwarnings()方法是用于设置警告过滤器的方法，它可以控制警告信息的输出方式和级别.","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Config","metadata":{}},{"cell_type":"code","source":"#设置随机种子,保证模型可以复现\nimport random\nseed=2024\n#设置随机种子,保证模型可以复现\nnp.random.seed(seed)\nrandom.seed(seed)\nnum_folds=10\n#这是pss4e1的参数,HMS比赛没有找过参数\nlgb_params={'random_state': seed, 'n_estimators': 1024,\n           'reg_alpha': 0.3245237982823759, 'reg_lambda': 9.713500590822735,\n           'colsample_bytree': 0.5031339908309955, 'subsample': 0.9680254188045883, \n           'learning_rate': 0.036537966896644465, 'num_leaves': 29, 'min_child_samples': 99}","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Import dataset","metadata":{}},{"cell_type":"code","source":"TARGETS=['seizure_vote', 'lpd_vote', 'gpd_vote', 'lrda_vote', 'grda_vote', 'other_vote']\ntrain_df=pd.read_csv(\"/kaggle/input/hms-harmful-brain-activity-classification/train.csv\")\neeg_ids=train_df['eeg_id'].unique()\nprint(f\"len(eeg_ids):{len(eeg_ids)}\")\n\ntrain_feats=pd.DataFrame({'eeg_id':eeg_ids})\nfor target in TARGETS:\n    target_sum=train_df.groupby(train_df['eeg_id'])[[target]].agg({target:'sum'}).reset_index()\n    train_feats=train_feats.merge(target_sum,on='eeg_id',how='left')\ntotal_sum=train_feats[TARGETS].values.sum(axis=1)\nfor target in TARGETS:\n    train_feats[target]/=total_sum\ntrain_feats.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Feature Engineer","metadata":{}},{"cell_type":"code","source":"#https://www.kaggle.com/code/yunsuxiaozi/writing-quality-fusion-notebook\ncolumns=['Fp1', 'F3', 'C3', 'P3', 'F7', 'T3', 'T5', 'O1', 'Fz', 'Cz', 'Pz',\n       'Fp2', 'F4', 'C4', 'P4', 'F8', 'T4', 'T6', 'O2', 'EKG']\n#对数据求统计特征\nAGGREGATIONS = ['count', 'mean', 'std', 'min', 'max', 'sem','median', 'skew','sum']\ngaps=[1,2,3,5,10,20,30,60,100]\n\nadd_feats=[]\nfor eeg_id in eeg_ids:\n    eeg_data=pd.read_parquet(f\"/kaggle/input/hms-harmful-brain-activity-classification/train_eegs/{eeg_id}.parquet\")\n    feats=[]#每个eeg_id的feats\n    for col  in columns:\n        for gap in gaps:\n            eeg_data[f\"{col}_shift{gap}\"]=eeg_data[col].shift(gap)\n            eeg_data[f\"{col}_gap{gap}\"]=eeg_data[col]-eeg_data[f\"{col}_shift{gap}\"]\n            feats+=list(eeg_data[f\"{col}_gap{gap}\"].agg(AGGREGATIONS).values)\n    add_feats.append(feats)\nfeatures=[f\"{col}_gap_{gap}_{agg}\" for agg  in  AGGREGATIONS for gap in gaps for col in columns]\nprint(f\"len(features):{len(features)}\")\ntrain_feats[features]=add_feats\ntrain_feats.head()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Train and save models","metadata":{}},{"cell_type":"code","source":"X=train_feats[features]\ny=train_feats[TARGETS]\ny_label=np.argmax(y.values,axis=1)\nall_oof = []\nall_true = []\n\n#保存训练好的树模型,obj是保存的模型,path是需要保存的路径\ndef pickle_dump(obj, path):\n    #打开指定的路径path,binary write(二进制写入)\n    with open(path, mode=\"wb\") as f:\n        #将obj对象保存到f,使用协议版本4进行序列化\n        dill.dump(obj, f, protocol=4)\n#根据数据的一些属性,使用5折交叉验证.\nskf = StratifiedKFold(n_splits=num_folds,shuffle=True,random_state=seed)\n#根据训练数据的类别和患者id来划分.\nfor fold, (train_index, valid_index) in enumerate(skf.split(X,y_label.astype(str))):   \n    \n    print(f'Fold {fold+1}')\n    \n    model = LGBMClassifier(**lgb_params)\n    \n    X_train = X.loc[train_index].values\n    y_train = np.argmax(y.loc[train_index].values,axis=1)#最大的下标\n    sample_weight=np.max(y.loc[train_index].values,axis=1)#最大的概率(置信度)\n    X_valid = X.loc[valid_index].values\n    y_valid = np.argmax(y.loc[valid_index].values,axis=1)\n    \n    model.fit(X_train, y_train, eval_set=[(X_valid, y_valid)], \n              verbose=0,#不输出任何东西\n              sample_weight=sample_weight,\n              early_stopping_rounds=100)\n    pickle_dump(model, f'/kaggle/working/lgb_f{fold}.model') #保存训练好的模型   \n    \n    all_oof.append(model.predict_proba(X_valid))\n    all_true.append(y.loc[valid_index].values)\n    \nall_oof = np.concatenate(all_oof)\nall_true = np.concatenate(all_true)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Metric","metadata":{}},{"cell_type":"code","source":"def KL_loss(p,q):\n    epsilon=10**(-15)\n    p=np.clip(p,epsilon,1-epsilon)\n    #对第一个维度,就是num_classes维度的损失求和,得到每个样本的损失,然后对第0维求平均,得到每个样本平均KL散度.\n    return np.mean( np.sum(p*(np.log(p)-np.log(q)),axis=1)  )\nprint(f\"CV of Kullback Leibler Divergence:{KL_loss(all_true,all_oof)}\")","metadata":{},"execution_count":null,"outputs":[]}]}