{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# About this notebook\n\n## 目的 : fast aiとembedding + UMAPを見ることによって、\n## 機械学習がどのように進んでいくかを見ていく。\n\n\n## Objective: See how machine learning progresses by looking at fast ai and embedding + UMAP.","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 1. Import & Load","metadata":{}},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-03-04T06:53:36.710010Z","iopub.execute_input":"2022-03-04T06:53:36.710628Z","iopub.status.idle":"2022-03-04T06:53:36.742525Z","shell.execute_reply.started":"2022-03-04T06:53:36.710535Z","shell.execute_reply":"2022-03-04T06:53:36.741836Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from fastai.tabular.all import *","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:36.744031Z","iopub.execute_input":"2022-03-04T06:53:36.744348Z","iopub.status.idle":"2022-03-04T06:53:39.188884Z","shell.execute_reply.started":"2022-03-04T06:53:36.744313Z","shell.execute_reply":"2022-03-04T06:53:39.188166Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = pd.read_csv(\"/kaggle/input/digit-recognizer/train.csv\")\ntrain.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:39.190375Z","iopub.execute_input":"2022-03-04T06:53:39.190632Z","iopub.status.idle":"2022-03-04T06:53:42.146582Z","shell.execute_reply.started":"2022-03-04T06:53:39.190597Z","shell.execute_reply":"2022-03-04T06:53:42.145900Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test = pd.read_csv(\"/kaggle/input/digit-recognizer/test.csv\")\ntest.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:42.148578Z","iopub.execute_input":"2022-03-04T06:53:42.148814Z","iopub.status.idle":"2022-03-04T06:53:43.990573Z","shell.execute_reply.started":"2022-03-04T06:53:42.148782Z","shell.execute_reply":"2022-03-04T06:53:43.989853Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission= pd.read_csv(\"/kaggle/input/digit-recognizer/sample_submission.csv\")\nsubmission.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:43.991836Z","iopub.execute_input":"2022-03-04T06:53:43.992254Z","iopub.status.idle":"2022-03-04T06:53:44.013551Z","shell.execute_reply.started":"2022-03-04T06:53:43.992213Z","shell.execute_reply":"2022-03-04T06:53:44.012781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2. 初期のUMAP状態を見る\n## View initial UMAP status","metadata":{}},{"cell_type":"code","source":"import cudf, cuml, cupy\nfrom cuml import UMAP","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:44.014888Z","iopub.execute_input":"2022-03-04T06:53:44.015220Z","iopub.status.idle":"2022-03-04T06:53:46.948130Z","shell.execute_reply.started":"2022-03-04T06:53:44.015183Z","shell.execute_reply":"2022-03-04T06:53:46.947397Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:46.949461Z","iopub.execute_input":"2022-03-04T06:53:46.949714Z","iopub.status.idle":"2022-03-04T06:53:46.974608Z","shell.execute_reply.started":"2022-03-04T06:53:46.949682Z","shell.execute_reply":"2022-03-04T06:53:46.973967Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"umap = UMAP(random_state=42)\nembed_2d = umap.fit_transform(train.iloc[:,1:].values)\nembed_2d = cupy.asnumpy( embed_2d )","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:46.975841Z","iopub.execute_input":"2022-03-04T06:53:46.976098Z","iopub.status.idle":"2022-03-04T06:53:56.174379Z","shell.execute_reply.started":"2022-03-04T06:53:46.976066Z","shell.execute_reply":"2022-03-04T06:53:56.173471Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.scatter(embed_2d[:,0],embed_2d[:,1],c = train[\"label\"] )","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:56.175796Z","iopub.execute_input":"2022-03-04T06:53:56.176026Z","iopub.status.idle":"2022-03-04T06:53:57.705404Z","shell.execute_reply.started":"2022-03-04T06:53:56.175995Z","shell.execute_reply":"2022-03-04T06:53:57.704715Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## すでにlabelごとにある程度固まっている\n## Already solidified to some extent for each label","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3. 機械学習後のUMAP特徴量\nUMAP features after machine learning\n\n## 3.1 5kfoldに分けて1fold目で実験\nDivide into 5kfold and experiment with the 1st fold","metadata":{}},{"cell_type":"code","source":"from sklearn import preprocessing\nfrom sklearn.metrics import accuracy_score\nfrom sklearn.model_selection import StratifiedKFold","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:57.708521Z","iopub.execute_input":"2022-03-04T06:53:57.708936Z","iopub.status.idle":"2022-03-04T06:53:57.713031Z","shell.execute_reply.started":"2022-03-04T06:53:57.708897Z","shell.execute_reply":"2022-03-04T06:53:57.712347Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Fold = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\nfor n, (train_index, val_index) in enumerate(Fold.split(train, train[\"label\"])):\n    train.loc[val_index, 'fold'] = int(n)\ntrain['fold'] = train['fold'].astype(int)\nprint(train.groupby(['fold', \"label\"]).size())","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:57.714098Z","iopub.execute_input":"2022-03-04T06:53:57.714364Z","iopub.status.idle":"2022-03-04T06:53:57.749072Z","shell.execute_reply.started":"2022-03-04T06:53:57.714331Z","shell.execute_reply":"2022-03-04T06:53:57.748412Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# seedの固定 : fix seed","metadata":{}},{"cell_type":"code","source":"seed=42\n#fastai　内のライブラリ\nset_seed(seed, reproducible=True)","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:57.750396Z","iopub.execute_input":"2022-03-04T06:53:57.750867Z","iopub.status.idle":"2022-03-04T06:53:57.755279Z","shell.execute_reply.started":"2022-03-04T06:53:57.750832Z","shell.execute_reply":"2022-03-04T06:53:57.754504Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 数値データ、ターゲットの定義 : define features and target","metadata":{}},{"cell_type":"code","source":"train.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:57.756632Z","iopub.execute_input":"2022-03-04T06:53:57.757102Z","iopub.status.idle":"2022-03-04T06:53:57.784628Z","shell.execute_reply.started":"2022-03-04T06:53:57.757063Z","shell.execute_reply":"2022-03-04T06:53:57.783994Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.columns[1:-1]","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:57.786892Z","iopub.execute_input":"2022-03-04T06:53:57.787155Z","iopub.status.idle":"2022-03-04T06:53:57.792482Z","shell.execute_reply.started":"2022-03-04T06:53:57.787111Z","shell.execute_reply":"2022-03-04T06:53:57.791642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#catlist = [\"Sex\",\"Embarked\"] # define string ( categorical data ). 文字列の列名\ncontlist = train.columns[1:-1].to_list()# define continuous data. 数字の列名\nTARGET = \"label\" # target . 予想するもの","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:57.794151Z","iopub.execute_input":"2022-03-04T06:53:57.794481Z","iopub.status.idle":"2022-03-04T06:53:57.799731Z","shell.execute_reply.started":"2022-03-04T06:53:57.794439Z","shell.execute_reply":"2022-03-04T06:53:57.799022Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"validind = train[train[\"fold\"]==0].index # validationのindex\nvalidind[:3]","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:57.800862Z","iopub.execute_input":"2022-03-04T06:53:57.801856Z","iopub.status.idle":"2022-03-04T06:53:58.007322Z","shell.execute_reply.started":"2022-03-04T06:53:57.801819Z","shell.execute_reply":"2022-03-04T06:53:58.006437Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BATCH_SIZE = 256","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:58.008783Z","iopub.execute_input":"2022-03-04T06:53:58.009184Z","iopub.status.idle":"2022-03-04T06:53:58.013045Z","shell.execute_reply.started":"2022-03-04T06:53:58.009140Z","shell.execute_reply":"2022-03-04T06:53:58.012262Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(validind)","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:58.014235Z","iopub.execute_input":"2022-03-04T06:53:58.014878Z","iopub.status.idle":"2022-03-04T06:53:58.023867Z","shell.execute_reply.started":"2022-03-04T06:53:58.014843Z","shell.execute_reply":"2022-03-04T06:53:58.022786Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# DataLoader","metadata":{}},{"cell_type":"code","source":"dls = TabularDataLoaders.from_df(train, # dataframe\n                                 path='.',  \n                                 #procs=[Normalize], # 文字列の数字変換、中央値でfillna、平均減算標準偏差で割って正規化 \n                                 cat_names=None, # 文字列リスト。文字列ない場合はNoneでOK\n                                 cont_names=contlist, # 数字列リスト。ない場合はNoneでOK\n                                 y_names=TARGET, # target\n                                 y_block=CategoryBlock, # CategoryBlock, MultiCategoryBlock, RegressionBlockから選ぶ noneでも可 \n                                 valid_idx=validind, # Validationのindex\n                                 bs=BATCH_SIZE, # バッチサイズ\n                                 shuffle_train=True, # 学習時にトレインデータshuffleするか\n                                 shuffle=False,\n                                 val_shuffle=False,\n                                 n=None, \n                                 device=\"cuda\", # gpu使用時は\"cuda\"\n                                 drop_last=None, # dataloaderでbatchsizeに余りがでたら、切るか。\n                                 val_bs=BATCH_SIZE * 2 # validationのbatch size\n                                 )","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:58.025239Z","iopub.execute_input":"2022-03-04T06:53:58.025645Z","iopub.status.idle":"2022-03-04T06:53:58.679610Z","shell.execute_reply.started":"2022-03-04T06:53:58.025609Z","shell.execute_reply":"2022-03-04T06:53:58.678899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dls.train.show_batch()","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:58.681044Z","iopub.execute_input":"2022-03-04T06:53:58.681304Z","iopub.status.idle":"2022-03-04T06:53:59.270581Z","shell.execute_reply.started":"2022-03-04T06:53:58.681271Z","shell.execute_reply":"2022-03-04T06:53:59.269839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"learn = tabular_learner(dls, # dataset.先ほど作成\n                        layers=[1000,500,200],  # neuralnetの中間層\n                        emb_szs=None,  \n                        config=None, \n                        n_out=None, # 出力する数.Noneだと自動認識してくれる\n                        y_range=None, \n                        loss_func=CrossEntropyLossFlat(), # ↑のリンク参照\n                        opt_func=Adam,  # optimizer\n                        lr=0.001, # 学習率\n                        splitter=trainable_params, \n                        \n                        \n                        cbs=[\n                            \n                            SaveModelCallback(monitor=\"accuracy\",comp=np.greater), # 学習後に一番良かったモデルsaveとload \n                             EarlyStoppingCallback(monitor=\"accuracy\",comp=np.greater, patience=3), # モニターしてpatience更新しなかったらやめる\n                          #   GradientClip, # 重みづけをいきすぎないように\n                          #   ReduceLROnPlateau(monitor='accuracy',comp=np.greater, patience=10,factor = 10) # 学習率モニターしながら変えたい人はこれを入れる\n                           ],\n\n\n                        metrics=accuracy, # metric \n                        path=None, \n                        model_dir='models', # savepathだと思うが、後で自分でやるからいい。 \n                        wd=None, \n                        wd_bn_bias=False,\n                        train_bn=True, \n                        moms=(0.95, 0.85, 0.95)\n                        )","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:59.271577Z","iopub.execute_input":"2022-03-04T06:53:59.272268Z","iopub.status.idle":"2022-03-04T06:53:59.300133Z","shell.execute_reply.started":"2022-03-04T06:53:59.272226Z","shell.execute_reply":"2022-03-04T06:53:59.299506Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.model","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:59.301534Z","iopub.execute_input":"2022-03-04T06:53:59.301798Z","iopub.status.idle":"2022-03-04T06:53:59.307859Z","shell.execute_reply.started":"2022-03-04T06:53:59.301762Z","shell.execute_reply":"2022-03-04T06:53:59.306956Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.lr_find()","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:53:59.309455Z","iopub.execute_input":"2022-03-04T06:53:59.309725Z","iopub.status.idle":"2022-03-04T06:54:01.285550Z","shell.execute_reply.started":"2022-03-04T06:53:59.309691Z","shell.execute_reply":"2022-03-04T06:54:01.284898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.fit(1, 1e-3)","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:54:01.286673Z","iopub.execute_input":"2022-03-04T06:54:01.286901Z","iopub.status.idle":"2022-03-04T06:54:03.110659Z","shell.execute_reply.started":"2022-03-04T06:54:01.286867Z","shell.execute_reply":"2022-03-04T06:54:03.110004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## viaualize embedding","metadata":{}},{"cell_type":"code","source":"learn.model.layers[3][0] = nn.Identity()","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:54:03.111930Z","iopub.execute_input":"2022-03-04T06:54:03.112346Z","iopub.status.idle":"2022-03-04T06:54:03.119560Z","shell.execute_reply.started":"2022-03-04T06:54:03.112307Z","shell.execute_reply":"2022-03-04T06:54:03.118498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trn = train[train[\"fold\"]!=0].reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:54:03.120843Z","iopub.execute_input":"2022-03-04T06:54:03.121219Z","iopub.status.idle":"2022-03-04T06:54:03.304064Z","shell.execute_reply.started":"2022-03-04T06:54:03.121186Z","shell.execute_reply":"2022-03-04T06:54:03.303321Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trn_dl = dls.test_dl(trn)","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:54:03.305237Z","iopub.execute_input":"2022-03-04T06:54:03.305732Z","iopub.status.idle":"2022-03-04T06:54:03.451560Z","shell.execute_reply.started":"2022-03-04T06:54:03.305692Z","shell.execute_reply":"2022-03-04T06:54:03.450792Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred, _ = learn.get_preds(dl=trn_dl)","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:54:03.455518Z","iopub.execute_input":"2022-03-04T06:54:03.455711Z","iopub.status.idle":"2022-03-04T06:54:04.125350Z","shell.execute_reply.started":"2022-03-04T06:54:03.455686Z","shell.execute_reply":"2022-03-04T06:54:04.124650Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred = np.array(pred)","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:54:04.126676Z","iopub.execute_input":"2022-03-04T06:54:04.126919Z","iopub.status.idle":"2022-03-04T06:54:04.141690Z","shell.execute_reply.started":"2022-03-04T06:54:04.126886Z","shell.execute_reply":"2022-03-04T06:54:04.141043Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"umap = UMAP(random_state=42)\nembed_2d = umap.fit_transform(pred)\nembed_2d = cupy.asnumpy( embed_2d )","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:54:04.143068Z","iopub.execute_input":"2022-03-04T06:54:04.143333Z","iopub.status.idle":"2022-03-04T06:54:04.575846Z","shell.execute_reply.started":"2022-03-04T06:54:04.143300Z","shell.execute_reply":"2022-03-04T06:54:04.575072Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.scatter(embed_2d[:,0],embed_2d[:,1],c = trn[\"label\"] )","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:54:04.577229Z","iopub.execute_input":"2022-03-04T06:54:04.577481Z","iopub.status.idle":"2022-03-04T06:54:06.029630Z","shell.execute_reply.started":"2022-03-04T06:54:04.577445Z","shell.execute_reply":"2022-03-04T06:54:06.028955Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 少し離れた : A little away","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 10 epoch","metadata":{}},{"cell_type":"code","source":"learn = tabular_learner(dls, # dataset.先ほど作成\n                        layers=[1000,500,200],  # neuralnetの中間層\n                        emb_szs=None,  \n                        config=None, \n                        n_out=None, # 出力する数.Noneだと自動認識してくれる\n                        y_range=None, \n                        loss_func=CrossEntropyLossFlat(), # ↑のリンク参照\n                        opt_func=Adam,  # optimizer\n                        lr=0.001, # 学習率\n                        splitter=trainable_params, \n                        \n                        \n                        cbs=[\n                            \n                            SaveModelCallback(monitor=\"accuracy\",comp=np.greater), # 学習後に一番良かったモデルsaveとload \n                           #  EarlyStoppingCallback(monitor=\"accuracy\",comp=np.greater, patience=3), # モニターしてpatience更新しなかったらやめる\n                          #   GradientClip, # 重みづけをいきすぎないように\n                          #   ReduceLROnPlateau(monitor='accuracy',comp=np.greater, patience=10,factor = 10) # 学習率モニターしながら変えたい人はこれを入れる\n                           ],\n\n\n                        metrics=accuracy, # metric \n                        path=None, \n                        model_dir='models', # savepathだと思うが、後で自分でやるからいい。 \n                        wd=None, \n                        wd_bn_bias=False,\n                        train_bn=True, \n                        moms=(0.95, 0.85, 0.95)\n                        )","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:54:06.031029Z","iopub.execute_input":"2022-03-04T06:54:06.031491Z","iopub.status.idle":"2022-03-04T06:54:06.051500Z","shell.execute_reply.started":"2022-03-04T06:54:06.031454Z","shell.execute_reply":"2022-03-04T06:54:06.050847Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.fit(10, 1e-3)","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:54:06.052495Z","iopub.execute_input":"2022-03-04T06:54:06.052710Z","iopub.status.idle":"2022-03-04T06:54:21.479644Z","shell.execute_reply.started":"2022-03-04T06:54:06.052678Z","shell.execute_reply":"2022-03-04T06:54:21.478989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.model.layers[3][0] = nn.Identity()\ntrn = train[train[\"fold\"]!=0].reset_index(drop=True)\ntrn_dl = dls.test_dl(trn)\npred, _ = learn.get_preds(dl=trn_dl)\n\npred = np.array(pred)\n\numap = UMAP(random_state=42)\nembed_2d = umap.fit_transform(pred)\nembed_2d = cupy.asnumpy( embed_2d )\n\nplt.scatter(embed_2d[:,0],embed_2d[:,1],c = trn[\"label\"] )","metadata":{"execution":{"iopub.status.busy":"2022-03-04T06:54:21.480763Z","iopub.execute_input":"2022-03-04T06:54:21.481182Z","iopub.status.idle":"2022-03-04T06:54:24.003780Z","shell.execute_reply.started":"2022-03-04T06:54:21.481144Z","shell.execute_reply":"2022-03-04T06:54:24.003083Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# かなりきれいに分離していっている。\nIt's separated pretty well.","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}