{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":3004,"databundleVersionId":861823,"sourceType":"competition"}],"dockerImageVersionId":30646,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"### <span style=\"color: blue; \">パッケージの読み込み</span>","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n%matplotlib inline\n\nnp.random.seed(0)\nrandom_seed = 0\nsns.set()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:06.822731Z","iopub.execute_input":"2024-02-15T10:04:06.823150Z","iopub.status.idle":"2024-02-15T10:04:07.585141Z","shell.execute_reply.started":"2024-02-15T10:04:06.823118Z","shell.execute_reply":"2024-02-15T10:04:07.584408Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nfrom tensorflow.keras.utils import to_categorical\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D\nfrom keras.optimizers import RMSprop","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:07.587008Z","iopub.execute_input":"2024-02-15T10:04:07.587743Z","iopub.status.idle":"2024-02-15T10:04:11.004499Z","shell.execute_reply.started":"2024-02-15T10:04:07.587698Z","shell.execute_reply":"2024-02-15T10:04:11.002416Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### <span style=\"color: blue; \">データの読み込み</span>","metadata":{}},{"cell_type":"code","source":"train = pd.read_csv('/kaggle/input/digit-recognizer/train.csv')\ntest = pd.read_csv('/kaggle/input/digit-recognizer/test.csv')","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:11.006789Z","iopub.execute_input":"2024-02-15T10:04:11.008115Z","iopub.status.idle":"2024-02-15T10:04:13.812769Z","shell.execute_reply.started":"2024-02-15T10:04:11.008069Z","shell.execute_reply":"2024-02-15T10:04:13.810718Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ あらかじめ準備されているデータの読み込み","metadata":{}},{"cell_type":"code","source":"sns.countplot(x='label', data=train)","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:13.815654Z","iopub.execute_input":"2024-02-15T10:04:13.816906Z","iopub.status.idle":"2024-02-15T10:04:14.081108Z","shell.execute_reply.started":"2024-02-15T10:04:13.816861Z","shell.execute_reply":"2024-02-15T10:04:14.080214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ 0 から 9 までの正解ラベルをつけられた手書き数字の画像がそれぞれ何個あるかを表示","metadata":{}},{"cell_type":"markdown","source":"### <span style=\"color: blue; \">特徴量エンジニアリング</span>","metadata":{}},{"cell_type":"code","source":"y_train = train['label']\nX_train = train.drop(labels = ['label'],axis = 1) \n\ny_train.value_counts()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:14.082452Z","iopub.execute_input":"2024-02-15T10:04:14.082810Z","iopub.status.idle":"2024-02-15T10:04:14.138572Z","shell.execute_reply.started":"2024-02-15T10:04:14.082780Z","shell.execute_reply":"2024-02-15T10:04:14.137225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ train データセットを正解ラベル（'label'）を表す y_train と、それ以外の X_train とに分け、正解ラベル y_train がそれぞれ何個あるかを表示した","metadata":{}},{"cell_type":"code","source":"X_train.isnull().sum()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:14.139825Z","iopub.execute_input":"2024-02-15T10:04:14.140092Z","iopub.status.idle":"2024-02-15T10:04:14.165838Z","shell.execute_reply.started":"2024-02-15T10:04:14.140069Z","shell.execute_reply":"2024-02-15T10:04:14.164592Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_train.isnull().sum()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:14.167093Z","iopub.execute_input":"2024-02-15T10:04:14.168617Z","iopub.status.idle":"2024-02-15T10:04:14.178204Z","shell.execute_reply.started":"2024-02-15T10:04:14.168586Z","shell.execute_reply":"2024-02-15T10:04:14.176782Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test.isnull().sum()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:14.180048Z","iopub.execute_input":"2024-02-15T10:04:14.180568Z","iopub.status.idle":"2024-02-15T10:04:14.203322Z","shell.execute_reply.started":"2024-02-15T10:04:14.180529Z","shell.execute_reply":"2024-02-15T10:04:14.201850Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ test と（X_train と y_train に分けた）train のデータセットのどちらも欠損値はなく、そのまま使用できることがわかった","metadata":{}},{"cell_type":"code","source":"X_train = X_train / 255.0\ntest = test / 255.0\n\nX_train = X_train.values.reshape(-1,28,28,1)\ntest = test.values.reshape(-1,28,28,1)","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:14.204563Z","iopub.execute_input":"2024-02-15T10:04:14.204846Z","iopub.status.idle":"2024-02-15T10:04:14.278684Z","shell.execute_reply.started":"2024-02-15T10:04:14.204824Z","shell.execute_reply":"2024-02-15T10:04:14.277947Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ pixel（画素） には濃淡の具合を表す 0 から 255 までの数値が割り当てられているが、これを 0 から 1 に変換する\n\nもともとのデータセットは 28 × 28 = 784 の pixel における数値を１列に並べただけのものであるが、これを reshape() によって\n\n（もともとの情報を失わないよう）きちんと 28 × 28 と色の種類を表すチャンネルが 1 つ（カラー画像であれば RGB の 3 とする）のデータとして並べ直している\n\n最初の -1 はデータセットの総量と reshape の操作後の結果の辻褄が合うように自動的に調節させることを意味し、ここでは画像の枚数が（具体的に指定せずとも）全部で〜個ある、ということを入力したことと等しい","metadata":{}},{"cell_type":"code","source":"y_train = to_categorical(y_train, num_classes = 10)","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:14.281028Z","iopub.execute_input":"2024-02-15T10:04:14.281264Z","iopub.status.idle":"2024-02-15T10:04:14.288988Z","shell.execute_reply.started":"2024-02-15T10:04:14.281244Z","shell.execute_reply":"2024-02-15T10:04:14.287800Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ to_categorical で先ほどのデータセット y_train における各データを『one-hot ベクトル』というものに変換している\n\ny_train の中には 0〜9 までの数値が散りばめられており、第何個目の画像が数値〜である、ということの答えを与えるデータとなっていた\n\nこれを、例えば 0 → [1,0,0,0,0,0,0,0,0,0]、1 → [0,1,0,0,0,0,0,0,0,0]、2 → [0,0,1,0,0,0,0,0,0,0]、3 → [0,0,0,1,0,0,0,0,0,0] というように\n\n0 か 1 かという数字の列（one-hot ベクトル）で表し直すことを行っている（num_classes = 10 はその列の数を指定している）","metadata":{}},{"cell_type":"markdown","source":"### <span style=\"color: blue; \">学習・検証用データの分割</span>","metadata":{}},{"cell_type":"code","source":"X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size = 0.1, random_state=random_seed)","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:14.290425Z","iopub.execute_input":"2024-02-15T10:04:14.291475Z","iopub.status.idle":"2024-02-15T10:04:14.563867Z","shell.execute_reply.started":"2024-02-15T10:04:14.291433Z","shell.execute_reply":"2024-02-15T10:04:14.563090Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ X_train, y_train で表した訓練用のデータセットをさらに学習用 X_train, y_train と検証用 X_val, y_val に分け、予測の精度を上げるようにしている\n\n（学習用：検証用の比率は test_size = 0.1 によって９：１としている）","metadata":{}},{"cell_type":"code","source":"plt.imshow(X_train[0][:,:,0])","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:14.567249Z","iopub.execute_input":"2024-02-15T10:04:14.567542Z","iopub.status.idle":"2024-02-15T10:04:14.822924Z","shell.execute_reply.started":"2024-02-15T10:04:14.567520Z","shell.execute_reply":"2024-02-15T10:04:14.821417Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ 学習用データセット X_train の最初の画像を表示（X_train[0][:,:,0] の [0] の部分の数値を変えることをとで何個めの画像を表示させるかを指定できる）\n\n（[ : , : , 0] の部分は 28 × 28 × 1 個ある数値を全て用いて１つの画像とすることを意味しており、ここを変更することはできない）","metadata":{}},{"cell_type":"code","source":"plt.imshow(X_val[0][:,:,0])","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:14.824126Z","iopub.execute_input":"2024-02-15T10:04:14.824526Z","iopub.status.idle":"2024-02-15T10:04:15.063252Z","shell.execute_reply.started":"2024-02-15T10:04:14.824496Z","shell.execute_reply":"2024-02-15T10:04:15.062188Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ 検証用データセット X_val の最初の画像を表示","metadata":{}},{"cell_type":"markdown","source":"### <span style=\"color: blue; \">畳み込みニューラルネットワーク（CNN）の実行</span>","metadata":{}},{"cell_type":"code","source":"model = Sequential()\n\nmodel.add(Conv2D(filters = 32, kernel_size = (5,5), padding = 'Same', activation ='relu', input_shape = (28,28,1)))\nmodel.add(Conv2D(filters = 32, kernel_size = (5,5), padding = 'Same', activation ='relu'))\nmodel.add(MaxPool2D(pool_size=(2,2)))\nmodel.add(Dropout(0.25))\n\nmodel.add(Conv2D(filters = 64, kernel_size = (3,3), padding = 'Same', activation ='relu'))\nmodel.add(Conv2D(filters = 64, kernel_size = (3,3), padding = 'Same', activation ='relu'))\nmodel.add(MaxPool2D(pool_size=(2,2), strides=(2,2)))\nmodel.add(Dropout(0.25))\n\nmodel.add(Flatten())\nmodel.add(Dense(256, activation = \"relu\"))\nmodel.add(Dropout(0.5))\nmodel.add(Dense(10, activation = \"softmax\"))","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:15.064352Z","iopub.execute_input":"2024-02-15T10:04:15.064625Z","iopub.status.idle":"2024-02-15T10:04:15.231389Z","shell.execute_reply.started":"2024-02-15T10:04:15.064604Z","shell.execute_reply":"2024-02-15T10:04:15.230426Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ 深層学習（ディープラーニング）のためのライブラリである Keras における Sequential 機能を用いて、どのようなニューラルネットワークを作成するのかを具体的に指定している\n\nadd(〜) でどのような種類の層を追加していくかを指定しており、Conv2D（畳み込み層）、MaxPool2D（プーリング層）、Dropout（ドロップアウト処理）、Flatten（平坦化処理）、Dense（全結合層）などが使用可能\n\nより詳しくいうと、\n\nConv2D における filters = 32, kernel_size = (5,5) は 5×5 の数字からなる 32 種類のフィルターを作成し用いること、padding = 'Same' は一般的に畳み込みの処理を行うとそのままではデータ量が削減される（28×28 が 24×24 などになる）が、それを防ぐためにデータを水増しして同じサイズのままにすること、activation ='relu' は活性化関数として Relu 関数を用いること, input_shape = (28,28,1) は入力データのサイズを指定していることを意味する\n\nMaxPool2D　ではプーリング処理として最大値プーリングを行うことを意味しており、pool_size=(2,2) によって 2×2 の各領域での最大値を取り出して新たなデータとして出力する\n\nDropout() では（学習データに合わせすぎて他のデータへの応用が効かなくなる過学習を防ぐために）次に続く層への繋がりのうち、（）で指定された割合だけデータをあえて削除する操作を行うことを意味している\n\nFlatten はそれまでに得られたタテ×ヨコのデータを１列に並べる操作を行うことを意味する（次に続く全結合層へうまく入力させるため）\n\nDense は全結合ニューラルネットワークの層を表し、ノードの数や activation （活性化関数）の指定を行う（最後の層に限っては、いま 0〜9 までの『10』個の数字画像の『分類』を行いたいため、ノードは 10 個、活性化関数は出力値を確率としての値に変換する softmax 関数を用いなければならない）","metadata":{}},{"cell_type":"code","source":"optimizer = RMSprop(lr=0.01, rho=0.9, epsilon=1e-08, weight_decay=0.0)\nmodel.compile(optimizer = optimizer , loss = \"categorical_crossentropy\", metrics=[\"accuracy\"])","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:15.232629Z","iopub.execute_input":"2024-02-15T10:04:15.232925Z","iopub.status.idle":"2024-02-15T10:04:15.251284Z","shell.execute_reply.started":"2024-02-15T10:04:15.232898Z","shell.execute_reply":"2024-02-15T10:04:15.250540Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ ニューラルネットワークの学習を行う際の指針となる最適化のセットアップに関わる箇所であり、詳細は省くが、交差エントロピーについての平方根平均二乗伝播という方法を用いた","metadata":{}},{"cell_type":"code","source":"epochs = 1\nbatch_size = 64","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:15.252210Z","iopub.execute_input":"2024-02-15T10:04:15.252658Z","iopub.status.idle":"2024-02-15T10:04:15.256308Z","shell.execute_reply.started":"2024-02-15T10:04:15.252629Z","shell.execute_reply":"2024-02-15T10:04:15.255548Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ epochs（エポック数）とは学習データを何回繰り返し学習に用いるかを指定するものであり、epochs = 1 は学習データセット全体を１回だけ用いることを意味する\n\nまた、学習データをいっぺんにコンピュータに入れるよりも小分けして学習させる方が便利なため、batch_size（バッチサイズ）で何個ずつのデータでまとめるかを指定している","metadata":{}},{"cell_type":"code","source":"history = model.fit(X_train, y_train, batch_size = batch_size, epochs = epochs, validation_data = (X_val, y_val))","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:04:15.257120Z","iopub.execute_input":"2024-02-15T10:04:15.257345Z","iopub.status.idle":"2024-02-15T10:05:41.055764Z","shell.execute_reply.started":"2024-02-15T10:04:15.257326Z","shell.execute_reply":"2024-02-15T10:05:41.054377Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ 学習の実行と結果の表示\n\n学習用データと検証用データのそれぞれについて、最終的にどれだけの正答率（accuracy）が得られるようになったかが表示される","metadata":{}},{"cell_type":"code","source":"results = model.predict(test)\nresults = np.argmax(results,axis = 1)\nresults = pd.Series(results,name=\"Label\")","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:05:41.057274Z","iopub.execute_input":"2024-02-15T10:05:41.057619Z","iopub.status.idle":"2024-02-15T10:05:59.348715Z","shell.execute_reply.started":"2024-02-15T10:05:41.057589Z","shell.execute_reply":"2024-02-15T10:05:59.347259Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ 学習を終えた畳み込みニューラルネットワークを提出用のテストデータセット test に適用し、予測を行い、'Label'という名前の列としてまとめている\n\n作成してきた畳み込みニューラルネットワークの最終的な出力としては、どのカテゴリーが何％かという確率としての値が出されているだけなので、そのうち最大の値は何番目にあるのか（これは 0〜9 のどの数字に相当するのかを指定していることと等しくなる）を改めて results として出力させている","metadata":{}},{"cell_type":"code","source":"submission = pd.concat([pd.Series(range(1,28001),name = \"ImageId\"),results],axis = 1)\nsubmission.to_csv(\"mysubmission.csv\",index=False)","metadata":{"execution":{"iopub.status.busy":"2024-02-15T10:05:59.350301Z","iopub.execute_input":"2024-02-15T10:05:59.350597Z","iopub.status.idle":"2024-02-15T10:05:59.376026Z","shell.execute_reply.started":"2024-02-15T10:05:59.350573Z","shell.execute_reply":"2024-02-15T10:05:59.374452Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"↑ submit（提出）用のファイルとして、'ImageId' と先ほどの予測した 'Label' からなるデータセットをまとめた mysubmission.csv を書き出した","metadata":{}}]}