From a371f3f9536772252d31cf7965e46ab32f801034 Mon Sep 17 00:00:00 2001 From: CharmStrange <105769152+CharmStrange@users.noreply.github.com> Date: Tue, 14 Feb 2023 12:55:55 +0900 Subject: [PATCH 01/99] Delete README.md --- README.md | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index ca2af2f..0000000 --- a/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Study -학습한 것들을 기록합니다. - -- 기초 수학 -- 선형대수학 -- 컴퓨터 과학 -- 프로그래밍 언어 From 3df64d9f9324e74a97fe5c76d809ae8c8c5974e8 Mon Sep 17 00:00:00 2001 From: CharmStrange <105769152+CharmStrange@users.noreply.github.com> Date: Tue, 14 Feb 2023 12:56:02 +0900 Subject: [PATCH 02/99] Delete 1 --- 1 | 1 - 1 file changed, 1 deletion(-) delete mode 100644 1 diff --git a/1 b/1 deleted file mode 100644 index 8b13789..0000000 --- a/1 +++ /dev/null @@ -1 +0,0 @@ - From 52f6f1b31034fd324fe1f9c4f15bed83cd226ee6 Mon Sep 17 00:00:00 2001 From: CharmStrange <105769152+CharmStrange@users.noreply.github.com> Date: Tue, 14 Feb 2023 22:08:29 +0900 Subject: [PATCH 03/99] Numpy Links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 선형대수학에 사용되는 모듈인 Numpy 학습 기록입니다 : Naver Blog --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..b75ca9c --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Study +학습한 것들을 기록합니다. From cfbf532ad8a7a632913df8728dd20254ca231423 Mon Sep 17 00:00:00 2001 From: CharmStrange <105769152+CharmStrange@users.noreply.github.com> Date: Tue, 14 Feb 2023 22:17:41 +0900 Subject: [PATCH 04/99] Update and rename README.md to BlogStudy.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 학습 한, 학습 할 것들이 블로그에 올라옵니다. --- BlogStudy.md | 8 ++++++++ README.md | 2 -- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 BlogStudy.md delete mode 100644 README.md diff --git a/BlogStudy.md b/BlogStudy.md new file mode 100644 index 0000000..d975f22 --- /dev/null +++ b/BlogStudy.md @@ -0,0 +1,8 @@ +# Blog Links : 학습 기록 +--- +* Numpy(1) : +* Numpy(2) : +* Numpy(3) : +* Numpy(4) : +* Numpy(5) : +* Numpy Linear Algebra : diff --git a/README.md b/README.md deleted file mode 100644 index b75ca9c..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Study -학습한 것들을 기록합니다. From c7cce437b8976b217e82b36d8586994e05a3b609 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 7 May 2023 16:29:44 +0900 Subject: [PATCH 05/99] Update BlogStudy.md --- BlogStudy.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BlogStudy.md b/BlogStudy.md index d975f22..543108e 100644 --- a/BlogStudy.md +++ b/BlogStudy.md @@ -1,5 +1,7 @@ # Blog Links : 학습 기록 --- +* 개념과 활용 : +--- * Numpy(1) : * Numpy(2) : * Numpy(3) : From 8957b7284ba5a183bf40bf107a9fc418121afa30 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 7 May 2023 19:02:54 +0900 Subject: [PATCH 06/99] Update BlogStudy.md --- BlogStudy.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/BlogStudy.md b/BlogStudy.md index 543108e..b25f3a0 100644 --- a/BlogStudy.md +++ b/BlogStudy.md @@ -1,4 +1,4 @@ -# Blog Links : 학습 기록 +# Blog : 학습 기록 --- * 개념과 활용 : --- @@ -7,4 +7,7 @@ * Numpy(3) : * Numpy(4) : * Numpy(5) : -* Numpy Linear Algebra : +* Numpy Linear Algebra(1) : +* Numpy Linear Algebra(2) : +* Numpy Linear Algebra(3) : +* Numpy Linear Algebra(4) : From a055d72f9a6ac3043b2c9b9c0a24b31fba9f1fa1 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Tue, 13 Jun 2023 19:13:29 +0900 Subject: [PATCH 07/99] Rename BlogStudy.md to BlogStudy.MD --- BlogStudy.md => BlogStudy.MD | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename BlogStudy.md => BlogStudy.MD (100%) diff --git a/BlogStudy.md b/BlogStudy.MD similarity index 100% rename from BlogStudy.md rename to BlogStudy.MD From 8581dad8092a82caba150cbd7fbce4324bf3f867 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Tue, 13 Jun 2023 19:13:48 +0900 Subject: [PATCH 08/99] Rename BlogStudy.MD to README.md --- BlogStudy.MD => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename BlogStudy.MD => README.md (100%) diff --git a/BlogStudy.MD b/README.md similarity index 100% rename from BlogStudy.MD rename to README.md From 988061d0e67d137846758ef4818104addde8b430 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Tue, 13 Jun 2023 19:14:16 +0900 Subject: [PATCH 09/99] Create README.md --- "\352\270\260\354\264\210/README.md" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "\352\270\260\354\264\210/README.md" diff --git "a/\352\270\260\354\264\210/README.md" "b/\352\270\260\354\264\210/README.md" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/\352\270\260\354\264\210/README.md" @@ -0,0 +1 @@ + From ac5d79da619f033a4d1924660600c3bf6db87039 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Tue, 13 Jun 2023 19:14:33 +0900 Subject: [PATCH 10/99] =?UTF-8?q?Rename=20LinAlg.py=20to=20=EA=B8=B0?= =?UTF-8?q?=EC=B4=88/LinAlg.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LinAlg.py => "\352\270\260\354\264\210/LinAlg.py" | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename LinAlg.py => "\352\270\260\354\264\210/LinAlg.py" (100%) diff --git a/LinAlg.py "b/\352\270\260\354\264\210/LinAlg.py" similarity index 100% rename from LinAlg.py rename to "\352\270\260\354\264\210/LinAlg.py" From acc383283988c93f9fa58ac8be9f9bc0f0683cf7 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Thu, 15 Jun 2023 23:43:06 +0900 Subject: [PATCH 11/99] =?UTF-8?q?Rename=20=EA=B8=B0=EC=B4=88/LinAlg.py=20t?= =?UTF-8?q?o=20=EA=B8=B0=EC=B4=88/Algorithm/LinAlg.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LinAlg.py" => "\352\270\260\354\264\210/Algorithm/LinAlg.py" | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename "\352\270\260\354\264\210/LinAlg.py" => "\352\270\260\354\264\210/Algorithm/LinAlg.py" (100%) diff --git "a/\352\270\260\354\264\210/LinAlg.py" "b/\352\270\260\354\264\210/Algorithm/LinAlg.py" similarity index 100% rename from "\352\270\260\354\264\210/LinAlg.py" rename to "\352\270\260\354\264\210/Algorithm/LinAlg.py" From 6a70270659d28586bceef3922ce2b18e75193b7f Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 16 Jun 2023 00:25:15 +0900 Subject: [PATCH 12/99] Create CNNdimension.py --- .../CNN/CNNdimension.py" | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 "\352\270\260\354\264\210/CNN/CNNdimension.py" diff --git "a/\352\270\260\354\264\210/CNN/CNNdimension.py" "b/\352\270\260\354\264\210/CNN/CNNdimension.py" new file mode 100644 index 0000000..e9fe719 --- /dev/null +++ "b/\352\270\260\354\264\210/CNN/CNNdimension.py" @@ -0,0 +1,62 @@ +import numpy as np +import tensorflow as tf +import matplotlib.pyplot as plt + +# 1D CNN +x_train_1d = np.random.random((100, 10, 1)) +y_train_1d = np.random.randint(2, size=(100, 1)) + +model_1d = tf.keras.Sequential([ + tf.keras.layers.Conv1D(32, 3, activation='relu', input_shape=(10, 1)), + tf.keras.layers.MaxPooling1D(2), + tf.keras.layers.Flatten(), + tf.keras.layers.Dense(1, activation='sigmoid') +]) + +model_1d.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) +model_1d.fit(x_train_1d, y_train_1d, epochs=10) + +plt.plot(model_1d.history.history['accuracy']) +plt.xlabel('Epoch') +plt.ylabel('Accuracy') +plt.show() + + +# 2D CNN +x_train_2d = np.random.random((100, 10, 10, 3)) +y_train_2d = np.random.randint(2, size=(100, 1)) + +model_2d = tf.keras.Sequential([ + tf.keras.layers.Conv2D(32, 3, activation='relu', input_shape=(10, 10, 3)), + tf.keras.layers.MaxPooling2D(2), + tf.keras.layers.Flatten(), + tf.keras.layers.Dense(1, activation='sigmoid') +]) + +model_2d.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) +model_2d.fit(x_train_2d, y_train_2d, epochs=10) + +plt.plot(model_2d.history.history['accuracy']) +plt.xlabel('Epoch') +plt.ylabel('Accuracy') +plt.show() + + +# 3D CNN +x_train_3d = np.random.random((100, 10, 10, 10, 3)) +y_train_3d = np.random.randint(2, size=(100, 1)) + +model_3d = tf.keras.Sequential([ + tf.keras.layers.Conv3D(32, 3, activation='relu', input_shape=(10, 10, 10, 3)), + tf.keras.layers.MaxPooling3D(2), + tf.keras.layers.Flatten(), + tf.keras.layers.Dense(1, activation='sigmoid') +]) + +model_3d.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) +model_3d.fit(x_train_3d, y_train_3d, epochs=10) + +plt.plot(model_3d.history.history['accuracy']) +plt.xlabel('Epoch') +plt.ylabel('Accuracy') +plt.show() From 39ef3f6f36473a30c6995fcf81d633f08fcf46df Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 18 Jun 2023 23:48:42 +0900 Subject: [PATCH 13/99] Create README.md --- DeepLearning/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 DeepLearning/README.md diff --git a/DeepLearning/README.md b/DeepLearning/README.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/DeepLearning/README.md @@ -0,0 +1 @@ + From 3079377ac8085705b202eceaf6593fc41b1f5752 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 18 Jun 2023 23:49:13 +0900 Subject: [PATCH 14/99] Create README.md --- MachineLearning/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 MachineLearning/README.md diff --git a/MachineLearning/README.md b/MachineLearning/README.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/MachineLearning/README.md @@ -0,0 +1 @@ + From 62ca06a14a93de2afad69c4a4803878c76f1aabe Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Mon, 19 Jun 2023 11:21:21 +0900 Subject: [PATCH 15/99] =?UTF-8?q?=EA=B0=9C=EC=9D=B8=20=ED=95=99=EC=8A=B5?= =?UTF-8?q?=20:=20=EB=94=A5=EB=9F=AC=EB=8B=9D=EC=9D=98=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=EC=A0=81=20=EB=AC=B8=EC=A0=9C=EC=A0=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 딥러닝의 문제점과 해결 방안에 대해 직접 찾아보고 공부한 보고서 형식의 기록 파일입니다. --- DeepLearning/Study#1.ipynb | 508 +++++++++++++++++++++++++++++++++++++ 1 file changed, 508 insertions(+) create mode 100644 DeepLearning/Study#1.ipynb diff --git a/DeepLearning/Study#1.ipynb b/DeepLearning/Study#1.ipynb new file mode 100644 index 0000000..ac25d1e --- /dev/null +++ b/DeepLearning/Study#1.ipynb @@ -0,0 +1,508 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "\n", + "# 과거 딥러닝의 근본적 문제점\n", + "\n", + "* 과적합\n", + "* 기울기 소멸\n", + "* 성능 하락" + ], + "metadata": { + "id": "d4BM45MFAQs3" + } + }, + { + "cell_type": "markdown", + "source": [ + "# 문제 발생 원인\n", + "\n", + "* 과적합 - 훈련 데이터를 과도하게 학습하여, 검증/실제 데이터에 대한 오차가 증가함.\n", + "\n", + "* 기울기 소멸 - 은닉층이 많아지다 보면, 오차에 대한 계산도 많아져 오차가 크게 감소, 결국은 이에 대한 기울기가 소멸(0에 수렴)하여 학습이 불가해짐.\n", + "\n", + "* 성능 하락 - 경사 하강법은 오차가 가장 작게 되는 지점을 찾는데, 이 과정에서 시간 낭비, 적합점 탐색 불가, 발산 등의 성능이 하락하는 문제들이 발생." + ], + "metadata": { + "id": "64xguKP5DiBE" + } + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "---\n", + "\n" + ], + "metadata": { + "id": "7l7TGYvtSTrb" + } + }, + { + "cell_type": "markdown", + "source": [ + "# 과적합 문제 해결 방안\n", + "\n", + "* 과적합 - 드롭아웃" + ], + "metadata": { + "id": "wFWcAwpGCaQj" + } + }, + { + "cell_type": "code", + "source": [ + "# 과적합 문제 발생\n", + "\n", + "import numpy as np\n", + "from tensorflow.keras.datasets import mnist\n", + "from tensorflow.keras.models import Sequential\n", + "from tensorflow.keras.layers import Dense\n", + "\n", + "# MNIST 데이터셋 로드\n", + "(x_train, y_train), (x_test, y_test) = mnist.load_data()\n", + "\n", + "# 데이터 전처리\n", + "x_train = x_train.reshape(-1, 784) / 255.0\n", + "x_test = x_test.reshape(-1, 784) / 255.0\n", + "\n", + "# 과적합을 위해 훈련 데이터 증강(의도)\n", + "x_train = np.concatenate((x_train, x_train[:1000]))\n", + "y_train = np.concatenate((y_train, y_train[:1000]))\n", + "\n", + "# 모델 구성\n", + "model = Sequential()\n", + "model.add(Dense(256, activation='relu', input_shape=(784,)))\n", + "model.add(Dense(256, activation='relu'))\n", + "model.add(Dense(10, activation='softmax'))\n", + "\n", + "# 모델 컴파일 및 학습\n", + "model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])\n", + "model.fit(x_train, y_train, batch_size=128, epochs=20, validation_data=(x_test, y_test))" + ], + "metadata": { + "id": "sPHWw2cUADvd" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 이 코드를 추가\n", + "\n", + "from tensorflow.keras.layers import Dropout\n", + "\n", + "# 모델 구성\n", + "model = Sequential()\n", + "model.add(Dense(256, activation='relu', input_shape=(784,)))\n", + "model.add(Dropout(0.5)) # 드롭아웃 층 추가\n", + "model.add(Dense(256, activation='relu'))\n", + "model.add(Dropout(0.5)) # 드롭아웃 층 추가\n", + "model.add(Dense(10, activation='softmax'))" + ], + "metadata": { + "id": "w4Sh2OYdKmuk" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "드롭아웃은 입력된 데이터에 대해 학습하는 과정 중 학습에 사용되는 일부 노드(뉴런)들을 학습에서 제외시켜 과적합을 막을 수 있는 방법이다. 과적합 문제 뿐 아니라 모델이 더욱 향상된 일반화 성능을 가질 수 있게 해 준다." + ], + "metadata": { + "id": "uBMuE2B-K2PH" + } + }, + { + "cell_type": "code", + "source": [ + "# 드롭아웃 구성 예제\n", + "class DropoutModel(torch.nn.Module):\n", + " def __init__(self):\n", + " super(DropoutModel, self).__init__()\n", + " self.layer1 = torch.nn.Linear(784, 1200)\n", + " self.dropout1 = torch.nn.Dropout(0.5) # 50%의 노드를 무작위로 선택하여 사용하지 않겠다는 의미\n", + "\n", + " self.layer2 = torch.nn.Linear(1200, 1200)\n", + " self.dropout2 = torch.nn.Dropout(0.5) # \"\n", + "\n", + " self.layer3 = torch.nn.Linear(1200, 10)\n", + "\n", + " def forward(self, x):\n", + " x = F.relu( self.layer1(x) )\n", + " x = self.dropout1(x)\n", + "\n", + " x = F.relu( self.layer2(x) )\n", + " x = self.dropout2(x)\n", + "\n", + " return self.layer3(x)" + ], + "metadata": { + "id": "df_4_4OFLcBE" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "---\n", + "\n" + ], + "metadata": { + "id": "TDUz-o7eSQWs" + } + }, + { + "cell_type": "markdown", + "source": [ + "# 기울기 소멸 문제 해결 방안\n", + "\n", + "* 기울기 소멸 - ReLU" + ], + "metadata": { + "id": "vDYNED2YJ_lC" + } + }, + { + "cell_type": "code", + "source": [ + "# 시그모이드 함수의 정의\n", + "\n", + "import numpy as np\n", + "\n", + "def sigmoid(x):\n", + " return 1 / (1 + np.exp(-x))" + ], + "metadata": { + "id": "GOoXk1umPxw5" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# PyToch\n", + "\n", + "import torch\n", + "import torch.nn.functional as F\n", + "\n", + "torch.sigmoid(x)" + ], + "metadata": { + "id": "c1F9zF4qT-e7" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "은닉층이 많은 신경망에서, 역전파 과정 중 오차가 0에 수렴하여 가중치에 대한 업데이트가 이루어지지 않는 현상이다." + ], + "metadata": { + "id": "SNWXoDJ1P4zI" + } + }, + { + "cell_type": "markdown", + "source": [ + "주 원인은 활성화 함수로 시그모이드 함수가 사용되기 때문인데, 시그모이드 함수는 0~1 사이의 값을 출력하며, 만약 작은 값이 시그모이드 함수를 사용한 역전파 과정에서 계속 곱해지면 기울기가 점차 감소한다.\n", + "\n", + "그렇기에 시그모이드 함수 대신 렐루 함수를 활성화 함수로 사용하면 이 문제가 해결된다." + ], + "metadata": { + "id": "CGC_ufGERrI2" + } + }, + { + "cell_type": "code", + "source": [ + "# ReLU 함수의 정의\n", + "def relu(x):\n", + " return max(0, x)" + ], + "metadata": { + "id": "bYkvpTkUR8N7" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# PyTorch\n", + "\n", + "import torch\n", + "import torch.nn.functional as F\n", + "\n", + "F.relu(x)" + ], + "metadata": { + "id": "2P1LgOyfUB0E" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "---\n", + "\n" + ], + "metadata": { + "id": "jo7dheOPSUsz" + } + }, + { + "cell_type": "markdown", + "source": [], + "metadata": { + "id": "C9XvVuzdSM1B" + } + }, + { + "cell_type": "markdown", + "source": [ + "# 성능 하락 문제 해결 방안\n", + "\n", + "* 성능 하락 - 확률적 경사 하강법 / 미니 배치 경사 하강법" + ], + "metadata": { + "id": "oyvG5ze_KAa3" + } + }, + { + "cell_type": "code", + "source": [ + "# 일반적인 경사 하강법 알고리즘\n", + "\n", + "def gradient_descent(X, y, learning_rate, num_iterations):\n", + " num_samples, num_features = X.shape\n", + " weights = np.zeros(num_features)\n", + " bias = 0\n", + "\n", + " for _ in range(num_iterations):\n", + " # 예측 계산\n", + " y_pred = np.dot(X, weights) + bias\n", + "\n", + " # 오차 계산\n", + " error = y_pred - y\n", + "\n", + " # 가중치와 편향의 업데이트\n", + " weights -= (learning_rate / num_samples) * np.dot(X.T, error)\n", + " bias -= (learning_rate / num_samples) * np.sum(error)\n", + "\n", + " return weights, bias" + ], + "metadata": { + "id": "ssTNDb-cTHeu" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "경사 하강법은 강력한 알고리즘이지만 지역 최솟값 수렴, 계산 시간 급증, 발산 등의 성능이 하락하는 문제가 발생할 가능성이 있다. 이를 해결하기 위해 미니 배치 경사 하강법, 확률적 경사 하강법 등을 사용한다." + ], + "metadata": { + "id": "R41qdz3-TYWN" + } + }, + { + "cell_type": "markdown", + "source": [ + "## 배치 경사 하강법\n", + "배치 경사 하강법은 Batch, 말 그대로 경사 하강법에 대해 일괄처리를 한다는 뜻이다. 전체 데이터셋에 대한 오류를 계산한 뒤 기울기를 한 번만 계산하여 모델의 파라미터를 업데이트한다." + ], + "metadata": { + "id": "QuRmCUBbUlJ2" + } + }, + { + "cell_type": "code", + "source": [ + "# 배치 경사 하강법 알고리즘\n", + "\n", + "import numpy as np\n", + "\n", + "def batch_gradient_descent(X, y, learning_rate, num_iterations):\n", + " num_samples, num_features = X.shape\n", + " weights = np.zeros(num_features)\n", + " bias = 0\n", + "\n", + " for _ in range(num_iterations):\n", + " # 예측 계산\n", + " y_pred = np.dot(X, weights) + bias\n", + "\n", + " # 오차 계산\n", + " error = y_pred - y\n", + "\n", + " # 가중치와 편향의 업데이트\n", + " weights -= (learning_rate / num_samples) * np.dot(X.T, error)\n", + " bias -= (learning_rate / num_samples) * np.sum(error)\n", + "\n", + " return weights, bias\n" + ], + "metadata": { + "id": "XDR6m0D-UWAA" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 미니 배치 경사 하강법\n", + "배치 경사 하강법과 개념적으로는 비슷하지만, 일괄처리하는 묶음을 여러 개로 쪼갠다는 차이점이 있다. 즉, 전체 데이터셋을 미니 배치 여러 개로 나누고 각각의 미니 배치에 대한 일괄 처리 계산 후 그것들의 평균 기울기를 사용해 모델의 파라미터를 업데이트한다." + ], + "metadata": { + "id": "RmE8aTcAVrtW" + } + }, + { + "cell_type": "code", + "source": [ + "# 미니 배치 경사 하강법 알고리즘\n", + "\n", + "import numpy as np\n", + "\n", + "def mini_batch_gradient_descent(X, y, learning_rate, batch_size, num_iterations):\n", + " num_samples, num_features = X.shape\n", + " weights = np.zeros(num_features)\n", + " bias = 0\n", + "\n", + " for _ in range(num_iterations):\n", + " # 배치 샘플 선택\n", + " indices = np.random.choice(num_samples, batch_size, replace=False)\n", + " X_batch = X[indices]\n", + " y_batch = y[indices]\n", + "\n", + " # 예측 계산\n", + " y_pred = np.dot(X_batch, weights) + bias\n", + "\n", + " # 오차 계산\n", + " error = y_pred - y_batch\n", + "\n", + " # 가중치와 편향의 업데이트\n", + " weights -= (learning_rate / batch_size) * np.dot(X_batch.T, error)\n", + " bias -= (learning_rate / batch_size) * np.sum(error)\n", + "\n", + " return weights, bias\n" + ], + "metadata": { + "id": "KK3n44LxWDu8" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 미니 배치 경사 하강법 구성 예제\n", + "\n", + "class CustomDataset(Dataset):\n", + " def __init__(self):\n", + " self.x_data = [ [1,2,3], [4,5,6], [7,8,9] ]\n", + " self.y_data = [ [12], [18], [11] ]\n", + "\n", + " def __len__(self):\n", + " return len(self.x_data)\n", + "\n", + " def __getitem__(self, idx):\n", + " x = torch.FloatTensor(self.x_data[idx])\n", + " y = torch.FloatTensor(self.y_data[idx])\n", + " return x, y\n", + "\n", + "dataset = CustomDataset()\n", + "dataloader = DataLoader( dataset, batch_size=2, shuffle=True )" + ], + "metadata": { + "id": "-2UHmKyoWPCF" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## 확률적 경사 하강법\n", + "확률적 경사 하강법은 임의로 선택한 데이터에 대해 기울기를 계산하고 가중치와 편향을 업데이트한다." + ], + "metadata": { + "id": "-46wfi2FYVi3" + } + }, + { + "cell_type": "code", + "source": [ + "# 확률적 경사 하강법 알고리즘\n", + "\n", + "import numpy as np\n", + "\n", + "def stochastic_gradient_descent(X, y, learning_rate, num_iterations):\n", + " num_samples, num_features = X.shape\n", + " weights = np.zeros(num_features)\n", + " bias = 0\n", + "\n", + " for _ in range(num_iterations):\n", + " # 무작위로 훈련 샘플 선택\n", + " index = np.random.randint(num_samples)\n", + " x = X[index]\n", + " label = y[index]\n", + "\n", + " # 예측 계산\n", + " y_pred = np.dot(x, weights) + bias\n", + "\n", + " # 오차 계산\n", + " error = y_pred - label\n", + "\n", + " # 가중치와 편향의 업데이트\n", + " weights -= learning_rate * error * x\n", + " bias -= learning_rate * error\n", + "\n", + " return weights, bias\n" + ], + "metadata": { + "id": "fqEVVJ9NcEjT" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "확률적 경사 하강법은 무작위로 하나의 훈련 샘플을 선택해 연산을 진행하기 때문에 파라미터의 변경 폭이 불안정하나 속도가 비교적 빠르다." + ], + "metadata": { + "id": "cETWRxExcVs3" + } + } + ] +} \ No newline at end of file From 1532fda697189d8b430b663fc421966d693ea01a Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Mon, 19 Jun 2023 12:29:55 +0900 Subject: [PATCH 16/99] Update : optimizer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 확률적 경사 하강법에 optimizer 내용을 추가하였습니다. --- DeepLearning/Study#1++.ipynb | 681 +++++++++++++++++++++++++++++++++++ 1 file changed, 681 insertions(+) create mode 100644 DeepLearning/Study#1++.ipynb diff --git a/DeepLearning/Study#1++.ipynb b/DeepLearning/Study#1++.ipynb new file mode 100644 index 0000000..6a4c44b --- /dev/null +++ b/DeepLearning/Study#1++.ipynb @@ -0,0 +1,681 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "\n", + "# 과거 딥러닝의 근본적 문제점\n", + "\n", + "* 과적합\n", + "* 기울기 소멸\n", + "* 성능 하락" + ], + "metadata": { + "id": "d4BM45MFAQs3" + } + }, + { + "cell_type": "markdown", + "source": [ + "# 문제 발생 원인\n", + "\n", + "* 과적합 - 훈련 데이터를 과도하게 학습하여, 검증/실제 데이터에 대한 오차가 증가함.\n", + "\n", + "* 기울기 소멸 - 은닉층이 많아지다 보면, 오차에 대한 계산도 많아져 오차가 크게 감소, 결국은 이에 대한 기울기가 소멸(0에 수렴)하여 학습이 불가해짐.\n", + "\n", + "* 성능 하락 - 경사 하강법은 오차가 가장 작게 되는 지점을 찾는데, 이 과정에서 시간 낭비, 적합점 탐색 불가, 발산 등의 성능이 하락하는 문제들이 발생." + ], + "metadata": { + "id": "64xguKP5DiBE" + } + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "---\n", + "\n" + ], + "metadata": { + "id": "7l7TGYvtSTrb" + } + }, + { + "cell_type": "markdown", + "source": [ + "# 과적합 문제 해결 방안\n", + "\n", + "* 과적합 - 드롭아웃" + ], + "metadata": { + "id": "wFWcAwpGCaQj" + } + }, + { + "cell_type": "code", + "source": [ + "# 과적합 문제 발생\n", + "\n", + "import numpy as np\n", + "from tensorflow.keras.datasets import mnist\n", + "from tensorflow.keras.models import Sequential\n", + "from tensorflow.keras.layers import Dense\n", + "\n", + "# MNIST 데이터셋 로드\n", + "(x_train, y_train), (x_test, y_test) = mnist.load_data()\n", + "\n", + "# 데이터 전처리\n", + "x_train = x_train.reshape(-1, 784) / 255.0\n", + "x_test = x_test.reshape(-1, 784) / 255.0\n", + "\n", + "# 과적합을 위해 훈련 데이터 증강(의도)\n", + "x_train = np.concatenate((x_train, x_train[:1000]))\n", + "y_train = np.concatenate((y_train, y_train[:1000]))\n", + "\n", + "# 모델 구성\n", + "model = Sequential()\n", + "model.add(Dense(256, activation='relu', input_shape=(784,)))\n", + "model.add(Dense(256, activation='relu'))\n", + "model.add(Dense(10, activation='softmax'))\n", + "\n", + "# 모델 컴파일 및 학습\n", + "model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])\n", + "model.fit(x_train, y_train, batch_size=128, epochs=20, validation_data=(x_test, y_test))" + ], + "metadata": { + "id": "sPHWw2cUADvd" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 이 코드를 추가\n", + "\n", + "from tensorflow.keras.layers import Dropout\n", + "\n", + "# 모델 구성\n", + "model = Sequential()\n", + "model.add(Dense(256, activation='relu', input_shape=(784,)))\n", + "model.add(Dropout(0.5)) # 드롭아웃 층 추가\n", + "model.add(Dense(256, activation='relu'))\n", + "model.add(Dropout(0.5)) # 드롭아웃 층 추가\n", + "model.add(Dense(10, activation='softmax'))" + ], + "metadata": { + "id": "w4Sh2OYdKmuk" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "드롭아웃은 입력된 데이터에 대해 학습하는 과정 중 학습에 사용되는 일부 노드(뉴런)들을 학습에서 제외시켜 과적합을 막을 수 있는 방법이다. 과적합 문제 뿐 아니라 모델이 더욱 향상된 일반화 성능을 가질 수 있게 해 준다." + ], + "metadata": { + "id": "uBMuE2B-K2PH" + } + }, + { + "cell_type": "code", + "source": [ + "# 드롭아웃 구성 예제\n", + "class DropoutModel(torch.nn.Module):\n", + " def __init__(self):\n", + " super(DropoutModel, self).__init__()\n", + " self.layer1 = torch.nn.Linear(784, 1200)\n", + " self.dropout1 = torch.nn.Dropout(0.5) # 50%의 노드를 무작위로 선택하여 사용하지 않겠다는 의미\n", + "\n", + " self.layer2 = torch.nn.Linear(1200, 1200)\n", + " self.dropout2 = torch.nn.Dropout(0.5) # \"\n", + "\n", + " self.layer3 = torch.nn.Linear(1200, 10)\n", + "\n", + " def forward(self, x):\n", + " x = F.relu( self.layer1(x) )\n", + " x = self.dropout1(x)\n", + "\n", + " x = F.relu( self.layer2(x) )\n", + " x = self.dropout2(x)\n", + "\n", + " return self.layer3(x)" + ], + "metadata": { + "id": "df_4_4OFLcBE" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "---\n", + "\n" + ], + "metadata": { + "id": "TDUz-o7eSQWs" + } + }, + { + "cell_type": "markdown", + "source": [ + "# 기울기 소멸 문제 해결 방안\n", + "\n", + "* 기울기 소멸 - ReLU" + ], + "metadata": { + "id": "vDYNED2YJ_lC" + } + }, + { + "cell_type": "code", + "source": [ + "# 시그모이드 함수의 정의\n", + "\n", + "import numpy as np\n", + "\n", + "def sigmoid(x):\n", + " return 1 / (1 + np.exp(-x))" + ], + "metadata": { + "id": "GOoXk1umPxw5" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# PyToch\n", + "\n", + "import torch\n", + "import torch.nn.functional as F\n", + "\n", + "torch.sigmoid(x)" + ], + "metadata": { + "id": "c1F9zF4qT-e7" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "은닉층이 많은 신경망에서, 역전파 과정 중 오차가 0에 수렴하여 가중치에 대한 업데이트가 이루어지지 않는 현상이다." + ], + "metadata": { + "id": "SNWXoDJ1P4zI" + } + }, + { + "cell_type": "markdown", + "source": [ + "주 원인은 활성화 함수로 시그모이드 함수가 사용되기 때문인데, 시그모이드 함수는 0~1 사이의 값을 출력하며, 만약 작은 값이 시그모이드 함수를 사용한 역전파 과정에서 계속 곱해지면 기울기가 점차 감소한다.\n", + "\n", + "그렇기에 시그모이드 함수 대신 렐루 함수를 활성화 함수로 사용하면 이 문제가 해결된다." + ], + "metadata": { + "id": "CGC_ufGERrI2" + } + }, + { + "cell_type": "code", + "source": [ + "# ReLU 함수의 정의\n", + "def relu(x):\n", + " return max(0, x)" + ], + "metadata": { + "id": "bYkvpTkUR8N7" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# PyTorch\n", + "\n", + "import torch\n", + "import torch.nn.functional as F\n", + "\n", + "F.relu(x)" + ], + "metadata": { + "id": "2P1LgOyfUB0E" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "---\n", + "\n" + ], + "metadata": { + "id": "jo7dheOPSUsz" + } + }, + { + "cell_type": "markdown", + "source": [], + "metadata": { + "id": "C9XvVuzdSM1B" + } + }, + { + "cell_type": "markdown", + "source": [ + "# 성능 하락 문제 해결 방안\n", + "\n", + "* 성능 하락 - 확률적 경사 하강법 / 미니 배치 경사 하강법" + ], + "metadata": { + "id": "oyvG5ze_KAa3" + } + }, + { + "cell_type": "code", + "source": [ + "# 일반적인 경사 하강법 알고리즘\n", + "\n", + "def gradient_descent(X, y, learning_rate, num_iterations):\n", + " num_samples, num_features = X.shape\n", + " weights = np.zeros(num_features)\n", + " bias = 0\n", + "\n", + " for _ in range(num_iterations):\n", + " # 예측 계산\n", + " y_pred = np.dot(X, weights) + bias\n", + "\n", + " # 오차 계산\n", + " error = y_pred - y\n", + "\n", + " # 가중치와 편향의 업데이트\n", + " weights -= (learning_rate / num_samples) * np.dot(X.T, error)\n", + " bias -= (learning_rate / num_samples) * np.sum(error)\n", + "\n", + " return weights, bias" + ], + "metadata": { + "id": "ssTNDb-cTHeu" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "경사 하강법은 강력한 알고리즘이지만 지역 최솟값 수렴, 계산 시간 급증, 발산 등의 성능이 하락하는 문제가 발생할 가능성이 있다. 이를 해결하기 위해 미니 배치 경사 하강법, 확률적 경사 하강법 등을 사용한다." + ], + "metadata": { + "id": "R41qdz3-TYWN" + } + }, + { + "cell_type": "markdown", + "source": [ + "## 배치 경사 하강법\n", + "배치 경사 하강법은 Batch, 말 그대로 경사 하강법에 대해 일괄처리를 한다는 뜻이다. 전체 데이터셋에 대한 오류를 계산한 뒤 기울기를 한 번만 계산하여 모델의 파라미터를 업데이트한다." + ], + "metadata": { + "id": "QuRmCUBbUlJ2" + } + }, + { + "cell_type": "code", + "source": [ + "# 배치 경사 하강법 알고리즘\n", + "\n", + "import numpy as np\n", + "\n", + "def batch_gradient_descent(X, y, learning_rate, num_iterations):\n", + " num_samples, num_features = X.shape\n", + " weights = np.zeros(num_features)\n", + " bias = 0\n", + "\n", + " for _ in range(num_iterations):\n", + " # 예측 계산\n", + " y_pred = np.dot(X, weights) + bias\n", + "\n", + " # 오차 계산\n", + " error = y_pred - y\n", + "\n", + " # 가중치와 편향의 업데이트\n", + " weights -= (learning_rate / num_samples) * np.dot(X.T, error)\n", + " bias -= (learning_rate / num_samples) * np.sum(error)\n", + "\n", + " return weights, bias\n" + ], + "metadata": { + "id": "XDR6m0D-UWAA" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 미니 배치 경사 하강법\n", + "배치 경사 하강법과 개념적으로는 비슷하지만, 일괄처리하는 묶음을 여러 개로 쪼갠다는 차이점이 있다. 즉, 전체 데이터셋을 미니 배치 여러 개로 나누고 각각의 미니 배치에 대한 일괄 처리 계산 후 그것들의 평균 기울기를 사용해 모델의 파라미터를 업데이트한다." + ], + "metadata": { + "id": "RmE8aTcAVrtW" + } + }, + { + "cell_type": "code", + "source": [ + "# 미니 배치 경사 하강법 알고리즘\n", + "\n", + "import numpy as np\n", + "\n", + "def mini_batch_gradient_descent(X, y, learning_rate, batch_size, num_iterations):\n", + " num_samples, num_features = X.shape\n", + " weights = np.zeros(num_features)\n", + " bias = 0\n", + "\n", + " for _ in range(num_iterations):\n", + " # 배치 샘플 선택\n", + " indices = np.random.choice(num_samples, batch_size, replace=False)\n", + " X_batch = X[indices]\n", + " y_batch = y[indices]\n", + "\n", + " # 예측 계산\n", + " y_pred = np.dot(X_batch, weights) + bias\n", + "\n", + " # 오차 계산\n", + " error = y_pred - y_batch\n", + "\n", + " # 가중치와 편향의 업데이트\n", + " weights -= (learning_rate / batch_size) * np.dot(X_batch.T, error)\n", + " bias -= (learning_rate / batch_size) * np.sum(error)\n", + "\n", + " return weights, bias\n" + ], + "metadata": { + "id": "KK3n44LxWDu8" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 미니 배치 경사 하강법 구성 예제\n", + "\n", + "class CustomDataset(Dataset):\n", + " def __init__(self):\n", + " self.x_data = [ [1,2,3], [4,5,6], [7,8,9] ]\n", + " self.y_data = [ [12], [18], [11] ]\n", + "\n", + " def __len__(self):\n", + " return len(self.x_data)\n", + "\n", + " def __getitem__(self, idx):\n", + " x = torch.FloatTensor(self.x_data[idx])\n", + " y = torch.FloatTensor(self.y_data[idx])\n", + " return x, y\n", + "\n", + "dataset = CustomDataset()\n", + "dataloader = DataLoader( dataset, batch_size=2, shuffle=True )" + ], + "metadata": { + "id": "-2UHmKyoWPCF" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## 확률적 경사 하강법\n", + "확률적 경사 하강법은 임의로 선택한 데이터에 대해 기울기를 계산하고 가중치와 편향을 업데이트한다." + ], + "metadata": { + "id": "-46wfi2FYVi3" + } + }, + { + "cell_type": "code", + "source": [ + "# 확률적 경사 하강법 알고리즘\n", + "\n", + "import numpy as np\n", + "\n", + "def stochastic_gradient_descent(X, y, learning_rate, num_iterations):\n", + " num_samples, num_features = X.shape\n", + " weights = np.zeros(num_features)\n", + " bias = 0\n", + "\n", + " for _ in range(num_iterations):\n", + " # 무작위로 훈련 샘플 선택\n", + " index = np.random.randint(num_samples)\n", + " x = X[index]\n", + " label = y[index]\n", + "\n", + " # 예측 계산\n", + " y_pred = np.dot(x, weights) + bias\n", + "\n", + " # 오차 계산\n", + " error = y_pred - label\n", + "\n", + " # 가중치와 편향의 업데이트\n", + " weights -= learning_rate * error * x\n", + " bias -= learning_rate * error\n", + "\n", + " return weights, bias\n" + ], + "metadata": { + "id": "fqEVVJ9NcEjT" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "import torch.optim as optim\n", + "...\n", + "model = LinearModel()\n", + "criterion = nn.MSELoss()\n", + "\n", + "# 확률적 경사 하강법\n", + "optimizer = optim.SGD(model.parameters(), lr=0.01) # 학습률은 0.01로 설정\n" + ], + "metadata": { + "id": "6RcjsyjrpseA" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "확률적 경사 하강법은 무작위로 하나의 훈련 샘플을 선택해 연산을 진행하기 때문에 파라미터의 변경 폭이 불안정하나 속도가 비교적 빠르다." + ], + "metadata": { + "id": "cETWRxExcVs3" + } + }, + { + "cell_type": "markdown", + "source": [ + "### 확률적 경사 하강법의 옵티마이저\n", + "확률적 경사 하강법의 파라미터 변경 폭이 불안정한 문제를 해결하고자 도입한, 학습 속도와 운동량을 조절해주는 옵티마이저.\n", + "\n", + "* 운동량 개선\n", + "\n", + " > 모멘텀\n", + "\n", + " > 네스테로프 모멘텀\n", + "\n", + "* 속도 개선\n", + "\n", + " > 아다그라드\n", + "\n", + " > 아다델타\n", + "\n", + " > 알엠에스프롭\n", + "\n", + " > 아담" + ], + "metadata": { + "id": "46KF3Ti2myGk" + } + }, + { + "cell_type": "code", + "source": [ + "# 모멘텀\n", + "...\n", + "optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9) # 모멘텀은 0.9부터" + ], + "metadata": { + "id": "7WQ_URVrnBMe" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 네스테로프 모멘텀\n", + "...\n", + "optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=True) # 네스테로프 허용" + ], + "metadata": { + "id": "oFfnibIep8tI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 아다그라드\n", + "...\n", + "optimizer = torch.optim.Adagrad(model.parameters(), lr=0.01)" + ], + "metadata": { + "id": "vxPacHWJp_Nq" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 아다델타\n", + "...\n", + "optimizer = torch.optim.Adadelta(model.parameters(), lr=1.0)" + ], + "metadata": { + "id": "x2vzKDBtqBYt" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 알엠에스프롭\n", + "...\n", + "optimizer = torch.optim.RMSprop(model.parameters(), lr=0.01)" + ], + "metadata": { + "id": "yi97Am0wqGk8" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 아담 : 모멘텀과 알엠에스프롭의 장점을 결합한 경사 하강법\n", + "\n", + " # 아담 수학적 알고리즘\n", + "import torch\n", + "\n", + "def adam_update(parameters, gradients, m, v, beta1=0.9, beta2=0.999, epsilon=1e-8, learning_rate=0.001, t=0):\n", + " for param, grad in zip(parameters, gradients):\n", + " # 1차 및 2차 모멘트 계산\n", + " m[param] = beta1 * m[param] + (1 - beta1) * grad\n", + " v[param] = beta2 * v[param] + (1 - beta2) * grad**2\n", + "\n", + " # 모멘트 보정\n", + " m_hat = m[param] / (1 - beta1**(t+1))\n", + " v_hat = v[param] / (1 - beta2**(t+1))\n", + "\n", + " # 가중치 업데이트\n", + " param.data -= learning_rate * m_hat / (torch.sqrt(v_hat) + epsilon)\n", + "\n", + "# 모델 파라미터 및 모멘트 초기화\n", + "parameters = model.parameters()\n", + "m = {param: torch.zeros_like(param) for param in parameters}\n", + "v = {param: torch.zeros_like(param) for param in parameters}\n", + "\n", + "# 학습 루프\n", + "for t in range(num_epochs):\n", + " optimizer.zero_grad()\n", + " outputs = model(inputs)\n", + " loss = criterion(outputs, targets)\n", + " loss.backward()\n", + "\n", + " # Adam 업데이트\n", + " adam_update(parameters, [param.grad for param in parameters], m, v, t=t)\n", + "\n" + ], + "metadata": { + "id": "RTyFYHdOqIIj" + }, + "execution_count": 1, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "아담 알고리즘 : 모델의 초기 가중치와 모멘텀을 설정한다. 각 반복마다 모델의 가중치에 대한 그래디언트를 계산한다. 모멘텀을 업데이트하고 그래디언트에 대한 이동 평균을 계산한다. 학습률을 조정하고 가중치를 업데이트한다. 2~4단계를 반복하며 모델을 학습시킨다." + ], + "metadata": { + "id": "ZihqReVGsDAx" + } + }, + { + "cell_type": "code", + "source": [ + "optimizer = torch.optim.Adam(model.parameters(), lr=0.01)" + ], + "metadata": { + "id": "Wn7eqjSosSOe" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file From 355cfd18336b48bf19bad9e7f8ea506b8b589159 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Wed, 21 Jun 2023 11:27:05 +0900 Subject: [PATCH 17/99] =?UTF-8?q?=EA=B2=B0=EC=B8=A1=EC=B9=98=20=EC=98=88?= =?UTF-8?q?=EC=B8=A1/=EB=8C=80=EC=B2=B4=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MachineLearning/missingvalueimputation.ipynb | 1 + 1 file changed, 1 insertion(+) create mode 100644 MachineLearning/missingvalueimputation.ipynb diff --git a/MachineLearning/missingvalueimputation.ipynb b/MachineLearning/missingvalueimputation.ipynb new file mode 100644 index 0000000..2df76c9 --- /dev/null +++ b/MachineLearning/missingvalueimputation.ipynb @@ -0,0 +1 @@ +{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.10","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 데이터에 누락된 값이 있을 때 이를 채우거나 값을 예측하기","metadata":{}},{"cell_type":"markdown","source":"***pip install fancyimpute***","metadata":{}},{"cell_type":"code","source":"# 1\nimport numpy as np\nfrom fancyimpute import KNN\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.datasets import make_blobs\n\n# 모의 특성 행렬\nfeatures, _ = make_blobs(n_samples=1000, n_features=2, random_state=1)\n\n# 특성 표준화\nscaler = StandardScaler()\nstandardized_features = scaler.fit_transform(features)\n\n# 첫 번째 샘플의 첫 번째 특성을 삭제\ntrue_value = standardized_features[0,0]\nstandardized_features[0,0]=np.nan\n\n# 특성 행렬에 있는 누락된 값 예측\nfatures_knn_imputed = KNN(k=5, verbose=0).fit_transform(standardized_features)\n\n# 실제 값과 예측된 값 비교\nprint(\"실제 값 : \", true_value)\nprint(\"예측 값 : \", fatures_knn_imputed[0,0])","metadata":{"execution":{"iopub.status.busy":"2023-06-21T02:21:36.600409Z","iopub.execute_input":"2023-06-21T02:21:36.600764Z","iopub.status.idle":"2023-06-21T02:21:36.741717Z","shell.execute_reply.started":"2023-06-21T02:21:36.600742Z","shell.execute_reply":"2023-06-21T02:21:36.739885Z"},"trusted":true},"execution_count":17,"outputs":[{"name":"stdout","text":"실제 값 : 0.8730186113995938\n예측 값 : 1.0955332713113226\n","output_type":"stream"}]},{"cell_type":"code","source":"#2\nfrom sklearn.impute import SimpleImputer\n\nsimple_imputer = SimpleImputer()\nfeatures_simple_imputed = simple_imputer.fit_transform(features)\n\n# 실제 값과 대체된 값 비교\nprint(\"실제 값 : \", true_value)\nprint(\"대체 값 : \", features_simple_imputed[0,0])","metadata":{"execution":{"iopub.status.busy":"2023-06-21T02:18:30.167876Z","iopub.execute_input":"2023-06-21T02:18:30.168286Z","iopub.status.idle":"2023-06-21T02:18:30.177864Z","shell.execute_reply.started":"2023-06-21T02:18:30.168256Z","shell.execute_reply":"2023-06-21T02:18:30.176676Z"},"trusted":true},"execution_count":16,"outputs":[{"name":"stdout","text":"실제 값 : 0.8730186113995938\n예측 값 : -3.058372724614996\n","output_type":"stream"}]}]} \ No newline at end of file From 09aea2a0370ac260dae6469700cb9d05283529ce Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Mon, 26 Jun 2023 17:43:24 +0900 Subject: [PATCH 18/99] basic iris KNN --- MachineLearning/basicKNN.ipynb | 209 +++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 MachineLearning/basicKNN.ipynb diff --git a/MachineLearning/basicKNN.ipynb b/MachineLearning/basicKNN.ipynb new file mode 100644 index 0000000..1f5409a --- /dev/null +++ b/MachineLearning/basicKNN.ipynb @@ -0,0 +1,209 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# K-최근접 이웃(KNN)\n", + "KNN은 널리 쓰이는 지도 학습 머신 러닝 모델이며 특정 샘플 주위의 샘플들의 클래스를 고려하여 특정 샘플의 클래스를 예측한다.\n", + "장점으로는 단순한 알고리즘, 사전 학습 및 준비 과정이 필요하지 않다는 점이 있다." + ], + "metadata": { + "id": "9N8D5hSjyOfS" + } + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "PxKOEQOayMT-", + "outputId": "1e9531bd-70bb-4895-e8aa-62712547335f" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "array([[[1.03800476, 0.55861082, 1.10378283, 1.18556721],\n", + " [0.79566902, 0.32841405, 0.76275827, 1.05393502]]])" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "source": [ + "# 특정 샘플에서 가장 가까운 K개의 샘플(이웃) 찾기\n", + "# 가장 간단한 예시 코드\n", + "\n", + "from sklearn import datasets\n", + "from sklearn.neighbors import NearestNeighbors\n", + "from sklearn.preprocessing import StandardScaler\n", + "\n", + "# 데이터셋 가져오기\n", + "iris = datasets.load_iris()\n", + "features = iris.data\n", + "\n", + "# 표준화 객체 만들기\n", + "standardizer = StandardScaler()\n", + "\n", + "# 특성 표준화하기\n", + "features_standardized = standardizer.fit_transform(features)\n", + "\n", + "# K=2인 최근접 이웃 모델 만들기\n", + "nearest_neighbors = NearestNeighbors(n_neighbors=2).fit(features_standardized)\n", + "\n", + "# 새로운 샘플을 만들기\n", + "new_observation = [1, 1, 1, 1]\n", + "\n", + "# 이 샘플과 가장 가까운 이웃의 인덱스와 거리를 찾기\n", + "distance, indices = nearest_neighbors.kneighbors( [new_observation] )\n", + "\n", + "# 최근접 이웃을 확인\n", + "features_standardized[indices]" + ] + }, + { + "cell_type": "code", + "source": [ + "from sklearn.model_selection import train_test_split\n", + "from sklearn.neighbors import KNeighborsClassifier\n", + "import pandas as pd\n", + "\n", + "iris_df = pd.DataFrame(iris.data, columns=iris.feature_names)\n", + "iris_df['target'] = pd.Series(iris.target)\n", + "\n", + "X = iris_df.iloc[:, :4]\n", + "y = iris_df.iloc[:, -1]\n", + "\n", + "def iris_KNN(X, y, K):\n", + " X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)\n", + " KNN = KNeighborsClassifier(n_neighbors=K)\n", + " KNN.fit(X_train, y_train)\n", + " y_pred = KNN.predict(X_test)\n", + " return metrics.accuracy_score(y_test, y_pred)\n", + "\n", + "K = 3\n", + "scores = iris_KNN(X, y, K)\n", + "print( 'n_neighbors가 {0:d}일때 정확도 : {1:.3f}'.format(K, scores) )" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "FHHKTMkCcfpg", + "outputId": "a7c679d0-e35e-428f-9fd8-2acac77c41c3" + }, + "execution_count": 16, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "n_neighbors가 3일때 정확도 : 0.978\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "from sklearn import metrics\n", + "\n", + "KNN = KNeighborsClassifier(n_neighbors=K)\n", + "KNN.fit(iris.data, iris.target)\n", + "classes = { 0:'setosa', 1:'versicolor', 2:'virginica' }\n", + "\n", + "# 새로운 데이터\n", + "X = [ [4,2,1.3,0.4], [4,3,3.2,2.2] ]\n", + "y = KNN.predict(X)\n", + "\n", + "print( '{}특성을 가지는 품종 : {}'.format( X[0], classes[y[0]] ) )\n", + "print( '{}특성을 가지는 품종 : {}'.format( X[1], classes[y[1]] ) )\n", + "\n", + "y_pred_all = KNN.predict(iris.data)\n", + "scores = metrics.accuracy_score(iris.target, y_pred_all)\n", + "print( 'n_neighbors가 {0:d}일때 정확도 : {1:.3f}'.format(K, scores) )" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "bQotmF89obuI", + "outputId": "2e282315-34d7-420d-93e9-390ebfaa792a" + }, + "execution_count": 18, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[4, 2, 1.3, 0.4]특성을 가지는 품종 : setosa\n", + "[4, 3, 3.2, 2.2]특성을 가지는 품종 : versicolor\n", + "n_neighbors가 3일때 정확도 : 0.960\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import matplotlib.pyplot as plt\n", + "from sklearn.metrics import confusion_matrix\n", + "\n", + "plt.hist2d(iris.target, y_pred_all, bins=(3,3), cmap=plt.cm.jet)\n", + "conf_mat = confusion_matrix(iris.target, y_pred_all)\n", + "conf_mat" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 491 + }, + "id": "YqUeFb1ZyLtQ", + "outputId": "d6057fb8-d9a9-4e0e-feaf-59e99fe6149a" + }, + "execution_count": 20, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "array([[50, 0, 0],\n", + " [ 0, 47, 3],\n", + " [ 0, 3, 47]])" + ] + }, + "metadata": {}, + "execution_count": 20 + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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q1mzZkWMd/bz3RotPb6DwaC+//77i/LYuRQ899xzqqur01133RUe83g8Ki4uVklJiV5++WVVVlbq9ttv18mTJztwpRcmKSlJRUVFevPNN/Xmm28qJSVFY8aM0e7duyVdnH8rO7tvvvlGf/7zn5s8vi+l893Y2Kh58+bpF7/4hW688cYW69rr93fU342FzmnhwoVatWqVysrKIi7WnTp1avjPw4YNU1pamq699lqVlZXpjjvu6IilXrDMzMyIL4kdOXKk/u7v/k6///3v9dRTT3XgytrP0qVLNWzYMI0YMSJi3MbzDemNN97Qk08+qQ0bNkRcu5KVlRX+c1pamjwej/r37681a9Zo5syZHbHUCzZ48GANHjw4fHvkyJE6ePCgFi9erD/84Q8duLL2s3z5cvXq1avJ90NeSud77ty52rt3b6e5pqjTPbPTt29fxcTEqLq6OmK8urpabre72WPcbvdZ68/8N5o521tr+j7jueee08KFC/Xee+8pLS3trLUDBw5U3759deDAgQte88VwIX2fccUVV+imm24K92T7+Q6FQlq1atV5/ePW2c53a7T0+I6Pj1e3bt0uys9QZ7Zq1SrNmjVLa9asafJ0/8/16tVL119//SV9vpszYsSIcE+2n29jjJYtW6Z7771XsbGxZ63trOf7gQce0Ntvv60PP/xQV1999Vlr2+v3d6cLO7GxsRo+fLhKS0vDY42NjSotLY34v/mfyszMjKiXpE2bNoXrU1NT5Xa7I2qCwaC2b9/e4pztrTV9Sz9epf7UU0+ppKREt9xyyznv58iRIzpx4oSSkpIuyrovVGv7/qmGhgZ9+umn4Z5sPt/Sj2/TrK+v1z333HPO++ls57s1zvX4vhg/Q53VypUrlZOTo5UrV0Z8xEBL6urqdPDgwUv6fDenoqIi3JPN51v68R1NBw4cOK//mels59sYowceeEDr1q3TBx98oNTU1HMe026/v6O6tLqdrFq1yjidTlNcXGz+53/+x9x///2mV69eJhAIGGOMuffee838+fPD9R999JHp2rWree6558znn39u8vPzzRVXXGE+/fTTcM3ChQtNr169zIYNG8wnn3xiJk+ebFJTU83333/f7v21JNq+Fy5caGJjY81//dd/maqqqvB28uRJY4wxJ0+eNA8//LApLy83lZWV5v333zc333yzGTRokDl16lSH9NicaPt+8sknzbvvvmsOHjxodu3aZaZOnWri4uLMZ599Fq6x8XyfMWrUKDNlypQm45fK+T558qTZs2eP2bNnj5Fknn/+ebNnzx7z1VdfGWOMmT9/vrn33nvD9X/5y19M9+7dzSOPPGI+//xzU1hYaGJiYkxJSUm45lx/l51BtH3/6U9/Ml27djWFhYURj++amppwzUMPPWTKyspMZWWl+eijj4zX6zV9+/Y1R48ebff+WhJt34sXLzbr1683+/fvN59++ql58MEHTZcuXcz7778frrHxfJ9xzz33GI/H0+ycnf18z5kzx7hcLlNWVhbxM/vdd9+Fazrq93enDDvGGPOf//mf5pprrjGxsbFmxIgRZtu2beF9o0ePNjNmzIioX7Nmjbn++utNbGysGTp0qHnnnXci9jc2NponnnjCJCYmGqfTae644w6zb9++9mglKtH03b9/fyOpyZafn2+MMea7774z48ePN/369TNXXHGF6d+/v5k9e3an+gfhjGj6njdvXrg2MTHR/OpXvzK7d++OmM/G822MMV988YWRZN57770mc10q5/vMW4t/vp3pdcaMGWb06NFNjsnIyDCxsbFm4MCB5vXXX28y79n+LjuDaPsePXr0WeuN+fEt+ElJSSY2NtZcddVVZsqUKebAgQPt29g5RNv3M888Y6699loTFxdn+vTpY8aMGWM++OCDJvPadr6N+fEt1d26dTOvvPJKs3N29vPdXL+SIh6vHfX72/F/CwQAALBSp7tmBwAA4GIi7AAAAKsRdgAAgNUIOwAAwGqEHQAAYDXCDgAAsBphBwAAWI2wAwAArEbYAQAAViPsAAAAqxF2AACA1f4/jhLZK+UGfIAAAAAASUVORK5CYII=\n" + }, + "metadata": {} + } + ] + } + ] +} \ No newline at end of file From 8ff395b77bb6c21899d135b470d68d9c2ae5b325 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Wed, 28 Jun 2023 12:02:31 +0900 Subject: [PATCH 19/99] Delete README.md --- "\352\270\260\354\264\210/README.md" | 1 - 1 file changed, 1 deletion(-) delete mode 100644 "\352\270\260\354\264\210/README.md" diff --git "a/\352\270\260\354\264\210/README.md" "b/\352\270\260\354\264\210/README.md" deleted file mode 100644 index 8b13789..0000000 --- "a/\352\270\260\354\264\210/README.md" +++ /dev/null @@ -1 +0,0 @@ - From da20649f9e90b848d52a5a61744088e9a92a7346 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Thu, 6 Jul 2023 23:56:06 +0900 Subject: [PATCH 20/99] =?UTF-8?q?Create=203=EC=B8=B5=EC=8B=A0=EA=B2=BD?= =?UTF-8?q?=EB=A7=9D.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../3\354\270\265\354\213\240\352\262\275\353\247\235.py" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "DeepLearning/3\354\270\265\354\213\240\352\262\275\353\247\235.py" diff --git "a/DeepLearning/3\354\270\265\354\213\240\352\262\275\353\247\235.py" "b/DeepLearning/3\354\270\265\354\213\240\352\262\275\353\247\235.py" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/DeepLearning/3\354\270\265\354\213\240\352\262\275\353\247\235.py" @@ -0,0 +1 @@ + From 9e16c9e6923cd680291fe22f05925a931eb7c96f Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 7 Jul 2023 00:05:34 +0900 Subject: [PATCH 21/99] =?UTF-8?q?Delete=203=EC=B8=B5=EC=8B=A0=EA=B2=BD?= =?UTF-8?q?=EB=A7=9D.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../3\354\270\265\354\213\240\352\262\275\353\247\235.py" | 1 - 1 file changed, 1 deletion(-) delete mode 100644 "DeepLearning/3\354\270\265\354\213\240\352\262\275\353\247\235.py" diff --git "a/DeepLearning/3\354\270\265\354\213\240\352\262\275\353\247\235.py" "b/DeepLearning/3\354\270\265\354\213\240\352\262\275\353\247\235.py" deleted file mode 100644 index 8b13789..0000000 --- "a/DeepLearning/3\354\270\265\354\213\240\352\262\275\353\247\235.py" +++ /dev/null @@ -1 +0,0 @@ - From b82db634b737a5c09a35f508a5610cb1fdc0c07f Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 7 Jul 2023 00:10:19 +0900 Subject: [PATCH 22/99] READMATRIX.md --- .../\354\210\230\355\225\231/READMATRIX.md" | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 "\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" diff --git "a/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" "b/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" new file mode 100644 index 0000000..a19b210 --- /dev/null +++ "b/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" @@ -0,0 +1,7 @@ +## 행렬의 중요성 +- [연산의 효율에 있어서...]() +- [딥러닝 층 구현에 있어서...]() +- []() +- []() + +--- From 3ebfa2ceb153ca796d941aafe44684a8fcbf39fa Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 7 Jul 2023 00:39:01 +0900 Subject: [PATCH 23/99] Create (2).md --- .../\354\210\230\355\225\231/(2).md" | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 "\352\270\260\354\264\210/\354\210\230\355\225\231/(2).md" diff --git "a/\352\270\260\354\264\210/\354\210\230\355\225\231/(2).md" "b/\352\270\260\354\264\210/\354\210\230\355\225\231/(2).md" new file mode 100644 index 0000000..3d0e95a --- /dev/null +++ "b/\352\270\260\354\264\210/\354\210\230\355\225\231/(2).md" @@ -0,0 +1,16 @@ +## 신경망에서의 계산은 행렬 계산으로 정리가 가능하다. + +[**입력층 - 은닉층 - 출력층**] 에 있어, 입력층에서 은닉층의 첫 번째 층(index : 0)의 첫 번째 뉴런으로 신호가 전달될 때의 과정을 수식으로 표현할 수 있다. + +image + + +**A**를 각각의 뉴런을 가진 벡터로, **X**를 각각의 입력층을 가진 벡터로, **B**를 각각의 [**편향**]()을 가진 벡터로 두고 **W**를 가중치를 가진 벡터(2차원 ~)라고 생각하면 **다음과 같은 식**을 한꺼번에 여러 개 연산이 가능하게 된다. + +image + +전체 수식으로 표현하면 이렇다(입력층, 은닉층, 출력층의 크기는 임의로 정함). + +***신경망에서의 계산 식*** : + +image From 72c40cb8c9e89baec7905c2b8231481df11d2922 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 7 Jul 2023 00:39:40 +0900 Subject: [PATCH 24/99] Update READMATRIX.md --- .../\354\210\230\355\225\231/READMATRIX.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" "b/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" index a19b210..c7e4e8b 100644 --- "a/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" +++ "b/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" @@ -1,6 +1,6 @@ ## 행렬의 중요성 - [연산의 효율에 있어서...]() -- [딥러닝 층 구현에 있어서...]() +- [딥러닝 층 구현에 있어서...](기초/수학/(2).md) - []() - []() From df2b0eab114d56eabdc318eb4ab966ba6cf8032d Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 7 Jul 2023 00:40:02 +0900 Subject: [PATCH 25/99] Update READMATRIX.md --- .../\354\210\230\355\225\231/READMATRIX.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" "b/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" index c7e4e8b..d1c261c 100644 --- "a/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" +++ "b/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" @@ -1,6 +1,6 @@ ## 행렬의 중요성 - [연산의 효율에 있어서...]() -- [딥러닝 층 구현에 있어서...](기초/수학/(2).md) +- [딥러닝 층 구현에 있어서...]([기초/수학/(2).md](https://github.com/CharmStrange/Study/blob/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5/%EA%B8%B0%EC%B4%88/%EC%88%98%ED%95%99/(2).md)https://github.com/CharmStrange/Study/blob/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5/%EA%B8%B0%EC%B4%88/%EC%88%98%ED%95%99/(2).md) - []() - []() From f43eca93fee612586ad5e79b6e4b10eb8f17ee08 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 7 Jul 2023 00:40:33 +0900 Subject: [PATCH 26/99] Update READMATRIX.md --- .../\354\210\230\355\225\231/READMATRIX.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" "b/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" index d1c261c..d9ac3a4 100644 --- "a/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" +++ "b/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" @@ -1,6 +1,6 @@ ## 행렬의 중요성 - [연산의 효율에 있어서...]() -- [딥러닝 층 구현에 있어서...]([기초/수학/(2).md](https://github.com/CharmStrange/Study/blob/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5/%EA%B8%B0%EC%B4%88/%EC%88%98%ED%95%99/(2).md)https://github.com/CharmStrange/Study/blob/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5/%EA%B8%B0%EC%B4%88/%EC%88%98%ED%95%99/(2).md) +- [딥러닝 층 구현에 있어서...](https://github.com/CharmStrange/Study/blob/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5/%EA%B8%B0%EC%B4%88/%EC%88%98%ED%95%99/(2).md) - []() - []() From 3902365ffcc16912463ecfee82490355591a4df2 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 7 Jul 2023 23:01:28 +0900 Subject: [PATCH 27/99] =?UTF-8?q?Rename=20Study#1++.ipynb=20to=20=EB=94=A5?= =?UTF-8?q?=EB=9F=AC=EB=8B=9D=EC=9D=98=EB=AC=B8=EC=A0=9C=EC=A0=90=EA=B3=BC?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=EB=B0=A9=EC=95=88.ipynb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...3\274\355\225\264\352\262\260\353\260\251\354\225\210.ipynb" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename DeepLearning/Study#1++.ipynb => "DeepLearning/\353\224\245\353\237\254\353\213\235\354\235\230\353\254\270\354\240\234\354\240\220\352\263\274\355\225\264\352\262\260\353\260\251\354\225\210.ipynb" (99%) diff --git a/DeepLearning/Study#1++.ipynb "b/DeepLearning/\353\224\245\353\237\254\353\213\235\354\235\230\353\254\270\354\240\234\354\240\220\352\263\274\355\225\264\352\262\260\353\260\251\354\225\210.ipynb" similarity index 99% rename from DeepLearning/Study#1++.ipynb rename to "DeepLearning/\353\224\245\353\237\254\353\213\235\354\235\230\353\254\270\354\240\234\354\240\220\352\263\274\355\225\264\352\262\260\353\260\251\354\225\210.ipynb" index 6a4c44b..fbebccb 100644 --- a/DeepLearning/Study#1++.ipynb +++ "b/DeepLearning/\353\224\245\353\237\254\353\213\235\354\235\230\353\254\270\354\240\234\354\240\220\352\263\274\355\225\264\352\262\260\353\260\251\354\225\210.ipynb" @@ -678,4 +678,4 @@ "outputs": [] } ] -} \ No newline at end of file +} From b59da8af4fc934fc4ca880434288b1ab95e47c7b Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 7 Jul 2023 23:01:50 +0900 Subject: [PATCH 28/99] =?UTF-8?q?Rename=20Study#1.ipynb=20to=20=EB=94=A5?= =?UTF-8?q?=EB=9F=AC=EB=8B=9D=EC=9D=98=EA=B5=AC=EC=A1=B0=EC=A0=81=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=EC=A0=90.ipynb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...1\260\354\240\201\353\254\270\354\240\234\354\240\220.ipynb" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename DeepLearning/Study#1.ipynb => "DeepLearning/\353\224\245\353\237\254\353\213\235\354\235\230\352\265\254\354\241\260\354\240\201\353\254\270\354\240\234\354\240\220.ipynb" (99%) diff --git a/DeepLearning/Study#1.ipynb "b/DeepLearning/\353\224\245\353\237\254\353\213\235\354\235\230\352\265\254\354\241\260\354\240\201\353\254\270\354\240\234\354\240\220.ipynb" similarity index 99% rename from DeepLearning/Study#1.ipynb rename to "DeepLearning/\353\224\245\353\237\254\353\213\235\354\235\230\352\265\254\354\241\260\354\240\201\353\254\270\354\240\234\354\240\220.ipynb" index ac25d1e..fe8c2da 100644 --- a/DeepLearning/Study#1.ipynb +++ "b/DeepLearning/\353\224\245\353\237\254\353\213\235\354\235\230\352\265\254\354\241\260\354\240\201\353\254\270\354\240\234\354\240\220.ipynb" @@ -505,4 +505,4 @@ } } ] -} \ No newline at end of file +} From 0095772e47b69a34283157f001d16b9aa172b7f7 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 7 Jul 2023 23:12:05 +0900 Subject: [PATCH 29/99] Update READMATRIX.md --- .../\354\210\230\355\225\231/READMATRIX.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" "b/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" index d9ac3a4..11d1eef 100644 --- "a/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" +++ "b/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" @@ -1,7 +1,7 @@ ## 행렬의 중요성 - [연산의 효율에 있어서...]() - [딥러닝 층 구현에 있어서...](https://github.com/CharmStrange/Study/blob/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5/%EA%B8%B0%EC%B4%88/%EC%88%98%ED%95%99/(2).md) -- []() +- [학습에 있어서...]() - []() --- From 43a2b16511f9e1319f6c4b7bd517b47461d01229 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 7 Jul 2023 23:18:47 +0900 Subject: [PATCH 30/99] Create LOSSFUNCTION.md --- DeepLearning/LOSSFUNCTION.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 DeepLearning/LOSSFUNCTION.md diff --git a/DeepLearning/LOSSFUNCTION.md b/DeepLearning/LOSSFUNCTION.md new file mode 100644 index 0000000..3dd2e31 --- /dev/null +++ b/DeepLearning/LOSSFUNCTION.md @@ -0,0 +1,8 @@ +# **손실 함수** + +딥러닝의 신경망에서 손실 함수는 신경망 처리 성능의 지표이다. + +신경망의 학습에선 최적의 파라미터(가중치와 편향), 즉 손실 함수의 값을 가장 작게 하는 파라미터를 찾는데, 여기서 미분 연산이 활발히 이루어진다. + +학습 과정에서 손실 함수의 값을 계속해서 미분하는데 이것은 손실 함수 값 변화와 CHAIN, 그러니까 미분 값에 따라 손실 함수의 값도 바뀌고, 바뀐 손실 함수 값에 따라 미분 값도 바뀌어 최적의 파라미터를 찾을 수 있게 된다. + From 0d061189bbc29cdebf17d439d5d4790955cf08a1 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 7 Jul 2023 23:19:16 +0900 Subject: [PATCH 31/99] Update READMATRIX.md --- .../\354\210\230\355\225\231/READMATRIX.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" "b/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" index 11d1eef..82b8c16 100644 --- "a/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" +++ "b/\352\270\260\354\264\210/\354\210\230\355\225\231/READMATRIX.md" @@ -1,7 +1,7 @@ ## 행렬의 중요성 - [연산의 효율에 있어서...]() - [딥러닝 층 구현에 있어서...](https://github.com/CharmStrange/Study/blob/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5/%EA%B8%B0%EC%B4%88/%EC%88%98%ED%95%99/(2).md) -- [학습에 있어서...]() +- [학습에 있어서...](https://github.com/CharmStrange/Study/blob/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5/DeepLearning/LOSSFUNCTION.md) - []() --- From 68e172c7fc20c093f43239bb709cec5cc69a0f05 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 8 Jul 2023 16:16:07 +0900 Subject: [PATCH 32/99] Create d.md --- .../\354\210\230\355\225\231/d.md" | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 "\352\270\260\354\264\210/\354\210\230\355\225\231/d.md" diff --git "a/\352\270\260\354\264\210/\354\210\230\355\225\231/d.md" "b/\352\270\260\354\264\210/\354\210\230\355\225\231/d.md" new file mode 100644 index 0000000..41753e4 --- /dev/null +++ "b/\352\270\260\354\264\210/\354\210\230\355\225\231/d.md" @@ -0,0 +1,17 @@ +# 미분 +-> 어느 순간(***h->0***)의 변화량을 구할 수 있다. + +image + +``` +def numerical_diff(f, x): + h = 1e-4 + return (f(x+h) - f(x-h) ) / (2*h) +``` +차분을 구해 이것으로 미분하는 수치 미분 함수이다. + +``` +def function_2(x): + return x[0]**2 + x[1]**2 +``` +배열을 받아 편미분을 계산하는 함수이다. From 82197b4177464f266d554f4dc9b652729c83bded Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Wed, 12 Jul 2023 11:34:29 +0900 Subject: [PATCH 33/99] Update LOSSFUNCTION.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 구글에 떠도는 자료는 전부 서로 비슷하거나 제가 참고한 책을 그대로 베껴 쓴 내용이 참 많네요. --- DeepLearning/LOSSFUNCTION.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/DeepLearning/LOSSFUNCTION.md b/DeepLearning/LOSSFUNCTION.md index 3dd2e31..5122b12 100644 --- a/DeepLearning/LOSSFUNCTION.md +++ b/DeepLearning/LOSSFUNCTION.md @@ -1,8 +1,33 @@ # **손실 함수** +#### (*밑바닥부터 시작하는 딥러닝* 교재 참고) 딥러닝의 신경망에서 손실 함수는 신경망 처리 성능의 지표이다. -신경망의 학습에선 최적의 파라미터(가중치와 편향), 즉 손실 함수의 값을 가장 작게 하는 파라미터를 찾는데, 여기서 미분 연산이 활발히 이루어진다. +신경망의 학습에선 최적의 **파라미터**(가중치와 편향), 즉 손실 함수의 값을 가장 작게 하는 파라미터를 찾는데, 여기서 미분 연산이 활발히 이루어진다. 학습 과정에서 손실 함수의 값을 계속해서 미분하는데 이것은 손실 함수 값 변화와 CHAIN, 그러니까 미분 값에 따라 손실 함수의 값도 바뀌고, 바뀐 손실 함수 값에 따라 미분 값도 바뀌어 최적의 파라미터를 찾을 수 있게 된다. +--- + +## 1. 평균 제곱 오차(MSE) +결과(출력, 또는 예측) 값과 실제 값(레이블)의 차이를 오차로 두고, 이들을 제곱하여 모두 더한 후 데이터의 개수로 나누어 구한다. +```Python +import numpy as np + +def MSE(n, y, Label): + return (1/n) * np.sum( (y-Label)**2 ) + +# Label +L = np.array( [1, 0, 1, 1, 0] ) + +# Expected Output +ye = np.array( [0.8, 0.1, 1, 0.9, 0.3] ) + +print( MSE(5, ye, L) ) +``` +```Python +>>> 0.029999999999999995 +``` +수식에서 n이 아닌 2를 쓰기도 하는데 이는 미분했을 때 제곱의 2가 곱해지는 것을 상쇄하기 위해 존재한다. + +## 2. 교차 엔트로피 오차(CEE) From 2973ef559b74d1862cf3bfc0094b3f56f6555667 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Wed, 12 Jul 2023 12:11:53 +0900 Subject: [PATCH 34/99] Update LOSSFUNCTION.md --- DeepLearning/LOSSFUNCTION.md | 52 +++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/DeepLearning/LOSSFUNCTION.md b/DeepLearning/LOSSFUNCTION.md index 5122b12..da01095 100644 --- a/DeepLearning/LOSSFUNCTION.md +++ b/DeepLearning/LOSSFUNCTION.md @@ -10,24 +10,38 @@ --- ## 1. 평균 제곱 오차(MSE) -결과(출력, 또는 예측) 값과 실제 값(레이블)의 차이를 오차로 두고, 이들을 제곱하여 모두 더한 후 데이터의 개수로 나누어 구한다. -```Python -import numpy as np - -def MSE(n, y, Label): - return (1/n) * np.sum( (y-Label)**2 ) - -# Label -L = np.array( [1, 0, 1, 1, 0] ) - -# Expected Output -ye = np.array( [0.8, 0.1, 1, 0.9, 0.3] ) - -print( MSE(5, ye, L) ) -``` -```Python ->>> 0.029999999999999995 -``` -수식에서 n이 아닌 2를 쓰기도 하는데 이는 미분했을 때 제곱의 2가 곱해지는 것을 상쇄하기 위해 존재한다. +>결과(출력, 또는 예측) 값과 실제 값(레이블)의 차이를 오차로 두고, 이들을 제곱하여 모두 더한 후 데이터의 개수로 나누>어 구한다. +>```Python +>import numpy as np +> +>def MSE(n, y, Label): +> return (1/n) * np.sum( (y-Label)**2 ) +> +># Label +>L = np.array( [1, 0, 1, 1, 0] ) +> +># Expected Output +>ye = np.array( [0.8, 0.1, 1, 0.9, 0.3] ) +> +>print( MSE(5, ye, L) ) +>``` +>```Python +> >>> 0.029999999999999995 +>``` +>수식에서 n이 아닌 2를 쓰기도 하는데 이는 미분했을 때 제곱의 2가 곱해지는 것을 상쇄하기 위해 존재한다. ## 2. 교차 엔트로피 오차(CEE) +>데이터의 불확실성으로 인해, 정보 이론 기반의 *엔트로피*가 이름에 붙었고, 예측된 확률 분포의 로그 값과 실제 값(레이블)을 곱하고 모두 더해 구한다. +>```Python +>import numpy as np +> +>def CEE(y, L): +> delta = 1e-7 +> return -np.sum( L*np.log(y+delta) ) +> +>print( CEE(ye, L) ) +>``` +>```Python +> >>> 0.3285037308609439 +>``` +> From 0c4edae92adde22b1519a6dad79da40ec9769c2d Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Thu, 20 Jul 2023 20:52:28 +0900 Subject: [PATCH 35/99] Delete README.md --- README.md | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index b25f3a0..0000000 --- a/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Blog : 학습 기록 ---- -* 개념과 활용 : ---- -* Numpy(1) : -* Numpy(2) : -* Numpy(3) : -* Numpy(4) : -* Numpy(5) : -* Numpy Linear Algebra(1) : -* Numpy Linear Algebra(2) : -* Numpy Linear Algebra(3) : -* Numpy Linear Algebra(4) : From 647ae1f169ba24e35e5a403308a88565f7fa1bfc Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 22 Jul 2023 15:18:36 +0900 Subject: [PATCH 36/99] Rename CNNdimension.py to dimension.py --- .../CNN/CNNdimension.py" => DeepLearning/CNN/dimension.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename "\352\270\260\354\264\210/CNN/CNNdimension.py" => DeepLearning/CNN/dimension.py (100%) diff --git "a/\352\270\260\354\264\210/CNN/CNNdimension.py" b/DeepLearning/CNN/dimension.py similarity index 100% rename from "\352\270\260\354\264\210/CNN/CNNdimension.py" rename to DeepLearning/CNN/dimension.py From f28baa6e0aabbd2b6e7585a4a62eacb50d6eed4c Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 22 Jul 2023 17:26:36 +0900 Subject: [PATCH 37/99] Add files via upload --- DeepLearning/CNN/Butterfly_Species.ipynb | 456 +++++++++++++++++++++++ 1 file changed, 456 insertions(+) create mode 100644 DeepLearning/CNN/Butterfly_Species.ipynb diff --git a/DeepLearning/CNN/Butterfly_Species.ipynb b/DeepLearning/CNN/Butterfly_Species.ipynb new file mode 100644 index 0000000..860b531 --- /dev/null +++ b/DeepLearning/CNN/Butterfly_Species.ipynb @@ -0,0 +1,456 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "데이터셋 및 파일 접근을 위한 os, ImageFolder, Image 등의 모듈과, 직접적 데이터 조작을 위한 모듈, 연산을 위한 알고리즘을 가진 모듈을 import.\n", + "메인은 PyTorch 프레임워크 사용." + ], + "metadata": { + "id": "oCbu87aKZR_C" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "kJAi0py4Qvm-" + }, + "outputs": [], + "source": [ + "import os\n", + "import random\n", + "import numpy as np\n", + "import pandas as pd\n", + "import torch\n", + "import torch.nn as nn\n", + "import torch.nn.functional as F\n", + "from torch.utils.data import random_split\n", + "from torch.utils.data import DataLoader, Dataset, Subset\n", + "from torch.utils.data import SubsetRandomSampler\n", + "from torchvision import datasets, transforms, models\n", + "from torchvision.datasets import ImageFolder\n", + "from torchvision.transforms import ToTensor\n", + "from torchvision.utils import make_grid\n", + "from pytorch_lightning import LightningModule\n", + "from pytorch_lightning import Trainer\n", + "import pytorch_lightning as pl\n", + "from matplotlib import pyplot as plt\n", + "%matplotlib inline\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.metrics import classification_report\n", + "from PIL import Image" + ] + }, + { + "cell_type": "markdown", + "source": [ + "torchvision의 transforms 메소드로 사용할 이미지 데이터에 대한 전처리 파이프라인 틀을 잡아줌.\n", + ": transforms.Compose() 메소드는 모든 이미지 데이터가 같은 전처리 과정을 거치게 함." + ], + "metadata": { + "id": "PVkuY68AZxuf" + } + }, + { + "cell_type": "code", + "source": [ + "transform=transforms.Compose([\n", + " transforms.RandomRotation(10), # 랜덤하게 이미지 회전(10도) : 데이터 다양하게 변형하여 과적합 방지\n", + " transforms.RandomHorizontalFlip(), # 랜덤하게 이미지 좌우 뒤집기 : 위와 동일\n", + " transforms.Resize(224), # 이미지의 크기를 224 by 224 로 조정 : 일반적으로 이 크기를 사용\n", + " transforms.CenterCrop(224), # 이미지 중앙을 또 한 번 24 by 224 로 자름 : 중요 부분\n", + " transforms.ToTensor(), # 이미지를 텐서로 변환\n", + " transforms.Normalize( [0.485, 0.456, 0.406],\n", + " [0.229, 0.224, 0.225] ) # 이미지의 채널을 정규화\n", + "])" + ], + "metadata": { + "id": "bBLqZKRPZQt7" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "데이터셋을 불러오고 이상이 없는지 확인하는 과정. 가공된 데이터 프레임을 새로 만듦." + ], + "metadata": { + "id": "3REYzwgAcH55" + } + }, + { + "cell_type": "code", + "source": [ + "# 전체가 확인하는 코드\n", + "\n", + "data=pd.read_csv('/content/Train')\n", + "print(len(data))\n", + "class_names=sorted(data['label'].unique().tolist())\n", + "print(class_names)\n", + "print(len(class_names))\n", + "N=list(range(len(class_names)))\n", + "normal_mapping=dict(zip(class_names,N))\n", + "reverse_mapping=dict(zip(N, class_names))\n", + "data['label2']=data['label'].map(normal_mapping)\n", + "dir0='/content/'\n", + "data['path']=dir0+data['filename']\n", + "display(data)" + ], + "metadata": { + "id": "VCUBkOyIcHWJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "이 함수는 데이터 프레임의 이미지 파일 경로와 레이블을 묶은 튜플을 원소로 가지는 리스트를 생성." + ], + "metadata": { + "id": "-RDzSb6ddrd9" + } + }, + { + "cell_type": "code", + "source": [ + "def create_path_label_list(df):\n", + " path_label_list= []\n", + " for _, row in df.iterrows():\n", + " path=row['path']\n", + " label=row['label2']\n", + " path_label_list.append((path,label))\n", + " return path_label_list\n", + "\n", + "# 확인\n", + "#path_label=create_path_label_list(data)\n", + "#print(path_label[0:3])" + ], + "metadata": { + "id": "a9xNBunWdanx" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "데이터 로더를 위한 클래스 하나를 만듦." + ], + "metadata": { + "id": "Hjq8wBRjemf5" + } + }, + { + "cell_type": "code", + "source": [ + "class CustomDataset(torch.utils.data.Dataset):\n", + " def __init__(self, path_label, transform=None): # 생성자\n", + " self.path_label = path_label # 방금 위에서 만든 함수의 반환\n", + " self.transform = transform # 아까 위에서 만든 전처리 파이프라인\n", + "\n", + " def __len__(self):\n", + " return len(self.path_label)\n", + "\n", + " # 인덱스 사용해 이미지 파일 경로와 레이블 추출, 이미지에 전처리 과정을 적용\n", + " def __getitem__(self, idx):\n", + " path, label = self.path_label[idx]\n", + " img = Image.open(path).convert('RGB') # RGB : Channel=3\n", + "\n", + " if self.transform is not None:\n", + " img = self.transform(img)\n", + "\n", + " return img, label" + ], + "metadata": { + "id": "zxwgmmrqel_S" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "PyTorch Lightning은 PyTorch 간편화 라이브러리인데 이것을 사용해 이미지 데이터셋 로드 후 전처리를 진행." + ], + "metadata": { + "id": "G2FfaYAZgHJ6" + } + }, + { + "cell_type": "code", + "source": [ + "class ImageDataset(pl.LightningDataModule):\n", + " def __init__(self, path_label, batch_size=32):\n", + " super().__init__()\n", + " self.path_label = path_label\n", + " self.batch_size = batch_size # 데이터 로더의 반환 배치 크기를 지정\n", + "\n", + " # 전처리 파이프라인을 새롭게 정의\n", + " self.transform = transforms.Compose([\n", + " transforms.ToTensor(),\n", + " transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))\n", + " ])\n", + "\n", + " # 데이터 모듈을 설정하는 메소드, 데이터 로드 후 훈련용과 테스트용 데이터 분류\n", + " def setup(self, stage=None):\n", + " dataset = CustomDataset(self.path_label, self.transform)\n", + " dataset_size = len(dataset)\n", + " train_size = int(0.8 * dataset_size)\n", + " test_size = dataset_size - train_size\n", + "\n", + " self.train_dataset = torch.utils.data.Subset(dataset, range(train_size))\n", + " self.test_dataset = torch.utils.data.Subset(dataset, range(train_size, dataset_size))\n", + "\n", + " def __len__(self): # 데이터셋의 길이 반환(훈련 or 테스트)\n", + " if self.train_dataset is not None:\n", + " return len(self.train_dataset)\n", + " elif self.test_dataset is not None:\n", + " return len(self.test_dataset)\n", + " else:\n", + " return 0\n", + "\n", + " # 인덱스를 사용해 하나의 샘플 데이터 반환(훈련 or 테스트)\n", + " def __getitem__(self, index):\n", + " if self.train_dataset is not None:\n", + " return self.train_dataset[index]\n", + " elif self.test_dataset is not None:\n", + " return self.test_dataset[index]\n", + " else:\n", + " raise IndexError(\"Index out of range. The dataset is empty.\")\n", + "\n", + " def train_dataloader(self): # 훈련용\n", + " return DataLoader(self.train_dataset, batch_size=self.batch_size, shuffle=True)\n", + "\n", + " def val_dataloader(self): # 검증용\n", + " return DataLoader(self.test_dataset, batch_size=self.batch_size)\n", + "\n", + " def test_dataloader(self): # 테스트용\n", + " return DataLoader(self.test_dataset, batch_size=self.batch_size)" + ], + "metadata": { + "id": "53FNJP1YgHbj" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "데이터셋을 훈련용과 테스트용으로 분리." + ], + "metadata": { + "id": "jYPpeOJQi0yP" + } + }, + { + "cell_type": "code", + "source": [ + "class DataModule(pl.LightningDataModule):\n", + "\n", + " def __init__(self, transform=transform, batch_size=32):\n", + " super().__init__()\n", + " self.root_dir = \"/content/\"\n", + " self.transform = transform # 위와 동일\n", + " self.batch_size = batch_size # 위와 동일\n", + "\n", + " # 데이터 모듈을 설정하는 메소드\n", + " def setup(self, stage=None):\n", + " dataset = datasets.ImageFolder(root=self.root_dir, transform=self.transform)\n", + " n_data = len(dataset)\n", + " n_train = int(0.8 * n_data)\n", + " n_test = n_data - n_train\n", + "\n", + " train_dataset, test_dataset = random_split(dataset, [n_train, n_test])\n", + "\n", + " # 훈련용과 테스트용 데이터셋을 데이터 로더로 변환\n", + " self.train_dataset = DataLoader(train_dataset, batch_size=self.batch_size, shuffle=True)\n", + " self.test_dataset = DataLoader(test_dataset, batch_size=self.batch_size)\n", + "\n", + " def train_dataloader(self):\n", + " return self.train_dataset\n", + "\n", + " def test_dataloader(self):\n", + " return self.test_dataset" + ], + "metadata": { + "id": "Y5pts3KHi1DJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "CNN 모델인데 PyTorch Lightning을 사용하여 간단한 구현이 가능." + ], + "metadata": { + "id": "sn_T53BOkn5K" + } + }, + { + "cell_type": "code", + "source": [ + "class ConvolutionalNetwork(LightningModule):\n", + "\n", + " # 이미지 데이터는 이곳에서 2개의 합성곱층과 3개의 전결합층을 거쳐 출력됨\n", + " def __init__(self): # 중요한 생성자\n", + " super(ConvolutionalNetwork, self).__init__()\n", + "\n", + " # 합성곱층은 2개\n", + " self.conv1 = nn.Conv2d(3, 6, 3, 1)\n", + " self.conv2 = nn.Conv2d(6, 16, 3, 1)\n", + "\n", + " # 실질적 전결합층은 3개, 각 메소드의 첫 인자는 이전 결과(출력)를 사용\n", + " self.fc1 = nn.Linear(16 * 54 * 54, 120) # 120개 뉴런\n", + " self.fc2 = nn.Linear(120, 84) # 84개 뉴런\n", + " self.fc3 = nn.Linear(84, 20) # 20개 뉴런\n", + " self.fc4 = nn.Linear(20, len(class_names)) # 여긴 softmax 함수 사용해 클래스 분류에 사용됨\n", + "\n", + " # 순전파 메소드\n", + " def forward(self, X):\n", + " X = F.relu(self.conv1(X)) # 활성화 함수 : ReLu\n", + " X = F.max_pool2d(X, 2, 2)\n", + " X = F.relu(self.conv2(X))\n", + " X = F.max_pool2d(X, 2, 2)\n", + " X = X.view(-1, 16 * 54 * 54)\n", + " X = F.relu(self.fc1(X))\n", + " X = F.relu(self.fc2(X))\n", + " X = F.relu(self.fc3(X))\n", + " X = self.fc4(X) # 최종 전결합층 거치기\n", + " return F.log_softmax(X, dim=1) # 활성화 함수 : softmax\n", + "\n", + " def configure_optimizers(self):\n", + " optimizer = torch.optim.Adam(self.parameters(), lr=0.001) # Adam 옵티마이저\n", + " return optimizer\n", + "\n", + " # 훈련 단계를 정의한 메소드, 손실값을 반환\n", + " def training_step(self, train_batch, batch_idx):\n", + " X, y = train_batch # 미니 배치\n", + " y_hat = self(X) # 예측된 y\n", + " loss = F.cross_entropy(y_hat, y) # 손실을 구함 : 교차 엔트로피 오차\n", + " pred = y_hat.argmax(dim=1, keepdim=True) # 예측값 : 가장 높은 확률을 가짐\n", + " acc = pred.eq(y.view_as(pred)).sum().item() / y.shape[0] # 정확도\n", + " self.log(\"train_loss\", loss)\n", + " self.log(\"train_acc\", acc)\n", + " return loss\n", + "\n", + " # 검증 단계를 정의한 메소드, 알고리즘은 위와 동일\n", + " def validation_step(self, val_batch, batch_idx):\n", + " X, y = val_batch\n", + " y_hat = self(X)\n", + " loss = F.cross_entropy(y_hat, y)\n", + " pred = y_hat.argmax(dim=1, keepdim=True)\n", + " acc = pred.eq(y.view_as(pred)).sum().item() / y.shape[0]\n", + " self.log(\"val_loss\", loss)\n", + " self.log(\"val_acc\", acc)\n", + "\n", + " # 테스트 단계를 정의한 메소드, 알고리즘은 위와 동일\n", + " def test_step(self, test_batch, batch_idx):\n", + " X, y = test_batch\n", + " y_hat = self(X)\n", + " loss = F.cross_entropy(y_hat, y)\n", + " pred = y_hat.argmax(dim=1, keepdim=True)\n", + " acc = pred.eq(y.view_as(pred)).sum().item() / y.shape[0]\n", + " self.log(\"test_loss\", loss)\n", + " self.log(\"test_acc\", acc)" + ], + "metadata": { + "id": "FJQM53fHkkm0" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "모델을 훈련시키고 테스트. if 구문을 아래와 같이 작성하면 해당 스크립트가 포함된 파일을 외부에서 import 해도 if 구문 내 스크립트는 실행되지 않음." + ], + "metadata": { + "id": "BHMi29ewonoy" + } + }, + { + "cell_type": "code", + "source": [ + "if __name__ == '__main__':\n", + " dataset = ImageDataset(path_label) # 데이터셋 변수 생성, 이미지 파일 경로와 레이블들이 튜플로 묶여있는 리스트 path_label\n", + "\n", + " dataset.setup() # 데이터를 훈련용과 테스트용으로 분리\n", + "\n", + " train_dataloader = dataset.train_dataloader() # 훈련용\n", + " test_dataloader = dataset.test_dataloader() # 테스트용\n", + "\n", + " datamodule = DataModule() # 데이터모듈 객체 생성\n", + "\n", + " datamodule.setup() # 데이터모듈 : 데이터를 훈련용과 테스트용으로 분리\n", + "\n", + " model = ConvolutionalNetwork() # CNN 모델 객체 생성\n", + "\n", + " trainer = pl.Trainer(max_epochs=30) # PyTorch Lightning Trainer : 30 epoch\n", + "\n", + " trainer.fit(model, datamodule) # CNN 모델 훈련 : 30회\n", + "\n", + " datamodule.setup(stage='test') # 데이터모듈 : 테스트 모드로 전환\n", + "\n", + " test_loader = datamodule.test_dataloader() # 데이터모듈 : 테스트용\n", + "\n", + " trainer.test(dataloaders=test_loader) # 테스트용으로 훈련된 모델을 평가" + ], + "metadata": { + "id": "FAJtO47aon9c" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "최종적으로 테스트셋 평가, 분류 결과를 분석." + ], + "metadata": { + "id": "-32Fom46rp6f" + } + }, + { + "cell_type": "code", + "source": [ + "device = torch.device(\"cpu\") # cuda:0 이면 GPU\n", + "\n", + "model.eval()\n", + "y_true=[]\n", + "y_pred=[]\n", + "with torch.no_grad():\n", + " for test_data in datamodule.test_dataloader():\n", + " test_images, test_labels = test_data[0].to(device), test_data[1].to(device)\n", + " pred = model(test_images).argmax(dim=1)\n", + " for i in range(len(pred)):\n", + " y_true.append(test_labels[i].item())\n", + " y_pred.append(pred[i].item())\n", + "\n", + "print(classification_report(y_true,y_pred,target_names=class_names,digits=4))" + ], + "metadata": { + "id": "GcggODqkrpn0" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file From c94114d04910565dbd07d9ebc88f145aa9b43214 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 22 Jul 2023 17:27:34 +0900 Subject: [PATCH 38/99] Create README.md --- DeepLearning/CNN/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 DeepLearning/CNN/README.md diff --git a/DeepLearning/CNN/README.md b/DeepLearning/CNN/README.md new file mode 100644 index 0000000..e926907 --- /dev/null +++ b/DeepLearning/CNN/README.md @@ -0,0 +1 @@ +# CNN 구조 공부 From 4c99fc57eadd3f476e9034ec164119c675f6a1d3 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 22 Jul 2023 17:42:37 +0900 Subject: [PATCH 39/99] Add files via upload --- DeepLearning/CNN/Butterfly_Species.md | 507 ++++++++++++++++++++++++++ 1 file changed, 507 insertions(+) create mode 100644 DeepLearning/CNN/Butterfly_Species.md diff --git a/DeepLearning/CNN/Butterfly_Species.md b/DeepLearning/CNN/Butterfly_Species.md new file mode 100644 index 0000000..74c94ba --- /dev/null +++ b/DeepLearning/CNN/Butterfly_Species.md @@ -0,0 +1,507 @@ +데이터셋 및 파일 접근을 위한 os, ImageFolder, Image 등의 모듈과, 직접적 데이터 조작을 위한 모듈, 연산을 위한 알고리즘을 가진 모듈을 import. +메인은 PyTorch 프레임워크 사용. + + +```python +import os +import random +import numpy as np +import pandas as pd +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.utils.data import random_split +from torch.utils.data import DataLoader, Dataset, Subset +from torch.utils.data import SubsetRandomSampler +from torchvision import datasets, transforms, models +from torchvision.datasets import ImageFolder +from torchvision.transforms import ToTensor +from torchvision.utils import make_grid +from pytorch_lightning import LightningModule +from pytorch_lightning import Trainer +import pytorch_lightning as pl +from matplotlib import pyplot as plt +%matplotlib inline +from sklearn.model_selection import train_test_split +from sklearn.metrics import classification_report +from PIL import Image +``` + +torchvision의 transforms 메소드로 사용할 이미지 데이터에 대한 전처리 파이프라인 틀을 잡아줌. +: transforms.Compose() 메소드는 모든 이미지 데이터가 같은 전처리 과정을 거치게 함. + + +```python +transform=transforms.Compose([ + transforms.RandomRotation(10), # 랜덤하게 이미지 회전(10도) : 데이터 다양하게 변형하여 과적합 방지 + transforms.RandomHorizontalFlip(), # 랜덤하게 이미지 좌우 뒤집기 : 위와 동일 + transforms.Resize(224), # 이미지의 크기를 224 by 224 로 조정 : 일반적으로 이 크기를 사용 + transforms.CenterCrop(224), # 이미지 중앙을 또 한 번 24 by 224 로 자름 : 중요 부분 + transforms.ToTensor(), # 이미지를 텐서로 변환 + transforms.Normalize( [0.485, 0.456, 0.406], + [0.229, 0.224, 0.225] ) # 이미지의 채널을 정규화 +]) +``` + +데이터셋을 불러오고 이상이 없는지 확인하는 과정. 가공된 데이터 프레임을 새로 만듦. + + +```python +# 전체가 확인하는 코드 + +data=pd.read_csv('/content/Train') +print(len(data)) +class_names=sorted(data['label'].unique().tolist()) +print(class_names) +print(len(class_names)) +N=list(range(len(class_names))) +normal_mapping=dict(zip(class_names,N)) +reverse_mapping=dict(zip(N, class_names)) +data['label2']=data['label'].map(normal_mapping) +dir0='/content/' +data['path']=dir0+data['filename'] +display(data) +``` + +이 함수는 데이터 프레임의 이미지 파일 경로와 레이블을 묶은 튜플을 원소로 가지는 리스트를 생성. + + +```python +def create_path_label_list(df): + path_label_list= [] + for _, row in df.iterrows(): + path=row['path'] + label=row['label2'] + path_label_list.append((path,label)) + return path_label_list + +# 확인 +#path_label=create_path_label_list(data) +#print(path_label[0:3]) +``` + +데이터 로더를 위한 클래스 하나를 만듦. + + +```python +class CustomDataset(torch.utils.data.Dataset): + def __init__(self, path_label, transform=None): # 생성자 + self.path_label = path_label # 방금 위에서 만든 함수의 반환 + self.transform = transform # 아까 위에서 만든 전처리 파이프라인 + + def __len__(self): + return len(self.path_label) + + # 인덱스 사용해 이미지 파일 경로와 레이블 추출, 이미지에 전처리 과정을 적용 + def __getitem__(self, idx): + path, label = self.path_label[idx] + img = Image.open(path).convert('RGB') # RGB : Channel=3 + + if self.transform is not None: + img = self.transform(img) + + return img, label +``` + +PyTorch Lightning은 PyTorch 간편화 라이브러리인데 이것을 사용해 이미지 데이터셋 로드 후 전처리를 진행. + + +```python +class ImageDataset(pl.LightningDataModule): + def __init__(self, path_label, batch_size=32): + super().__init__() + self.path_label = path_label + self.batch_size = batch_size # 데이터 로더의 반환 배치 크기를 지정 + + # 전처리 파이프라인을 새롭게 정의 + self.transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) + ]) + + # 데이터 모듈을 설정하는 메소드, 데이터 로드 후 훈련용과 테스트용 데이터 분류 + def setup(self, stage=None): + dataset = CustomDataset(self.path_label, self.transform) + dataset_size = len(dataset) + train_size = int(0.8 * dataset_size) + test_size = dataset_size - train_size + + self.train_dataset = torch.utils.data.Subset(dataset, range(train_size)) + self.test_dataset = torch.utils.data.Subset(dataset, range(train_size, dataset_size)) + + def __len__(self): # 데이터셋의 길이 반환(훈련 or 테스트) + if self.train_dataset is not None: + return len(self.train_dataset) + elif self.test_dataset is not None: + return len(self.test_dataset) + else: + return 0 + + # 인덱스를 사용해 하나의 샘플 데이터 반환(훈련 or 테스트) + def __getitem__(self, index): + if self.train_dataset is not None: + return self.train_dataset[index] + elif self.test_dataset is not None: + return self.test_dataset[index] + else: + raise IndexError("Index out of range. The dataset is empty.") + + def train_dataloader(self): # 훈련용 + return DataLoader(self.train_dataset, batch_size=self.batch_size, shuffle=True) + + def val_dataloader(self): # 검증용 + return DataLoader(self.test_dataset, batch_size=self.batch_size) + + def test_dataloader(self): # 테스트용 + return DataLoader(self.test_dataset, batch_size=self.batch_size) +``` + +데이터셋을 훈련용과 테스트용으로 분리. + + +```python +class DataModule(pl.LightningDataModule): + + def __init__(self, transform=transform, batch_size=32): + super().__init__() + self.root_dir = "/content/" + self.transform = transform # 위와 동일 + self.batch_size = batch_size # 위와 동일 + + # 데이터 모듈을 설정하는 메소드 + def setup(self, stage=None): + dataset = datasets.ImageFolder(root=self.root_dir, transform=self.transform) + n_data = len(dataset) + n_train = int(0.8 * n_data) + n_test = n_data - n_train + + train_dataset, test_dataset = random_split(dataset, [n_train, n_test]) + + # 훈련용과 테스트용 데이터셋을 데이터 로더로 변환 + self.train_dataset = DataLoader(train_dataset, batch_size=self.batch_size, shuffle=True) + self.test_dataset = DataLoader(test_dataset, batch_size=self.batch_size) + + def train_dataloader(self): + return self.train_dataset + + def test_dataloader(self): + return self.test_dataset +``` + +CNN 모델인데 PyTorch Lightning을 사용하여 간단한 구현이 가능. + + +```python +class ConvolutionalNetwork(LightningModule): + + # 이미지 데이터는 이곳에서 2개의 합성곱층과 3개의 전결합층을 거쳐 출력됨 + def __init__(self): # 중요한 생성자 + super(ConvolutionalNetwork, self).__init__() + + # 합성곱층은 2개 + self.conv1 = nn.Conv2d(3, 6, 3, 1) + self.conv2 = nn.Conv2d(6, 16, 3, 1) + + # 실질적 전결합층은 3개, 각 메소드의 첫 인자는 이전 결과(출력)를 사용 + self.fc1 = nn.Linear(16 * 54 * 54, 120) # 120개 뉴런 + self.fc2 = nn.Linear(120, 84) # 84개 뉴런 + self.fc3 = nn.Linear(84, 20) # 20개 뉴런 + self.fc4 = nn.Linear(20, len(class_names)) # 여긴 softmax 함수 사용해 클래스 분류에 사용됨 + + # 순전파 메소드 + def forward(self, X): + X = F.relu(self.conv1(X)) # 활성화 함수 : ReLu + X = F.max_pool2d(X, 2, 2) + X = F.relu(self.conv2(X)) + X = F.max_pool2d(X, 2, 2) + X = X.view(-1, 16 * 54 * 54) + X = F.relu(self.fc1(X)) + X = F.relu(self.fc2(X)) + X = F.relu(self.fc3(X)) + X = self.fc4(X) # 최종 전결합층 거치기 + return F.log_softmax(X, dim=1) # 활성화 함수 : softmax + + def configure_optimizers(self): + optimizer = torch.optim.Adam(self.parameters(), lr=0.001) # Adam 옵티마이저 + return optimizer + + # 훈련 단계를 정의한 메소드, 손실값을 반환 + def training_step(self, train_batch, batch_idx): + X, y = train_batch # 미니 배치 + y_hat = self(X) # 예측된 y + loss = F.cross_entropy(y_hat, y) # 손실을 구함 : 교차 엔트로피 오차 + pred = y_hat.argmax(dim=1, keepdim=True) # 예측값 : 가장 높은 확률을 가짐 + acc = pred.eq(y.view_as(pred)).sum().item() / y.shape[0] # 정확도 + self.log("train_loss", loss) + self.log("train_acc", acc) + return loss + + # 검증 단계를 정의한 메소드, 알고리즘은 위와 동일 + def validation_step(self, val_batch, batch_idx): + X, y = val_batch + y_hat = self(X) + loss = F.cross_entropy(y_hat, y) + pred = y_hat.argmax(dim=1, keepdim=True) + acc = pred.eq(y.view_as(pred)).sum().item() / y.shape[0] + self.log("val_loss", loss) + self.log("val_acc", acc) + + # 테스트 단계를 정의한 메소드, 알고리즘은 위와 동일 + def test_step(self, test_batch, batch_idx): + X, y = test_batch + y_hat = self(X) + loss = F.cross_entropy(y_hat, y) + pred = y_hat.argmax(dim=1, keepdim=True) + acc = pred.eq(y.view_as(pred)).sum().item() / y.shape[0] + self.log("test_loss", loss) + self.log("test_acc", acc) +``` + +모델을 훈련시키고 테스트. if 구문을 아래와 같이 작성하면 해당 스크립트가 포함된 파일을 외부에서 import 해도 if 구문 내 스크립트는 실행되지 않음. + + +```python +if __name__ == '__main__': + dataset = ImageDataset(path_label) # 데이터셋 변수 생성, 이미지 파일 경로와 레이블들이 튜플로 묶여있는 리스트 path_label + + dataset.setup() # 데이터를 훈련용과 테스트용으로 분리 + + train_dataloader = dataset.train_dataloader() # 훈련용 + test_dataloader = dataset.test_dataloader() # 테스트용 + + datamodule = DataModule() # 데이터모듈 객체 생성 + + datamodule.setup() # 데이터모듈 : 데이터를 훈련용과 테스트용으로 분리 + + model = ConvolutionalNetwork() # CNN 모델 객체 생성 + + trainer = pl.Trainer(max_epochs=30) # PyTorch Lightning Trainer : 30 epoch + + trainer.fit(model, datamodule) # CNN 모델 훈련 : 30회 + + datamodule.setup(stage='test') # 데이터모듈 : 테스트 모드로 전환 + + test_loader = datamodule.test_dataloader() # 데이터모듈 : 테스트용 + + trainer.test(dataloaders=test_loader) # 테스트용으로 훈련된 모델을 평가 +``` + +최종적으로 테스트셋 평가, 분류 결과를 분석. + + +```python +device = torch.device("cpu") # cuda:0 이면 GPU + +model.eval() +y_true=[] +y_pred=[] +with torch.no_grad(): + for test_data in datamodule.test_dataloader(): + test_images, test_labels = test_data[0].to(device), test_data[1].to(device) + pred = model(test_images).argmax(dim=1) + for i in range(len(pred)): + y_true.append(test_labels[i].item()) + y_pred.append(pred[i].item()) + +print(classification_report(y_true,y_pred,target_names=class_names,digits=4)) +``` + + +```python +from google.colab import drive +drive.mount("/content/drive") + +!jupyter nbconvert --to markdown "/content/drive/MyDrive/CoLab Notebooks/Butterfly_Species.ipynb" +``` + + Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True). + [NbConvertApp] WARNING | pattern '/content/drive/MyDrive/CoLab Notebooks/Butterfly_Species.ipynb' matched no files + This application is used to convert notebook files (*.ipynb) + to various other formats. + + WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES. + + Options + ======= + The options below are convenience aliases to configurable class-options, + as listed in the "Equivalent to" description-line of the aliases. + To see all configurable class-options for some , use: + --help-all + + --debug + set log level to logging.DEBUG (maximize logging output) + Equivalent to: [--Application.log_level=10] + --show-config + Show the application's configuration (human-readable format) + Equivalent to: [--Application.show_config=True] + --show-config-json + Show the application's configuration (json format) + Equivalent to: [--Application.show_config_json=True] + --generate-config + generate default config file + Equivalent to: [--JupyterApp.generate_config=True] + -y + Answer yes to any questions instead of prompting. + Equivalent to: [--JupyterApp.answer_yes=True] + --execute + Execute the notebook prior to export. + Equivalent to: [--ExecutePreprocessor.enabled=True] + --allow-errors + Continue notebook execution even if one of the cells throws an error and include the error message in the cell output (the default behaviour is to abort conversion). This flag is only relevant if '--execute' was specified, too. + Equivalent to: [--ExecutePreprocessor.allow_errors=True] + --stdin + read a single notebook file from stdin. Write the resulting notebook with default basename 'notebook.*' + Equivalent to: [--NbConvertApp.from_stdin=True] + --stdout + Write notebook output to stdout instead of files. + Equivalent to: [--NbConvertApp.writer_class=StdoutWriter] + --inplace + Run nbconvert in place, overwriting the existing notebook (only + relevant when converting to notebook format) + Equivalent to: [--NbConvertApp.use_output_suffix=False --NbConvertApp.export_format=notebook --FilesWriter.build_directory=] + --clear-output + Clear output of current file and save in place, + overwriting the existing notebook. + Equivalent to: [--NbConvertApp.use_output_suffix=False --NbConvertApp.export_format=notebook --FilesWriter.build_directory= --ClearOutputPreprocessor.enabled=True] + --no-prompt + Exclude input and output prompts from converted document. + Equivalent to: [--TemplateExporter.exclude_input_prompt=True --TemplateExporter.exclude_output_prompt=True] + --no-input + Exclude input cells and output prompts from converted document. + This mode is ideal for generating code-free reports. + Equivalent to: [--TemplateExporter.exclude_output_prompt=True --TemplateExporter.exclude_input=True --TemplateExporter.exclude_input_prompt=True] + --allow-chromium-download + Whether to allow downloading chromium if no suitable version is found on the system. + Equivalent to: [--WebPDFExporter.allow_chromium_download=True] + --disable-chromium-sandbox + Disable chromium security sandbox when converting to PDF.. + Equivalent to: [--WebPDFExporter.disable_sandbox=True] + --show-input + Shows code input. This flag is only useful for dejavu users. + Equivalent to: [--TemplateExporter.exclude_input=False] + --embed-images + Embed the images as base64 dataurls in the output. This flag is only useful for the HTML/WebPDF/Slides exports. + Equivalent to: [--HTMLExporter.embed_images=True] + --sanitize-html + Whether the HTML in Markdown cells and cell outputs should be sanitized.. + Equivalent to: [--HTMLExporter.sanitize_html=True] + --log-level= + Set the log level by value or name. + Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL'] + Default: 30 + Equivalent to: [--Application.log_level] + --config= + Full path of a config file. + Default: '' + Equivalent to: [--JupyterApp.config_file] + --to= + The export format to be used, either one of the built-in formats + ['asciidoc', 'custom', 'html', 'latex', 'markdown', 'notebook', 'pdf', 'python', 'rst', 'script', 'slides', 'webpdf'] + or a dotted object name that represents the import path for an + ``Exporter`` class + Default: '' + Equivalent to: [--NbConvertApp.export_format] + --template= + Name of the template to use + Default: '' + Equivalent to: [--TemplateExporter.template_name] + --template-file= + Name of the template file to use + Default: None + Equivalent to: [--TemplateExporter.template_file] + --theme= + Template specific theme(e.g. the name of a JupyterLab CSS theme distributed + as prebuilt extension for the lab template) + Default: 'light' + Equivalent to: [--HTMLExporter.theme] + --sanitize_html= + Whether the HTML in Markdown cells and cell outputs should be sanitized.This + should be set to True by nbviewer or similar tools. + Default: False + Equivalent to: [--HTMLExporter.sanitize_html] + --writer= + Writer class used to write the + results of the conversion + Default: 'FilesWriter' + Equivalent to: [--NbConvertApp.writer_class] + --post= + PostProcessor class used to write the + results of the conversion + Default: '' + Equivalent to: [--NbConvertApp.postprocessor_class] + --output= + overwrite base name use for output files. + can only be used when converting one notebook at a time. + Default: '' + Equivalent to: [--NbConvertApp.output_base] + --output-dir= + Directory to write output(s) to. Defaults + to output to the directory of each notebook. To recover + previous default behaviour (outputting to the current + working directory) use . as the flag value. + Default: '' + Equivalent to: [--FilesWriter.build_directory] + --reveal-prefix= + The URL prefix for reveal.js (version 3.x). + This defaults to the reveal CDN, but can be any url pointing to a copy + of reveal.js. + For speaker notes to work, this must be a relative path to a local + copy of reveal.js: e.g., "reveal.js". + If a relative path is given, it must be a subdirectory of the + current directory (from which the server is run). + See the usage documentation + (https://nbconvert.readthedocs.io/en/latest/usage.html#reveal-js-html-slideshow) + for more details. + Default: '' + Equivalent to: [--SlidesExporter.reveal_url_prefix] + --nbformat= + The nbformat version to write. + Use this to downgrade notebooks. + Choices: any of [1, 2, 3, 4] + Default: 4 + Equivalent to: [--NotebookExporter.nbformat_version] + + Examples + -------- + + The simplest way to use nbconvert is + + > jupyter nbconvert mynotebook.ipynb --to html + + Options include ['asciidoc', 'custom', 'html', 'latex', 'markdown', 'notebook', 'pdf', 'python', 'rst', 'script', 'slides', 'webpdf']. + + > jupyter nbconvert --to latex mynotebook.ipynb + + Both HTML and LaTeX support multiple output templates. LaTeX includes + 'base', 'article' and 'report'. HTML includes 'basic', 'lab' and + 'classic'. You can specify the flavor of the format used. + + > jupyter nbconvert --to html --template lab mynotebook.ipynb + + You can also pipe the output to stdout, rather than a file + + > jupyter nbconvert mynotebook.ipynb --stdout + + PDF is generated via latex + + > jupyter nbconvert mynotebook.ipynb --to pdf + + You can get (and serve) a Reveal.js-powered slideshow + + > jupyter nbconvert myslides.ipynb --to slides --post serve + + Multiple notebooks can be given at the command line in a couple of + different ways: + + > jupyter nbconvert notebook*.ipynb + > jupyter nbconvert notebook1.ipynb notebook2.ipynb + + or you can specify the notebooks list in a config file, containing:: + + c.NbConvertApp.notebooks = ["my_notebook.ipynb"] + + > jupyter nbconvert --config mycfg.py + + To see all available configurables, use `--help-all`. + + From a7ab05988cd6f1a809b543212223f71d5c12c974 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 22 Jul 2023 17:43:17 +0900 Subject: [PATCH 40/99] Update Butterfly_Species.md --- DeepLearning/CNN/Butterfly_Species.md | 200 -------------------------- 1 file changed, 200 deletions(-) diff --git a/DeepLearning/CNN/Butterfly_Species.md b/DeepLearning/CNN/Butterfly_Species.md index 74c94ba..fb7207f 100644 --- a/DeepLearning/CNN/Butterfly_Species.md +++ b/DeepLearning/CNN/Butterfly_Species.md @@ -305,203 +305,3 @@ with torch.no_grad(): print(classification_report(y_true,y_pred,target_names=class_names,digits=4)) ``` - - -```python -from google.colab import drive -drive.mount("/content/drive") - -!jupyter nbconvert --to markdown "/content/drive/MyDrive/CoLab Notebooks/Butterfly_Species.ipynb" -``` - - Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True). - [NbConvertApp] WARNING | pattern '/content/drive/MyDrive/CoLab Notebooks/Butterfly_Species.ipynb' matched no files - This application is used to convert notebook files (*.ipynb) - to various other formats. - - WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES. - - Options - ======= - The options below are convenience aliases to configurable class-options, - as listed in the "Equivalent to" description-line of the aliases. - To see all configurable class-options for some , use: - --help-all - - --debug - set log level to logging.DEBUG (maximize logging output) - Equivalent to: [--Application.log_level=10] - --show-config - Show the application's configuration (human-readable format) - Equivalent to: [--Application.show_config=True] - --show-config-json - Show the application's configuration (json format) - Equivalent to: [--Application.show_config_json=True] - --generate-config - generate default config file - Equivalent to: [--JupyterApp.generate_config=True] - -y - Answer yes to any questions instead of prompting. - Equivalent to: [--JupyterApp.answer_yes=True] - --execute - Execute the notebook prior to export. - Equivalent to: [--ExecutePreprocessor.enabled=True] - --allow-errors - Continue notebook execution even if one of the cells throws an error and include the error message in the cell output (the default behaviour is to abort conversion). This flag is only relevant if '--execute' was specified, too. - Equivalent to: [--ExecutePreprocessor.allow_errors=True] - --stdin - read a single notebook file from stdin. Write the resulting notebook with default basename 'notebook.*' - Equivalent to: [--NbConvertApp.from_stdin=True] - --stdout - Write notebook output to stdout instead of files. - Equivalent to: [--NbConvertApp.writer_class=StdoutWriter] - --inplace - Run nbconvert in place, overwriting the existing notebook (only - relevant when converting to notebook format) - Equivalent to: [--NbConvertApp.use_output_suffix=False --NbConvertApp.export_format=notebook --FilesWriter.build_directory=] - --clear-output - Clear output of current file and save in place, - overwriting the existing notebook. - Equivalent to: [--NbConvertApp.use_output_suffix=False --NbConvertApp.export_format=notebook --FilesWriter.build_directory= --ClearOutputPreprocessor.enabled=True] - --no-prompt - Exclude input and output prompts from converted document. - Equivalent to: [--TemplateExporter.exclude_input_prompt=True --TemplateExporter.exclude_output_prompt=True] - --no-input - Exclude input cells and output prompts from converted document. - This mode is ideal for generating code-free reports. - Equivalent to: [--TemplateExporter.exclude_output_prompt=True --TemplateExporter.exclude_input=True --TemplateExporter.exclude_input_prompt=True] - --allow-chromium-download - Whether to allow downloading chromium if no suitable version is found on the system. - Equivalent to: [--WebPDFExporter.allow_chromium_download=True] - --disable-chromium-sandbox - Disable chromium security sandbox when converting to PDF.. - Equivalent to: [--WebPDFExporter.disable_sandbox=True] - --show-input - Shows code input. This flag is only useful for dejavu users. - Equivalent to: [--TemplateExporter.exclude_input=False] - --embed-images - Embed the images as base64 dataurls in the output. This flag is only useful for the HTML/WebPDF/Slides exports. - Equivalent to: [--HTMLExporter.embed_images=True] - --sanitize-html - Whether the HTML in Markdown cells and cell outputs should be sanitized.. - Equivalent to: [--HTMLExporter.sanitize_html=True] - --log-level= - Set the log level by value or name. - Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL'] - Default: 30 - Equivalent to: [--Application.log_level] - --config= - Full path of a config file. - Default: '' - Equivalent to: [--JupyterApp.config_file] - --to= - The export format to be used, either one of the built-in formats - ['asciidoc', 'custom', 'html', 'latex', 'markdown', 'notebook', 'pdf', 'python', 'rst', 'script', 'slides', 'webpdf'] - or a dotted object name that represents the import path for an - ``Exporter`` class - Default: '' - Equivalent to: [--NbConvertApp.export_format] - --template= - Name of the template to use - Default: '' - Equivalent to: [--TemplateExporter.template_name] - --template-file= - Name of the template file to use - Default: None - Equivalent to: [--TemplateExporter.template_file] - --theme= - Template specific theme(e.g. the name of a JupyterLab CSS theme distributed - as prebuilt extension for the lab template) - Default: 'light' - Equivalent to: [--HTMLExporter.theme] - --sanitize_html= - Whether the HTML in Markdown cells and cell outputs should be sanitized.This - should be set to True by nbviewer or similar tools. - Default: False - Equivalent to: [--HTMLExporter.sanitize_html] - --writer= - Writer class used to write the - results of the conversion - Default: 'FilesWriter' - Equivalent to: [--NbConvertApp.writer_class] - --post= - PostProcessor class used to write the - results of the conversion - Default: '' - Equivalent to: [--NbConvertApp.postprocessor_class] - --output= - overwrite base name use for output files. - can only be used when converting one notebook at a time. - Default: '' - Equivalent to: [--NbConvertApp.output_base] - --output-dir= - Directory to write output(s) to. Defaults - to output to the directory of each notebook. To recover - previous default behaviour (outputting to the current - working directory) use . as the flag value. - Default: '' - Equivalent to: [--FilesWriter.build_directory] - --reveal-prefix= - The URL prefix for reveal.js (version 3.x). - This defaults to the reveal CDN, but can be any url pointing to a copy - of reveal.js. - For speaker notes to work, this must be a relative path to a local - copy of reveal.js: e.g., "reveal.js". - If a relative path is given, it must be a subdirectory of the - current directory (from which the server is run). - See the usage documentation - (https://nbconvert.readthedocs.io/en/latest/usage.html#reveal-js-html-slideshow) - for more details. - Default: '' - Equivalent to: [--SlidesExporter.reveal_url_prefix] - --nbformat= - The nbformat version to write. - Use this to downgrade notebooks. - Choices: any of [1, 2, 3, 4] - Default: 4 - Equivalent to: [--NotebookExporter.nbformat_version] - - Examples - -------- - - The simplest way to use nbconvert is - - > jupyter nbconvert mynotebook.ipynb --to html - - Options include ['asciidoc', 'custom', 'html', 'latex', 'markdown', 'notebook', 'pdf', 'python', 'rst', 'script', 'slides', 'webpdf']. - - > jupyter nbconvert --to latex mynotebook.ipynb - - Both HTML and LaTeX support multiple output templates. LaTeX includes - 'base', 'article' and 'report'. HTML includes 'basic', 'lab' and - 'classic'. You can specify the flavor of the format used. - - > jupyter nbconvert --to html --template lab mynotebook.ipynb - - You can also pipe the output to stdout, rather than a file - - > jupyter nbconvert mynotebook.ipynb --stdout - - PDF is generated via latex - - > jupyter nbconvert mynotebook.ipynb --to pdf - - You can get (and serve) a Reveal.js-powered slideshow - - > jupyter nbconvert myslides.ipynb --to slides --post serve - - Multiple notebooks can be given at the command line in a couple of - different ways: - - > jupyter nbconvert notebook*.ipynb - > jupyter nbconvert notebook1.ipynb notebook2.ipynb - - or you can specify the notebooks list in a config file, containing:: - - c.NbConvertApp.notebooks = ["my_notebook.ipynb"] - - > jupyter nbconvert --config mycfg.py - - To see all available configurables, use `--help-all`. - - From 12ca61a5fa16b990d431aad50a565a44ee1d1587 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 22 Jul 2023 17:46:44 +0900 Subject: [PATCH 41/99] Update Butterfly_Species.md --- DeepLearning/CNN/Butterfly_Species.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DeepLearning/CNN/Butterfly_Species.md b/DeepLearning/CNN/Butterfly_Species.md index fb7207f..24c35e9 100644 --- a/DeepLearning/CNN/Butterfly_Species.md +++ b/DeepLearning/CNN/Butterfly_Species.md @@ -1,3 +1,5 @@ +사용한 [Butterfly Species 데이터셋](https://www.kaggle.com/datasets/phucthaiv02/butterfly-image-classification) + 데이터셋 및 파일 접근을 위한 os, ImageFolder, Image 등의 모듈과, 직접적 데이터 조작을 위한 모듈, 연산을 위한 알고리즘을 가진 모듈을 import. 메인은 PyTorch 프레임워크 사용. From d1579b748de2d64f7ac84155e3eacd943ce48b39 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 22 Jul 2023 17:47:41 +0900 Subject: [PATCH 42/99] Update Butterfly_Species.md --- DeepLearning/CNN/Butterfly_Species.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/DeepLearning/CNN/Butterfly_Species.md b/DeepLearning/CNN/Butterfly_Species.md index 24c35e9..beaa155 100644 --- a/DeepLearning/CNN/Butterfly_Species.md +++ b/DeepLearning/CNN/Butterfly_Species.md @@ -1,7 +1,7 @@ 사용한 [Butterfly Species 데이터셋](https://www.kaggle.com/datasets/phucthaiv02/butterfly-image-classification) -데이터셋 및 파일 접근을 위한 os, ImageFolder, Image 등의 모듈과, 직접적 데이터 조작을 위한 모듈, 연산을 위한 알고리즘을 가진 모듈을 import. -메인은 PyTorch 프레임워크 사용. +**데이터셋 및 파일 접근을 위한 os, ImageFolder, Image 등의 모듈과, 직접적 데이터 조작을 위한 모듈, 연산을 위한 알고리즘을 가진 모듈을 import. +메인은 PyTorch 프레임워크 사용.** ```python @@ -29,8 +29,8 @@ from sklearn.metrics import classification_report from PIL import Image ``` -torchvision의 transforms 메소드로 사용할 이미지 데이터에 대한 전처리 파이프라인 틀을 잡아줌. -: transforms.Compose() 메소드는 모든 이미지 데이터가 같은 전처리 과정을 거치게 함. +**torchvision의 transforms 메소드로 사용할 이미지 데이터에 대한 전처리 파이프라인 틀을 잡아줌. +: transforms.Compose() 메소드는 모든 이미지 데이터가 같은 전처리 과정을 거치게 함.** ```python @@ -45,7 +45,7 @@ transform=transforms.Compose([ ]) ``` -데이터셋을 불러오고 이상이 없는지 확인하는 과정. 가공된 데이터 프레임을 새로 만듦. +**데이터셋을 불러오고 이상이 없는지 확인하는 과정. 가공된 데이터 프레임을 새로 만듦.** ```python @@ -65,7 +65,7 @@ data['path']=dir0+data['filename'] display(data) ``` -이 함수는 데이터 프레임의 이미지 파일 경로와 레이블을 묶은 튜플을 원소로 가지는 리스트를 생성. +**이 함수는 데이터 프레임의 이미지 파일 경로와 레이블을 묶은 튜플을 원소로 가지는 리스트를 생성.** ```python @@ -82,7 +82,7 @@ def create_path_label_list(df): #print(path_label[0:3]) ``` -데이터 로더를 위한 클래스 하나를 만듦. +**데이터 로더를 위한 클래스 하나를 만듦.** ```python @@ -105,7 +105,7 @@ class CustomDataset(torch.utils.data.Dataset): return img, label ``` -PyTorch Lightning은 PyTorch 간편화 라이브러리인데 이것을 사용해 이미지 데이터셋 로드 후 전처리를 진행. +**PyTorch Lightning은 PyTorch 간편화 라이브러리인데 이것을 사용해 이미지 데이터셋 로드 후 전처리를 진행.** ```python @@ -158,7 +158,7 @@ class ImageDataset(pl.LightningDataModule): return DataLoader(self.test_dataset, batch_size=self.batch_size) ``` -데이터셋을 훈련용과 테스트용으로 분리. +**데이터셋을 훈련용과 테스트용으로 분리.** ```python @@ -190,7 +190,7 @@ class DataModule(pl.LightningDataModule): return self.test_dataset ``` -CNN 모델인데 PyTorch Lightning을 사용하여 간단한 구현이 가능. +**CNN 모델인데 PyTorch Lightning을 사용하여 간단한 구현이 가능.** ```python @@ -259,7 +259,7 @@ class ConvolutionalNetwork(LightningModule): self.log("test_acc", acc) ``` -모델을 훈련시키고 테스트. if 구문을 아래와 같이 작성하면 해당 스크립트가 포함된 파일을 외부에서 import 해도 if 구문 내 스크립트는 실행되지 않음. +**모델을 훈련시키고 테스트. if 구문을 아래와 같이 작성하면 해당 스크립트가 포함된 파일을 외부에서 import 해도 if 구문 내 스크립트는 실행되지 않음.** ```python @@ -288,7 +288,7 @@ if __name__ == '__main__': trainer.test(dataloaders=test_loader) # 테스트용으로 훈련된 모델을 평가 ``` -최종적으로 테스트셋 평가, 분류 결과를 분석. +**최종적으로 테스트셋 평가, 분류 결과를 분석.** ```python From 1e8cdfb6f3690b94fc4556493d4dea7c11376d0c Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 22 Jul 2023 17:48:00 +0900 Subject: [PATCH 43/99] Delete Butterfly_Species.ipynb --- DeepLearning/CNN/Butterfly_Species.ipynb | 456 ----------------------- 1 file changed, 456 deletions(-) delete mode 100644 DeepLearning/CNN/Butterfly_Species.ipynb diff --git a/DeepLearning/CNN/Butterfly_Species.ipynb b/DeepLearning/CNN/Butterfly_Species.ipynb deleted file mode 100644 index 860b531..0000000 --- a/DeepLearning/CNN/Butterfly_Species.ipynb +++ /dev/null @@ -1,456 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "markdown", - "source": [ - "데이터셋 및 파일 접근을 위한 os, ImageFolder, Image 등의 모듈과, 직접적 데이터 조작을 위한 모듈, 연산을 위한 알고리즘을 가진 모듈을 import.\n", - "메인은 PyTorch 프레임워크 사용." - ], - "metadata": { - "id": "oCbu87aKZR_C" - } - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "kJAi0py4Qvm-" - }, - "outputs": [], - "source": [ - "import os\n", - "import random\n", - "import numpy as np\n", - "import pandas as pd\n", - "import torch\n", - "import torch.nn as nn\n", - "import torch.nn.functional as F\n", - "from torch.utils.data import random_split\n", - "from torch.utils.data import DataLoader, Dataset, Subset\n", - "from torch.utils.data import SubsetRandomSampler\n", - "from torchvision import datasets, transforms, models\n", - "from torchvision.datasets import ImageFolder\n", - "from torchvision.transforms import ToTensor\n", - "from torchvision.utils import make_grid\n", - "from pytorch_lightning import LightningModule\n", - "from pytorch_lightning import Trainer\n", - "import pytorch_lightning as pl\n", - "from matplotlib import pyplot as plt\n", - "%matplotlib inline\n", - "from sklearn.model_selection import train_test_split\n", - "from sklearn.metrics import classification_report\n", - "from PIL import Image" - ] - }, - { - "cell_type": "markdown", - "source": [ - "torchvision의 transforms 메소드로 사용할 이미지 데이터에 대한 전처리 파이프라인 틀을 잡아줌.\n", - ": transforms.Compose() 메소드는 모든 이미지 데이터가 같은 전처리 과정을 거치게 함." - ], - "metadata": { - "id": "PVkuY68AZxuf" - } - }, - { - "cell_type": "code", - "source": [ - "transform=transforms.Compose([\n", - " transforms.RandomRotation(10), # 랜덤하게 이미지 회전(10도) : 데이터 다양하게 변형하여 과적합 방지\n", - " transforms.RandomHorizontalFlip(), # 랜덤하게 이미지 좌우 뒤집기 : 위와 동일\n", - " transforms.Resize(224), # 이미지의 크기를 224 by 224 로 조정 : 일반적으로 이 크기를 사용\n", - " transforms.CenterCrop(224), # 이미지 중앙을 또 한 번 24 by 224 로 자름 : 중요 부분\n", - " transforms.ToTensor(), # 이미지를 텐서로 변환\n", - " transforms.Normalize( [0.485, 0.456, 0.406],\n", - " [0.229, 0.224, 0.225] ) # 이미지의 채널을 정규화\n", - "])" - ], - "metadata": { - "id": "bBLqZKRPZQt7" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "데이터셋을 불러오고 이상이 없는지 확인하는 과정. 가공된 데이터 프레임을 새로 만듦." - ], - "metadata": { - "id": "3REYzwgAcH55" - } - }, - { - "cell_type": "code", - "source": [ - "# 전체가 확인하는 코드\n", - "\n", - "data=pd.read_csv('/content/Train')\n", - "print(len(data))\n", - "class_names=sorted(data['label'].unique().tolist())\n", - "print(class_names)\n", - "print(len(class_names))\n", - "N=list(range(len(class_names)))\n", - "normal_mapping=dict(zip(class_names,N))\n", - "reverse_mapping=dict(zip(N, class_names))\n", - "data['label2']=data['label'].map(normal_mapping)\n", - "dir0='/content/'\n", - "data['path']=dir0+data['filename']\n", - "display(data)" - ], - "metadata": { - "id": "VCUBkOyIcHWJ" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "이 함수는 데이터 프레임의 이미지 파일 경로와 레이블을 묶은 튜플을 원소로 가지는 리스트를 생성." - ], - "metadata": { - "id": "-RDzSb6ddrd9" - } - }, - { - "cell_type": "code", - "source": [ - "def create_path_label_list(df):\n", - " path_label_list= []\n", - " for _, row in df.iterrows():\n", - " path=row['path']\n", - " label=row['label2']\n", - " path_label_list.append((path,label))\n", - " return path_label_list\n", - "\n", - "# 확인\n", - "#path_label=create_path_label_list(data)\n", - "#print(path_label[0:3])" - ], - "metadata": { - "id": "a9xNBunWdanx" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "데이터 로더를 위한 클래스 하나를 만듦." - ], - "metadata": { - "id": "Hjq8wBRjemf5" - } - }, - { - "cell_type": "code", - "source": [ - "class CustomDataset(torch.utils.data.Dataset):\n", - " def __init__(self, path_label, transform=None): # 생성자\n", - " self.path_label = path_label # 방금 위에서 만든 함수의 반환\n", - " self.transform = transform # 아까 위에서 만든 전처리 파이프라인\n", - "\n", - " def __len__(self):\n", - " return len(self.path_label)\n", - "\n", - " # 인덱스 사용해 이미지 파일 경로와 레이블 추출, 이미지에 전처리 과정을 적용\n", - " def __getitem__(self, idx):\n", - " path, label = self.path_label[idx]\n", - " img = Image.open(path).convert('RGB') # RGB : Channel=3\n", - "\n", - " if self.transform is not None:\n", - " img = self.transform(img)\n", - "\n", - " return img, label" - ], - "metadata": { - "id": "zxwgmmrqel_S" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "PyTorch Lightning은 PyTorch 간편화 라이브러리인데 이것을 사용해 이미지 데이터셋 로드 후 전처리를 진행." - ], - "metadata": { - "id": "G2FfaYAZgHJ6" - } - }, - { - "cell_type": "code", - "source": [ - "class ImageDataset(pl.LightningDataModule):\n", - " def __init__(self, path_label, batch_size=32):\n", - " super().__init__()\n", - " self.path_label = path_label\n", - " self.batch_size = batch_size # 데이터 로더의 반환 배치 크기를 지정\n", - "\n", - " # 전처리 파이프라인을 새롭게 정의\n", - " self.transform = transforms.Compose([\n", - " transforms.ToTensor(),\n", - " transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))\n", - " ])\n", - "\n", - " # 데이터 모듈을 설정하는 메소드, 데이터 로드 후 훈련용과 테스트용 데이터 분류\n", - " def setup(self, stage=None):\n", - " dataset = CustomDataset(self.path_label, self.transform)\n", - " dataset_size = len(dataset)\n", - " train_size = int(0.8 * dataset_size)\n", - " test_size = dataset_size - train_size\n", - "\n", - " self.train_dataset = torch.utils.data.Subset(dataset, range(train_size))\n", - " self.test_dataset = torch.utils.data.Subset(dataset, range(train_size, dataset_size))\n", - "\n", - " def __len__(self): # 데이터셋의 길이 반환(훈련 or 테스트)\n", - " if self.train_dataset is not None:\n", - " return len(self.train_dataset)\n", - " elif self.test_dataset is not None:\n", - " return len(self.test_dataset)\n", - " else:\n", - " return 0\n", - "\n", - " # 인덱스를 사용해 하나의 샘플 데이터 반환(훈련 or 테스트)\n", - " def __getitem__(self, index):\n", - " if self.train_dataset is not None:\n", - " return self.train_dataset[index]\n", - " elif self.test_dataset is not None:\n", - " return self.test_dataset[index]\n", - " else:\n", - " raise IndexError(\"Index out of range. The dataset is empty.\")\n", - "\n", - " def train_dataloader(self): # 훈련용\n", - " return DataLoader(self.train_dataset, batch_size=self.batch_size, shuffle=True)\n", - "\n", - " def val_dataloader(self): # 검증용\n", - " return DataLoader(self.test_dataset, batch_size=self.batch_size)\n", - "\n", - " def test_dataloader(self): # 테스트용\n", - " return DataLoader(self.test_dataset, batch_size=self.batch_size)" - ], - "metadata": { - "id": "53FNJP1YgHbj" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "데이터셋을 훈련용과 테스트용으로 분리." - ], - "metadata": { - "id": "jYPpeOJQi0yP" - } - }, - { - "cell_type": "code", - "source": [ - "class DataModule(pl.LightningDataModule):\n", - "\n", - " def __init__(self, transform=transform, batch_size=32):\n", - " super().__init__()\n", - " self.root_dir = \"/content/\"\n", - " self.transform = transform # 위와 동일\n", - " self.batch_size = batch_size # 위와 동일\n", - "\n", - " # 데이터 모듈을 설정하는 메소드\n", - " def setup(self, stage=None):\n", - " dataset = datasets.ImageFolder(root=self.root_dir, transform=self.transform)\n", - " n_data = len(dataset)\n", - " n_train = int(0.8 * n_data)\n", - " n_test = n_data - n_train\n", - "\n", - " train_dataset, test_dataset = random_split(dataset, [n_train, n_test])\n", - "\n", - " # 훈련용과 테스트용 데이터셋을 데이터 로더로 변환\n", - " self.train_dataset = DataLoader(train_dataset, batch_size=self.batch_size, shuffle=True)\n", - " self.test_dataset = DataLoader(test_dataset, batch_size=self.batch_size)\n", - "\n", - " def train_dataloader(self):\n", - " return self.train_dataset\n", - "\n", - " def test_dataloader(self):\n", - " return self.test_dataset" - ], - "metadata": { - "id": "Y5pts3KHi1DJ" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "CNN 모델인데 PyTorch Lightning을 사용하여 간단한 구현이 가능." - ], - "metadata": { - "id": "sn_T53BOkn5K" - } - }, - { - "cell_type": "code", - "source": [ - "class ConvolutionalNetwork(LightningModule):\n", - "\n", - " # 이미지 데이터는 이곳에서 2개의 합성곱층과 3개의 전결합층을 거쳐 출력됨\n", - " def __init__(self): # 중요한 생성자\n", - " super(ConvolutionalNetwork, self).__init__()\n", - "\n", - " # 합성곱층은 2개\n", - " self.conv1 = nn.Conv2d(3, 6, 3, 1)\n", - " self.conv2 = nn.Conv2d(6, 16, 3, 1)\n", - "\n", - " # 실질적 전결합층은 3개, 각 메소드의 첫 인자는 이전 결과(출력)를 사용\n", - " self.fc1 = nn.Linear(16 * 54 * 54, 120) # 120개 뉴런\n", - " self.fc2 = nn.Linear(120, 84) # 84개 뉴런\n", - " self.fc3 = nn.Linear(84, 20) # 20개 뉴런\n", - " self.fc4 = nn.Linear(20, len(class_names)) # 여긴 softmax 함수 사용해 클래스 분류에 사용됨\n", - "\n", - " # 순전파 메소드\n", - " def forward(self, X):\n", - " X = F.relu(self.conv1(X)) # 활성화 함수 : ReLu\n", - " X = F.max_pool2d(X, 2, 2)\n", - " X = F.relu(self.conv2(X))\n", - " X = F.max_pool2d(X, 2, 2)\n", - " X = X.view(-1, 16 * 54 * 54)\n", - " X = F.relu(self.fc1(X))\n", - " X = F.relu(self.fc2(X))\n", - " X = F.relu(self.fc3(X))\n", - " X = self.fc4(X) # 최종 전결합층 거치기\n", - " return F.log_softmax(X, dim=1) # 활성화 함수 : softmax\n", - "\n", - " def configure_optimizers(self):\n", - " optimizer = torch.optim.Adam(self.parameters(), lr=0.001) # Adam 옵티마이저\n", - " return optimizer\n", - "\n", - " # 훈련 단계를 정의한 메소드, 손실값을 반환\n", - " def training_step(self, train_batch, batch_idx):\n", - " X, y = train_batch # 미니 배치\n", - " y_hat = self(X) # 예측된 y\n", - " loss = F.cross_entropy(y_hat, y) # 손실을 구함 : 교차 엔트로피 오차\n", - " pred = y_hat.argmax(dim=1, keepdim=True) # 예측값 : 가장 높은 확률을 가짐\n", - " acc = pred.eq(y.view_as(pred)).sum().item() / y.shape[0] # 정확도\n", - " self.log(\"train_loss\", loss)\n", - " self.log(\"train_acc\", acc)\n", - " return loss\n", - "\n", - " # 검증 단계를 정의한 메소드, 알고리즘은 위와 동일\n", - " def validation_step(self, val_batch, batch_idx):\n", - " X, y = val_batch\n", - " y_hat = self(X)\n", - " loss = F.cross_entropy(y_hat, y)\n", - " pred = y_hat.argmax(dim=1, keepdim=True)\n", - " acc = pred.eq(y.view_as(pred)).sum().item() / y.shape[0]\n", - " self.log(\"val_loss\", loss)\n", - " self.log(\"val_acc\", acc)\n", - "\n", - " # 테스트 단계를 정의한 메소드, 알고리즘은 위와 동일\n", - " def test_step(self, test_batch, batch_idx):\n", - " X, y = test_batch\n", - " y_hat = self(X)\n", - " loss = F.cross_entropy(y_hat, y)\n", - " pred = y_hat.argmax(dim=1, keepdim=True)\n", - " acc = pred.eq(y.view_as(pred)).sum().item() / y.shape[0]\n", - " self.log(\"test_loss\", loss)\n", - " self.log(\"test_acc\", acc)" - ], - "metadata": { - "id": "FJQM53fHkkm0" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "모델을 훈련시키고 테스트. if 구문을 아래와 같이 작성하면 해당 스크립트가 포함된 파일을 외부에서 import 해도 if 구문 내 스크립트는 실행되지 않음." - ], - "metadata": { - "id": "BHMi29ewonoy" - } - }, - { - "cell_type": "code", - "source": [ - "if __name__ == '__main__':\n", - " dataset = ImageDataset(path_label) # 데이터셋 변수 생성, 이미지 파일 경로와 레이블들이 튜플로 묶여있는 리스트 path_label\n", - "\n", - " dataset.setup() # 데이터를 훈련용과 테스트용으로 분리\n", - "\n", - " train_dataloader = dataset.train_dataloader() # 훈련용\n", - " test_dataloader = dataset.test_dataloader() # 테스트용\n", - "\n", - " datamodule = DataModule() # 데이터모듈 객체 생성\n", - "\n", - " datamodule.setup() # 데이터모듈 : 데이터를 훈련용과 테스트용으로 분리\n", - "\n", - " model = ConvolutionalNetwork() # CNN 모델 객체 생성\n", - "\n", - " trainer = pl.Trainer(max_epochs=30) # PyTorch Lightning Trainer : 30 epoch\n", - "\n", - " trainer.fit(model, datamodule) # CNN 모델 훈련 : 30회\n", - "\n", - " datamodule.setup(stage='test') # 데이터모듈 : 테스트 모드로 전환\n", - "\n", - " test_loader = datamodule.test_dataloader() # 데이터모듈 : 테스트용\n", - "\n", - " trainer.test(dataloaders=test_loader) # 테스트용으로 훈련된 모델을 평가" - ], - "metadata": { - "id": "FAJtO47aon9c" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "최종적으로 테스트셋 평가, 분류 결과를 분석." - ], - "metadata": { - "id": "-32Fom46rp6f" - } - }, - { - "cell_type": "code", - "source": [ - "device = torch.device(\"cpu\") # cuda:0 이면 GPU\n", - "\n", - "model.eval()\n", - "y_true=[]\n", - "y_pred=[]\n", - "with torch.no_grad():\n", - " for test_data in datamodule.test_dataloader():\n", - " test_images, test_labels = test_data[0].to(device), test_data[1].to(device)\n", - " pred = model(test_images).argmax(dim=1)\n", - " for i in range(len(pred)):\n", - " y_true.append(test_labels[i].item())\n", - " y_pred.append(pred[i].item())\n", - "\n", - "print(classification_report(y_true,y_pred,target_names=class_names,digits=4))" - ], - "metadata": { - "id": "GcggODqkrpn0" - }, - "execution_count": null, - "outputs": [] - } - ] -} \ No newline at end of file From 21d29952313117b71cc36aa395e140797d87c308 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 22 Jul 2023 17:48:30 +0900 Subject: [PATCH 44/99] Update README.md --- DeepLearning/CNN/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DeepLearning/CNN/README.md b/DeepLearning/CNN/README.md index e926907..bc2c49a 100644 --- a/DeepLearning/CNN/README.md +++ b/DeepLearning/CNN/README.md @@ -1 +1,3 @@ # CNN 구조 공부 + +[Markdown](Butterfly_Species.md) From 7aad2caba03bc0ba070d538174a09eb8614bba24 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 29 Jul 2023 21:44:04 +0900 Subject: [PATCH 45/99] Delete README.md --- MachineLearning/README.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 MachineLearning/README.md diff --git a/MachineLearning/README.md b/MachineLearning/README.md deleted file mode 100644 index 8b13789..0000000 --- a/MachineLearning/README.md +++ /dev/null @@ -1 +0,0 @@ - From 689de1e12251b5437cda55bbb30be42db397f3d7 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 29 Jul 2023 21:44:25 +0900 Subject: [PATCH 46/99] Rename MachineLearning/basicKNN.ipynb to MachineLearning/ipynb/basicKNN.ipynb --- MachineLearning/{ => ipynb}/basicKNN.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename MachineLearning/{ => ipynb}/basicKNN.ipynb (99%) diff --git a/MachineLearning/basicKNN.ipynb b/MachineLearning/ipynb/basicKNN.ipynb similarity index 99% rename from MachineLearning/basicKNN.ipynb rename to MachineLearning/ipynb/basicKNN.ipynb index 1f5409a..704fe29 100644 --- a/MachineLearning/basicKNN.ipynb +++ b/MachineLearning/ipynb/basicKNN.ipynb @@ -206,4 +206,4 @@ ] } ] -} \ No newline at end of file +} From 47737ad023bf2adf16e9afdc8ac19bd4dc803a03 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 29 Jul 2023 21:44:42 +0900 Subject: [PATCH 47/99] Rename MachineLearning/missingvalueimputation.ipynb to MachineLearning/ipynb/missingvalueimputation.ipynb --- MachineLearning/{ => ipynb}/missingvalueimputation.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename MachineLearning/{ => ipynb}/missingvalueimputation.ipynb (97%) diff --git a/MachineLearning/missingvalueimputation.ipynb b/MachineLearning/ipynb/missingvalueimputation.ipynb similarity index 97% rename from MachineLearning/missingvalueimputation.ipynb rename to MachineLearning/ipynb/missingvalueimputation.ipynb index 2df76c9..20f36b2 100644 --- a/MachineLearning/missingvalueimputation.ipynb +++ b/MachineLearning/ipynb/missingvalueimputation.ipynb @@ -1 +1 @@ -{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.10","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 데이터에 누락된 값이 있을 때 이를 채우거나 값을 예측하기","metadata":{}},{"cell_type":"markdown","source":"***pip install fancyimpute***","metadata":{}},{"cell_type":"code","source":"# 1\nimport numpy as np\nfrom fancyimpute import KNN\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.datasets import make_blobs\n\n# 모의 특성 행렬\nfeatures, _ = make_blobs(n_samples=1000, n_features=2, random_state=1)\n\n# 특성 표준화\nscaler = StandardScaler()\nstandardized_features = scaler.fit_transform(features)\n\n# 첫 번째 샘플의 첫 번째 특성을 삭제\ntrue_value = standardized_features[0,0]\nstandardized_features[0,0]=np.nan\n\n# 특성 행렬에 있는 누락된 값 예측\nfatures_knn_imputed = KNN(k=5, verbose=0).fit_transform(standardized_features)\n\n# 실제 값과 예측된 값 비교\nprint(\"실제 값 : \", true_value)\nprint(\"예측 값 : \", fatures_knn_imputed[0,0])","metadata":{"execution":{"iopub.status.busy":"2023-06-21T02:21:36.600409Z","iopub.execute_input":"2023-06-21T02:21:36.600764Z","iopub.status.idle":"2023-06-21T02:21:36.741717Z","shell.execute_reply.started":"2023-06-21T02:21:36.600742Z","shell.execute_reply":"2023-06-21T02:21:36.739885Z"},"trusted":true},"execution_count":17,"outputs":[{"name":"stdout","text":"실제 값 : 0.8730186113995938\n예측 값 : 1.0955332713113226\n","output_type":"stream"}]},{"cell_type":"code","source":"#2\nfrom sklearn.impute import SimpleImputer\n\nsimple_imputer = SimpleImputer()\nfeatures_simple_imputed = simple_imputer.fit_transform(features)\n\n# 실제 값과 대체된 값 비교\nprint(\"실제 값 : \", true_value)\nprint(\"대체 값 : \", features_simple_imputed[0,0])","metadata":{"execution":{"iopub.status.busy":"2023-06-21T02:18:30.167876Z","iopub.execute_input":"2023-06-21T02:18:30.168286Z","iopub.status.idle":"2023-06-21T02:18:30.177864Z","shell.execute_reply.started":"2023-06-21T02:18:30.168256Z","shell.execute_reply":"2023-06-21T02:18:30.176676Z"},"trusted":true},"execution_count":16,"outputs":[{"name":"stdout","text":"실제 값 : 0.8730186113995938\n예측 값 : -3.058372724614996\n","output_type":"stream"}]}]} \ No newline at end of file +{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.10","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 데이터에 누락된 값이 있을 때 이를 채우거나 값을 예측하기","metadata":{}},{"cell_type":"markdown","source":"***pip install fancyimpute***","metadata":{}},{"cell_type":"code","source":"# 1\nimport numpy as np\nfrom fancyimpute import KNN\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.datasets import make_blobs\n\n# 모의 특성 행렬\nfeatures, _ = make_blobs(n_samples=1000, n_features=2, random_state=1)\n\n# 특성 표준화\nscaler = StandardScaler()\nstandardized_features = scaler.fit_transform(features)\n\n# 첫 번째 샘플의 첫 번째 특성을 삭제\ntrue_value = standardized_features[0,0]\nstandardized_features[0,0]=np.nan\n\n# 특성 행렬에 있는 누락된 값 예측\nfatures_knn_imputed = KNN(k=5, verbose=0).fit_transform(standardized_features)\n\n# 실제 값과 예측된 값 비교\nprint(\"실제 값 : \", true_value)\nprint(\"예측 값 : \", fatures_knn_imputed[0,0])","metadata":{"execution":{"iopub.status.busy":"2023-06-21T02:21:36.600409Z","iopub.execute_input":"2023-06-21T02:21:36.600764Z","iopub.status.idle":"2023-06-21T02:21:36.741717Z","shell.execute_reply.started":"2023-06-21T02:21:36.600742Z","shell.execute_reply":"2023-06-21T02:21:36.739885Z"},"trusted":true},"execution_count":17,"outputs":[{"name":"stdout","text":"실제 값 : 0.8730186113995938\n예측 값 : 1.0955332713113226\n","output_type":"stream"}]},{"cell_type":"code","source":"#2\nfrom sklearn.impute import SimpleImputer\n\nsimple_imputer = SimpleImputer()\nfeatures_simple_imputed = simple_imputer.fit_transform(features)\n\n# 실제 값과 대체된 값 비교\nprint(\"실제 값 : \", true_value)\nprint(\"대체 값 : \", features_simple_imputed[0,0])","metadata":{"execution":{"iopub.status.busy":"2023-06-21T02:18:30.167876Z","iopub.execute_input":"2023-06-21T02:18:30.168286Z","iopub.status.idle":"2023-06-21T02:18:30.177864Z","shell.execute_reply.started":"2023-06-21T02:18:30.168256Z","shell.execute_reply":"2023-06-21T02:18:30.176676Z"},"trusted":true},"execution_count":16,"outputs":[{"name":"stdout","text":"실제 값 : 0.8730186113995938\n예측 값 : -3.058372724614996\n","output_type":"stream"}]}]} From 24f203a3cfe0eaa51b4ff26f949f444493f6b4fb Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 29 Jul 2023 21:45:31 +0900 Subject: [PATCH 48/99] Create EADME_GrowTopia_STAT.md --- .../READMES/EADME_GrowTopia_STAT.md | 225 ++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 MachineLearning/READMES/EADME_GrowTopia_STAT.md diff --git a/MachineLearning/READMES/EADME_GrowTopia_STAT.md b/MachineLearning/READMES/EADME_GrowTopia_STAT.md new file mode 100644 index 0000000..13e7e53 --- /dev/null +++ b/MachineLearning/READMES/EADME_GrowTopia_STAT.md @@ -0,0 +1,225 @@ +# 직접 하는 회귀 분석 +## 게임 내 아이템 거래 시장에 대한 통계적 분석이 필요하여 직접 데이터를 기록하고 적합한 선형 회귀 모델을 만들어 앞으로의 활동을 전략적으로 해 나가려는 목적(Profit Maximization). +--- +- 작성한 ipynb 파일(1차) : [ipynb file](https://github.com/CharmStrange/Snippet/blob/main/Python/ipynb/GrowTopia_stat(V2).ipynb) +- 작성한 py 파일(1차) : [py file](https://github.com/CharmStrange/Snippet/blob/main/Python/growtopia_stat(V2).py) +--- +### 1. 분석에 필요한 데이터의 정의, 수집 +먼저 아이템 거래에 대해 분석을 하려면 '***재고 보충량***', '***팔린 물품 수***', '***광고 게재 수***', '***방문자 수***' 정보가 필요하다. 여기서 모든 수치는 하루 기준이며 하루가 지나면 새로 기록을 해 주어야 한다. +``` +# 데이터 형태 정의 + +import pandas as pd + +Columns = ['Number of Restock', 'Number of sold items', 'Number of ADS', 'Number of Visitors'] +Index = ['Day 1', 'Day 2', 'Day 3', 'Day 4', 'Day 5', 'Day 6', 'Day 7', 'Day 8', 'Day 9', 'Day 10'] +``` +효율적인 데이터 관리를 위해 ***pandas***를 사용한 데이터프레임을 사용했다. + + +``` +# 데이터 수집, 구체화 + +DailyData=[ + [2200, 2200, 7, 4], + [3515, 2400, 8, 3], + [2400, 2400, 5, 4], + [4991, 4800, 14, 5], + [1231, 200, 1, 1], + [911, 0, 0, 0], + [0, 800, 0, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + [1800, 800, 6, 2] +] +Data = pd.DataFrame(DailyData, columns=Columns, index=Index) +Data.to_csv('DailyData.csv') +``` +image + +그리고 실제 기록한 10일간의 데이터를 작성해 주고 csv 파일로 저장해준다. + +--- +### 2. 데이터로부터 얻어낼 수 있는 인사이트 +일단 '***광고 게재 수***'(*독립 변수*)에 따른 '***방문자 수***'(*종속 변수*)와, '***재고 보충량***'(*독립 변수*)에 따른 '***팔린 물품 수***'(*종속 변수*)를 집중적으로 분석하기로 했다. +``` +# 데이터 관계의 선형성 확인 + +import matplotlib.pyplot as plt + +# Linearity Checking + +Data.plot(x='Number of ADS', y='Number of Visitors', style='o') +plt.title("Number of Visitors vs Number of ADS") +plt.xlabel('Number of ADS') +plt.ylabel('Number of Visitors') +plt.show() + +Data.plot(x='Number of Restock', y='Number of sold items', style='o') +plt.title("Number of sold items vs Number of Restock") +plt.xlabel('Number of Restock') +plt.ylabel('Number of sold items') +plt.show() +``` +image +image + +데이터 분포의 선형성을 확인하기 위해 시각화를 해 보았다. 데이터가 10개임에도 불구하고 뚜렷하게 선형성이 나타는 것으로 보아 회귀 분석이 적합할 것으로 예상된다. + +--- +### 3. 분석 시작 +``` +# 모델 구현 + +from sklearn.linear_model import LinearRegression + +LR_V = LinearRegression() +LR_S = LinearRegression() + +LR_V.fit(Data['Number of ADS'].values.reshape(-1, 1), Data['Number of Visitors'].values.reshape(-1, 1)) +LR_S.fit(Data['Number of Restock'].values.reshape(-1, 1), Data['Number of sold items'].values.reshape(-1, 1)) +``` +라이브러리를 사용해 회귀 분석을 시작했다. ***.fit()*** 메소드는 파라미터에 2차원 배열이 들어가야 하므로 인자로 들어갈 데이터의 형태 변환을 알맞게 해 주었다. +``` +# 예측 시도 + +predicted_visitors = LR.predict( [ [13], [14] ] ) +predicted_sold_items = LR.predict( [ [4800], [3200], [600] ] ) +``` +이제 모델에 독립 변수를 테스트삼아 넣어본다. 위 코드에선 '***광고 게재 수***' : **13**, **14** 이고 '***재고 보충량***' : **4800**, **3200**, **600** 이다. +``` +# 결과 확인 + +print('predicted visitors : ', predicted_visitors) +>>> predicted visitors : [[5.20206999], [5.56185313]] + +print('predicted sold items : ', predicted_sold_items) +>>> predicted sold items : [ [4087.96704049], [2677.80056828], [ 386.28005094] ] +``` +예측된 결과를 회귀 직선 그래프를 그려 표현하면 아래와 같다. +``` +# 회귀 직선 그래프 그리기 + +plt.scatter(Data['Number of ADS'], Data['Number of Visitors'], color='blue', label='Actual') +plt.plot(Data['Number of ADS'], LR_V.predict(Data['Number of ADS'].values.reshape(-1, 1)), color='red', label='Predicted') +plt.xlabel('Number of ADS') +plt.ylabel('Number of Visitors') +plt.title('Number of ADS vs Number of Visitors') +plt.legend() +plt.show() + +plt.scatter(Data['Number of Restock'], Data['Number of sold items'], color='blue', label='Actual') +plt.plot(Data['Number of Restock'], LR_S.predict(Data['Number of Restock'].values.reshape(-1, 1)), color='red', label='Predicted') +plt.xlabel('Number of Restock') +plt.ylabel('Number of sold items') +plt.title('Number of Restock vs Number of sold items') +plt.legend() +plt.show() +``` +image +image + +``` +# 오차 구하기 + +mse_visitors = mean_squared_error(Data['Number of Visitors'].values.reshape(-1, 1), predicted_visitors) +mse_sold_items = mean_squared_error(Data['Number of sold items'].values.reshape(-1, 1), predicted_sold_items) + +print('MSE of visitors: ', mse_visitors) +print('MSE of sold items: ', mse_sold_items) +``` +``` +>>> +MSE of visitors: 3.5810438634865918 +MSE of sold items: 1392562.4923213236 +``` +오차가 좀 크긴 하지만 고작 10개의 데이터 치고는 괜찮은 직선의 모습이다. 데이터가 너무 적은 것이 원인인 듯 하지만 현재보다 더 많은 실제 데이터를 축적해 나가면 더욱 괜찮은 예측치를 알아낼 수 있을 것이다. + +추가로 데이터를 스케일링하면 오차가 좀 줄어들지 않을까 싶어서 해 보았는데 큰 차이는 없었다. 역시나 데이터 수의 부족함이 문제되는것 같다. +``` +from sklearn.preprocessing import StandardScaler + +# Standardization +scaler = StandardScaler() +scaled_Data_std = scaler.fit_transform(Data) + +scaled_Data_std_df = pd.DataFrame(scaled_Data_std, columns=Columns, index=Index) + +scaled_Data_std_df + +LR_V = LinearRegression() +LR_S = LinearRegression() + +LR_V.fit(scaled_Data_std_df['Number of ADS'].values.reshape(-1, 1), scaled_Data_std_df['Number of Visitors'].values.reshape(-1, 1)) +LR_S.fit(scaled_Data_std_df['Number of Restock'].values.reshape(-1, 1), scaled_Data_std_df['Number of sold items'].values.reshape(-1, 1)) + +predicted_visitors = LR_V.predict([[13], [14], [8], [7], [7], [0], [0], [0], [9], [10]]) # give Number of ADS in params +predicted_sold_items = LR_S.predict([[4800], [3200], [600], [6600], [1200], [800], [0], [600], [1561], [2800]]) # give Number of Restock in params + +# Adjust negative predictions to 0 +predicted_visitors = [max(0, value[0]) for value in predicted_visitors] +predicted_sold_items = [max(0, value[0]) for value in predicted_sold_items] + +print('predicted visitors:', predicted_visitors) +print('predicted sold items:', predicted_sold_items) + +# Calculate MSE +mse_visitors = mean_squared_error(scaled_Data_std_df['Number of Visitors'].values.reshape(-1, 1), predicted_visitors) +mse_sold_items = mean_squared_error(scaled_Data_std_df['Number of sold items'].values.reshape(-1, 1), predicted_sold_items) + +print('MSE of visitors: ', mse_visitors) +print('MSE of sold items: ', mse_sold_items) +``` +``` +predicted visitors: [11.77742099917544, 12.683376460650475, 7.247643691800271, 6.3416882303252375, 6.3416882303252375, 0, 0, 0, 8.153599153275305, 9.05955461475034] +predicted sold items: [4431.605755547653, 2954.4038370317685, 553.9507194434566, 6093.457913878022, 1107.9014388869132, 738.6009592579421, 8.88241302397551e-17, 553.9507194434566, 1441.1951217520595, 2585.1033574027974] + +MSE of visitors: 53.84245232013412 +MSE of sold items: 7661501.684724535 +``` + +``` +from sklearn.preprocessing import MinMaxScaler + +# Normalization +scaler = MinMaxScaler() +scaled_Data_mms = scaler.fit_transform(Data) + +scaled_Data_mms_df = pd.DataFrame(scaled_Data_mms, columns=Columns, index=Index) + +scaled_Data_mms_df + +LR_V = LinearRegression() +LR_S = LinearRegression() + +LR_V.fit(scaled_Data_mms_df['Number of ADS'].values.reshape(-1, 1), scaled_Data_mms_df['Number of Visitors'].values.reshape(-1, 1)) +LR_S.fit(scaled_Data_mms_df['Number of Restock'].values.reshape(-1, 1), scaled_Data_mms_df['Number of sold items'].values.reshape(-1, 1)) + +predicted_visitors = LR_V.predict([[13], [14], [8], [7], [7], [0], [0], [0], [9], [10]]) # give Number of ADS in params +predicted_sold_items = LR_S.predict([[4800], [3200], [600], [6600], [1200], [800], [0], [600], [1561], [2800]]) # give Number of Restock in params + +# Adjust negative predictions to 0 +predicted_visitors = [max(0, value[0]) for value in predicted_visitors] +predicted_sold_items = [max(0, value[0]) for value in predicted_sold_items] + +print('predicted visitors:', predicted_visitors) +print('predicted sold items:', predicted_sold_items) + +# Calculate MSE +mse_visitors = mean_squared_error(scaled_Data_mms_df['Number of Visitors'].values.reshape(-1, 1), predicted_visitors) +mse_sold_items = mean_squared_error(scaled_Data_mms_df['Number of sold items'].values.reshape(-1, 1), predicted_sold_items) + +print('MSE of visitors: ', mse_visitors) +print('MSE of sold items: ', mse_sold_items) +``` +``` +predicted visitors: [13.201084277969446, 14.208477082306558, 8.164120256283885, 7.156727451946773, 7.156727451946773, 0.1049778215869886, 0.1049778215869886, 0.1049778215869886, 9.171513060620997, 10.178905864958109] +predicted sold items: [4398.808345002317, 2932.5289985865347, 549.8250606608892, 6048.3726097200715, 1099.6798155668075, 733.109978962862, 0, 549.8250606608892, 1430.5090931018683, 2565.959161982589] + +MSE of visitors: 65.92838783134934 +MSE of sold items: 7549335.969611017 +``` + +--- +### 결론 +이번에 진행한 회귀 분석은 머신 러닝에서 주로 사용하는 사이킷런 라이브러리의 알고리즘만 빌려와 주어진 데이터에서 유의미한 인사이트를 추출하는데에 그쳤다. 하지만 더 나아가 레이블 제공, 오차 줄이기, 데이터 크롤링 봇 제작에 활용 등 기능을 향상시켜 많은 유저들이 사용 가능한 프로그램(소스 코드 공개)이 될 수 있게끔 만들어 보겠다. From 71eb88188ce71033a65242d1ff26950735bbe4fd Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 29 Jul 2023 21:45:52 +0900 Subject: [PATCH 49/99] Rename EADME_GrowTopia_STAT.md to README_GrowTopia_STAT.md --- .../READMES/{EADME_GrowTopia_STAT.md => README_GrowTopia_STAT.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename MachineLearning/READMES/{EADME_GrowTopia_STAT.md => README_GrowTopia_STAT.md} (100%) diff --git a/MachineLearning/READMES/EADME_GrowTopia_STAT.md b/MachineLearning/READMES/README_GrowTopia_STAT.md similarity index 100% rename from MachineLearning/READMES/EADME_GrowTopia_STAT.md rename to MachineLearning/READMES/README_GrowTopia_STAT.md From 94497f5701f0799bd28b57fcc9cf3055ac56d44f Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 29 Jul 2023 21:47:44 +0900 Subject: [PATCH 50/99] Add files via upload --- .../ipynb/GrowTopia_stat(V2).ipynb | 423 ++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 MachineLearning/ipynb/GrowTopia_stat(V2).ipynb diff --git a/MachineLearning/ipynb/GrowTopia_stat(V2).ipynb b/MachineLearning/ipynb/GrowTopia_stat(V2).ipynb new file mode 100644 index 0000000..d04930d --- /dev/null +++ b/MachineLearning/ipynb/GrowTopia_stat(V2).ipynb @@ -0,0 +1,423 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "code", + "source": [ + "import pandas as pd\n", + "\n", + "# Train Data\n", + "DailyData=[\n", + " [2200, 2200, 7, 4],\n", + " [3515, 2400, 8, 3],\n", + " [2400, 2400, 5, 4],\n", + " [4991, 4800, 14, 5],\n", + " [1231, 200, 1, 1],\n", + " [911, 0, 0, 0],\n", + " [0, 800, 0, 1],\n", + " [0, 0, 0, 0],\n", + " [0, 0, 0, 0],\n", + " [1800, 800, 6, 2]\n", + "]\n", + "\n", + "Index = ['Day 1', 'Day 2', 'Day 3', 'Day 4', 'Day 5', 'Day 6', 'Day 7', 'Day 8', 'Day 9', 'Day 10']\n", + "\n", + "Columns = ['Number of Restock', 'Number of sold items', 'Number of ADS', 'Number of Visitors']\n", + "\n", + "Data = pd.DataFrame(DailyData, columns=Columns, index=Index)\n", + "\n", + "Data.to_csv('DailyData.csv')\n", + "\n", + "\n", + "# Test Data\n", + "DailyData_t=[\n", + " [3400, 3000, 12, 6],\n", + " [400, 0, 0, 0],\n", + " [400, 400,0, 1],\n", + " [0, 0, 0, 1],\n", + " [4600, 3200, 9, 3],\n", + " [4000, 1200, 3, 2],\n", + " [0, 0, 0, 1],\n", + " [3991, 3000, 4, 3],\n", + " [5250, 3800, 13, 4],\n", + " [6535, 7500, 21, 7]\n", + "]\n", + "\n", + "Data_t = pd.DataFrame(DailyData_t, columns=Columns, index=Index)\n", + "\n", + "Data_t.to_csv('DailyData_t.csv')" + ], + "metadata": { + "id": "hbmDhcgyGTaE" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Checking Data\n", + "\n", + "import statistics\n", + "\n", + "# Data['Number of Restock']\n", + "print(statistics.mean(Data['Number of Restock']))\n", + "\n", + "# Data['Number of sold items']\n", + "print(statistics.mean(Data['Number of sold items']))\n", + "\n", + "# Data['Number of ADS']\n", + "print(statistics.mean(Data['Number of ADS']))\n", + "\n", + "# Data['Number of Visitors']\n", + "print(statistics.mean(Data['Number of Visitors']))\n", + "\n", + "print(statistics.mean(Data_t['Number of Restock']))\n", + "print(statistics.mean(Data_t['Number of sold items']))\n", + "print(statistics.mean(Data_t['Number of ADS']))\n", + "print(statistics.mean(Data_t['Number of Visitors']))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "q_zv2xg-KSPQ", + "outputId": "ebb5887b-296f-4eed-8104-628839e1aee9" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "1704.8\n", + "1360\n", + "4.1\n", + "2\n", + "2857.6\n", + "2210\n", + "6.2\n", + "2.8\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "# Linearity Checking\n", + "\n", + "Data.plot(x='Number of ADS', y='Number of Visitors', style='o')\n", + "plt.title(\"Number of Visitors vs Number of ADS\")\n", + "plt.xlabel('Number of ADS')\n", + "plt.ylabel('Number of Visitors')\n", + "plt.show()\n", + "\n", + "Data.plot(x='Number of Restock', y='Number of sold items', style='o')\n", + "plt.title(\"Number of sold items vs Number of Restock\")\n", + "plt.xlabel('Number of Restock')\n", + "plt.ylabel('Number of sold items')\n", + "plt.show()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 927 + }, + "id": "JYiJtD5QNmwr", + "outputId": "748f42df-f06c-493c-857d-0adc5ef248f0" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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GYn3338fTZo0QVxcHC5dulRhtdja2qJ169YYNmwYbt68ifnz56Nu3bqqS2OlUilWrFiBLl26wMfHB8OGDcNrr72Gf//9F7GxsbC2ttb6sshin3zyCTZt2oQuXbpg7NixsLW1xdq1a5GamoqffvoJUunL/X0wcOBAjBw5Eunp6WW65DM3NxcuLi7o06cP/P39YWlpiX379uHEiROl3ocGeNId4O3tjS1btqBevXqwtbWFr68vfH198fXXX6NLly5o0aIFQkND8fDhQyxcuBByubxM3zF06dIldOjQAcHBwfD29oaRkRF27NiBmzdvqg00LY29vT3at2+PefPmITc3V6Pb58CBAxg9ejT69u2LevXqoaioSPXXennuNCuTyfDpp5+WOODUx8cHzZs3R3h4OO7evQtbW1ts3rxZIyjpUmpqKrp3747OnTvj6NGj2LBhA9577z34+/sDeBKevvrqK4SHhyMtLQ09e/aElZUVUlNTsWPHDowcOfK5d0N+npd97Z91/PhxXLlypdSvJXjttdfQqFEjREdHY8qUKarp//77r+rM24MHD5CUlIRt27YhMzMTEydOxAcffKBqu3fvXkRERKB79+5o3rw5LC0tcfXqVaxatQqFhYXlqpv0yEBXG1El9vTlyc8aMmSIAEDt8mRBeHJ5YGhoqCCXywUrKyshODhYyMrKKvXy5Fu3bmmst/iS0ac9eyl08SWRmzZtEsLDwwV7e3vBzMxM6Nq1q3Dt2jWN5c+cOSP06tVLsLOzE0xMTARXV1chODhY2L9//wtrep6UlBShT58+go2NjWBqaio0bdpU2L17t0Y7aHF5crG7d+8KJiYmAgAhKSmpxDZPH9fCwkJh8uTJgr+/v2BlZSVYWFgI/v7+wpIlS9SWefbyZEEQhL/++kto3LixYGxsrPFa7du3T2jVqpVgZmYmWFtbC0FBQRr1lHbsbt++LYSFhQn169cXLCwsBLlcLjRr1kzYunVrmY/D8uXLBQCClZWV8PDhQ7V5V69eFYYPHy64u7sLpqamgq2trdC+fXth3759L1xvae+1x48fC+7u7iW+ZikpKULHjh0FExMTwcHBQZg6daqwd+/eEi9PfvZnQxBKv9z22W0VH8+kpCShT58+gpWVlVC9enVh9OjRGsdAEAThp59+Elq3bi1YWFgIFhYWQv369YWwsDC1S9xLq+l5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Bw9+4eXJRERERLpU5qCyZs2aCiyDiIiISBPvTEtERESixaBCREREosWgQkRERKLFoEJERESixaBCREREosWgQkRERKLFoEJERESixaBCREREosWgQkRERKLFoEJERESixaBCREREosWgQkRERKLFoEJERESixaBCREREosWgQkRERKLFoEJERESixaBCREREosWgQkRERKLFoEJERESixaBCREREosWgQkRERKLFoEJERESixaBCREREosWgQkRERKLFoEJERESixaBCREREosWgQkRERKLFoEJERESixaBCREREosWgQkRERKJl0KASFxeHoKAgODs7QyKR4OeffzZkOSoKpYCjKXfwS8K/OJpyBwqlUKW2T0REJBZGhtx4Xl4e/P39MXz4cPTq1cuQpajEJGZg+q4kZGQXqKY5yU0REeSNzr5Or/z2iYiIxEQiCIIo/lyXSCTYsWMHevbsWeZlcnJyIJfLkZ2dDWtr65euISYxAx9tOI1nD4jk//9dOrBRhYYFQ2+fiIhIH7T5/OYYlf+nUAqYvitJIyQAUE2bviupwrphDL19IiIiMapUQaWwsBA5OTlqD12JT72r1t3yLAFARnYB4lPv6mybYto+ERGRGFWqoDJ79mzI5XLVo1atWjpbd1Zu6SGhPO0q2/aJiIjEqFIFlfDwcGRnZ6seN27c0Nm67a1Mddqusm2fiIhIjAx61Y+2TExMYGJiUiHrbupmCye5KTKzC0ocJyIB4Cg3RVM321dy+0RERGJk0DMqDx48QEJCAhISEgAAqampSEhIwPXr1/Vei0wqQUSQN4D/rrIpVvw8IsgbMumzc1+N7RMREYmRQS9PPnjwINq3b68xfciQIVizZs0Ll9f15cmA4e9jYujtExERVTRtPr9Fcx+V8qiIoAI8uVQ4PvUusnILYG/1pLtFn2cyDL19IiKiiqTN53elGqOiLzKpBC3c7ars9omIiMSiUl31Q0RERFULgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYkWgwoRERGJFoMKERERiRaDChEREYmWkaELEKOHjxSY9VsS0u7ko46dOaa+4w0zY5mhyyIiIqpyRHFGZfHixahTpw5MTU3RrFkzxMfHG6yWEetOwOuLGKw/dh1/Xr6N9ceuw+uLGIxYd8JgNREREVVVBg8qW7ZswYQJExAREYHTp0/D398fgYGByMrK0nstI9adwN6kkre7NymLYYWIiEjPDB5U5s2bhxEjRmDYsGHw9vbGsmXLYG5ujlWrVum1joePFKWGlGJ7k7Lw8JFCTxURERGRQYPKo0ePcOrUKXTs2FE1TSqVomPHjjh69KhG+8LCQuTk5Kg9dGXWb0k6bUdEREQvz6BB5fbt21AoFHBwcFCb7uDggMzMTI32s2fPhlwuVz1q1aqls1rS7uTrtB0RERG9PIN3/WgjPDwc2dnZqseNGzd0tu46duY6bUdEREQvz6BBpUaNGpDJZLh586ba9Js3b8LR0VGjvYmJCaytrdUeujL1HW+dtiMiIqKXZ9CgYmxsjMaNG2P//v2qaUqlEvv370eLFi30WouZsQydvO2f26aTtz3vp0JERKRHBu/6mTBhApYvX461a9fiwoUL+Oijj5CXl4dhw4bpvZblg98oNax08rbH8sFv6LkiIiKiqs3gd6bt168fbt26hS+++AKZmZkICAhATEyMxgBbfVk++A3emZaIiEgkJIIgCIYuorxycnIgl8uRnZ2t0/EqREREVHG0+fw2eNcPERERUWkYVIiIiEi0GFSIiIhItBhUiIiISLQYVIiIiEi0GFSIiIhItBhUiIiISLQYVIiIiEi0GFSIiIhItAx+C/2XUXxT3ZycHANXQkRERGVV/LldlpvjV+qgkpubCwCoVauWgSshIiIibeXm5kIulz+3TaX+rh+lUon09HRYWVlBIpHodN05OTmoVasWbty4USW/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\n" + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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CQCgffv2cHNzQ//+/TF37lwkJibi66+/RkBAAIyNjQEAI0eOxNKlSzF58mQMGTIEBw8exObNm7F79+7S3WAiIiIqs7Q6qPpNFixYAD09PfTs2RNZWVnw8/PD8uXLpfn6+vrYtWsXRo0aBR8fH5ibm2PgwIGYNWuW1MbFxQW7d+/G+PHjsWjRIlSuXBlr166Fn5+fNjaJiIiIyiCtX4eoPOB1iIiIiMqfcnUdIiIiIiJtYyAiIiIincdARERERDqPgYiIiIh0HgMRERER6TwGIiIiItJ5DERERESk8xiIiIiISOcxEBEREZHOYyAiIiIincdARERERDqPgYiIiIh0HgMRERER6TwGIiIiItJ5DERERESk8xiIiIiISOcxEBEREZHOYyAiIiIincdARERERDqPgYiIiIh0HgMRERER6TwGIiIiItJ5DERERESk8xiIiIiISOcxEBEREZHOYyAiIiIincdARERERDqPgYiIiIh0HgMRERER6TwGIiIiItJ5DERERESk8xiIiIiISOepHYju3r2Le/fuSc8jIyMxbtw4rF69WqOFEREREZUWtQPRp59+ikOHDgEAEhMT0a5dO0RGRuKrr77CrFmzNF4gERERUUlTOxBFR0fD29sbALB582a4u7vjxIkT+PXXXxEaGqrp+oiIiIhKnNqB6NmzZzA2NgYA/PXXX+jatSsAoE6dOkhISNBsdURERESlQO1AVLduXaxcuRJ///03wsPD0aFDBwBAfHw8bG1tNV4gERERUUlTOxDNmTMHq1atQuvWrdGnTx94enoCAHbs2CEdSiMiIiIqT2RCCKHui3Jzc5Geng5ra2tp2q1bt2BmZgZ7e3uNFlgWpKenw8rKCmlpaZDL5douh4iIiIpAnd9vg+KsQF9fXyUMAUDVqlWLsygiIiIirVM7ED148ADTp0/HoUOHkJycjLy8PJX5KSkpGiuOiIiIqDSoHYj69++PGzduwN/fHw4ODpDJZCVRFxEREVGpUTsQ/f333zh27Jg0mJqIiIiovFP7LLM6derg6dOnJVELERERkVaoHYiWL1+Or776CkeOHMGDBw+Qnp6u8iAiIiIqb9Q+ZKZQKJCeno42bdqoTBdCQCaTITc3V2PFEREREZUGtQNR3759YWhoiA0bNnBQNREREb0T1A5E0dHROHfuHGrXrl0S9RARERGVOrXHEDVq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\n" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "If the number of ADS is 0 and the number of visitors is greater than 1, it indicates a returning visitor." + ], + "metadata": { + "id": "kIqeLul6aok0" + } + }, + { + "cell_type": "code", + "source": [ + "from sklearn.linear_model import LinearRegression\n", + "import numpy as np\n", + "\n", + "LR_V = LinearRegression()\n", + "LR_S = LinearRegression()\n", + "\n", + "LR_V.fit(Data['Number of ADS'].values.reshape(-1, 1), Data['Number of Visitors'].values.reshape(-1, 1))\n", + "LR_S.fit(Data['Number of Restock'].values.reshape(-1, 1), Data['Number of sold items'].values.reshape(-1, 1))\n", + "\n", + "predicted_visitors = LR_V.predict([[13], [14], [8], [7], [7], [0], [0], [0], [9], [10]]) # give Number of ADS in params\n", + "predicted_sold_items = LR_S.predict([[4800], [3200], [600], [6600], [1200], [800], [0], [600], [1561], [2800]]) # give Number of Restock in params\n", + "\n", + "# Adjust negative predictions to 0\n", + "predicted_visitors = [max(0, value[0]) for value in predicted_visitors]\n", + "predicted_sold_items = [max(0, value[0]) for value in predicted_sold_items]\n", + "\n", + "print('predicted visitors:', predicted_visitors)\n", + "print('predicted sold items:', predicted_sold_items)\n" + ], + "metadata": { + "id": "WAJ0IHLnYzXY", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "d1a0d7c0-ea4d-4213-abf8-ae2bcb7ece72" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "predicted visitors: [5.202069985214392, 5.561853129620504, 3.4031542631838345, 3.0433711187777233, 3.0433711187777233, 0.5248891079349434, 0.5248891079349434, 0.5248891079349434, 3.7629374075899458, 4.122720551996058]\n", + "predicted sold items: [4087.967040488557, 2677.8005682794296, 386.2800509395978, 5674.404321723825, 915.0924780180205, 562.5508599657387, 0, 386.2800509395978, 1233.2612883102047, 2325.2589502271476]\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "plt.scatter(Data['Number of ADS'], Data['Number of Visitors'], color='blue', label='Actual')\n", + "plt.plot(Data['Number of ADS'], LR_V.predict(Data['Number of ADS'].values.reshape(-1, 1)), color='red', label='Predicted')\n", + "plt.xlabel('Number of ADS')\n", + "plt.ylabel('Number of Visitors')\n", + "plt.title('Number of ADS vs Number of Visitors')\n", + "plt.legend()\n", + "plt.show()\n", + "\n", + "plt.scatter(Data['Number of Restock'], Data['Number of sold items'], color='blue', label='Actual')\n", + "plt.plot(Data['Number of Restock'], LR_S.predict(Data['Number of Restock'].values.reshape(-1, 1)), color='red', label='Predicted')\n", + "plt.xlabel('Number of Restock')\n", + "plt.ylabel('Number of sold items')\n", + "plt.title('Number of Restock vs Number of sold items')\n", + "plt.legend()\n", + "plt.show()\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 927 + }, + "id": "kRuzQKt4xlOU", + "outputId": "9d718478-2c30-44fb-b513-93d0ed7dee38" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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\n" + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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YGOjXExEREQmiBUiJVlYAM2bS39ft04aOM1kiIiIqMCxQqQklQrIdm8kIiIiUgYrRERERGTymBARERGRyWNCRERERCaPCRERERGZPCZEREREZPKYEBEREZHJY0JEREREJo8JEREREZk8JkRERERk8pgQERERkcljQkREREQmjwkRERERmTwmRERERGTymBARERGRybNQOoDCQAgBAEhMTFQ4EiIiIsqtrO/trO/xV2FClAtJSUkAAE9PT4UjISIiIn0lJSXB0dHxlX1UIjdpk4nLzMzE3bt34eDgAJVKZdB1JyYmwtPTE7dv34ZGozHouuk5HueCw2NdMHicCwaPc8HJj2MthEBSUhLc3d1hZvbqUUKsEOWCmZkZPDw88nUbGo2Gv2wFgMe54PBYFwwe54LB41xwDH2sX1cZysJB1URERGTymBARERGRyWNCpDC1Wo3JkydDrVYrHUqRxuNccHisCwaPc8HgcS44Sh9rDqomIiIik8cKEREREZk8JkRERERk8pgQERERkcljQkREREQmjwmRghYtWgRvb29YW1ujXr16OHHihNIhGbXDhw+jXbt2cHd3h0qlwpYtW2TLhRCYNGkSSpUqBRsbGwQEBODq1auyPg8fPkSPHj2g0Wjg5OSE/v374/Hjx7I+586dQ6NGjWBtbQ1PT0/MmjUrv3fNqAQHB+Ott96Cg4MDXFxc0KFDB0RERMj6PHv2DEFBQShRogTs7e3RqVMnxMbGyvrcunULbdu2ha2tLVxcXDB27Fikp6fL+hw8eBC1a9eGWq1G+fLlsXr16vzePaOyZMkS1KhRQ3sjOn9/f+zatUu7nMc5f8ycORMqlQojR47UtvFYv7kpU6ZApVLJXpUrV9YuN/pjLEgRv/76q7CyshLff/+9uHjxohgwYIBwcnISsbGxSodmtHbu3Ck+//xzsWnTJgFAbN68WbZ85syZwtHRUWzZskWcPXtWvP/++8LHx0c8ffpU26dVq1bCz89PHDt2TBw5ckSUL19edOvWTbs8ISFBuLq6ih49eogLFy6IX375RdjY2Ihly5YV1G4qLjAwUKxatUpcuHBBhIeHizZt2ogyZcqIx48fa/sMGjRIeHp6in379omTJ0+K+vXri3feeUe7PD09XVSrVk0EBASIM2fOiJ07d4qSJUuKCRMmaPtcv35d2NraitGjR4tLly6JBQsW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\n" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "code", + "source": [ + "# Calculate MSE\n", + "mse_visitors = mean_squared_error(Data['Number of Visitors'].values.reshape(-1, 1), predicted_visitors)\n", + "mse_sold_items = mean_squared_error(Data['Number of sold items'].values.reshape(-1, 1), predicted_sold_items)\n", + "\n", + "print('MSE of visitors: ', mse_visitors)\n", + "print('MSE of sold items: ', mse_sold_items)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "wEYtZCglPUGj", + "outputId": "95abe7c8-94d1-408d-a7be-95826f31baaf" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "MSE of visitors: 3.5810438634865918\n", + "MSE of sold items: 1392562.4923213236\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "---" + ], + "metadata": { + "id": "cpkyc0xTddaC" + } + }, + { + "cell_type": "code", + "source": [ + "from sklearn.preprocessing import StandardScaler\n", + "\n", + "# Standardization\n", + "scaler = StandardScaler()\n", + "scaled_Data_std = scaler.fit_transform(Data)\n", + "\n", + "scaled_Data_std_df = pd.DataFrame(scaled_Data_std, columns=Columns, index=Index)\n", + "\n", + "scaled_Data_std_df\n", + "\n", + "LR_V = LinearRegression()\n", + "LR_S = LinearRegression()\n", + "\n", + "LR_V.fit(scaled_Data_std_df['Number of ADS'].values.reshape(-1, 1), scaled_Data_std_df['Number of Visitors'].values.reshape(-1, 1))\n", + "LR_S.fit(scaled_Data_std_df['Number of Restock'].values.reshape(-1, 1), scaled_Data_std_df['Number of sold items'].values.reshape(-1, 1))\n", + "\n", + "predicted_visitors = LR_V.predict([[13], [14], [8], [7], [7], [0], [0], [0], [9], [10]]) # give Number of ADS in params\n", + "predicted_sold_items = LR_S.predict([[4800], [3200], [600], [6600], [1200], [800], [0], [600], [1561], [2800]]) # give Number of Restock in params\n", + "\n", + "# Adjust negative predictions to 0\n", + "predicted_visitors = [max(0, value[0]) for value in predicted_visitors]\n", + "predicted_sold_items = [max(0, value[0]) for value in predicted_sold_items]\n", + "\n", + "print('predicted visitors:', predicted_visitors)\n", + "print('predicted sold items:', predicted_sold_items)\n", + "\n", + "# Calculate MSE\n", + "mse_visitors = mean_squared_error(scaled_Data_std_df['Number of Visitors'].values.reshape(-1, 1), predicted_visitors)\n", + "mse_sold_items = mean_squared_error(scaled_Data_std_df['Number of sold items'].values.reshape(-1, 1), predicted_sold_items)\n", + "\n", + "print('MSE of visitors: ', mse_visitors)\n", + "print('MSE of sold items: ', mse_sold_items)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "NN62k4rldeWF", + "outputId": "c2d25b7b-c624-442b-e949-3c46f431869d" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "predicted visitors: [11.77742099917544, 12.683376460650475, 7.247643691800271, 6.3416882303252375, 6.3416882303252375, 0, 0, 0, 8.153599153275305, 9.05955461475034]\n", + "predicted sold items: [4431.605755547653, 2954.4038370317685, 553.9507194434566, 6093.457913878022, 1107.9014388869132, 738.6009592579421, 8.88241302397551e-17, 553.9507194434566, 1441.1951217520595, 2585.1033574027974]\n", + "MSE of visitors: 53.84245232013412\n", + "MSE of sold items: 7661501.684724535\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "from sklearn.preprocessing import MinMaxScaler\n", + "\n", + "# Normalization\n", + "scaler = MinMaxScaler()\n", + "scaled_Data_mms = scaler.fit_transform(Data)\n", + "\n", + "scaled_Data_mms_df = pd.DataFrame(scaled_Data_mms, columns=Columns, index=Index)\n", + "\n", + "scaled_Data_mms_df\n", + "\n", + "LR_V = LinearRegression()\n", + "LR_S = LinearRegression()\n", + "\n", + "LR_V.fit(scaled_Data_mms_df['Number of ADS'].values.reshape(-1, 1), scaled_Data_mms_df['Number of Visitors'].values.reshape(-1, 1))\n", + "LR_S.fit(scaled_Data_mms_df['Number of Restock'].values.reshape(-1, 1), scaled_Data_mms_df['Number of sold items'].values.reshape(-1, 1))\n", + "\n", + "predicted_visitors = LR_V.predict([[13], [14], [8], [7], [7], [0], [0], [0], [9], [10]]) # give Number of ADS in params\n", + "predicted_sold_items = LR_S.predict([[4800], [3200], [600], [6600], [1200], [800], [0], [600], [1561], [2800]]) # give Number of Restock in params\n", + "\n", + "# Adjust negative predictions to 0\n", + "predicted_visitors = [max(0, value[0]) for value in predicted_visitors]\n", + "predicted_sold_items = [max(0, value[0]) for value in predicted_sold_items]\n", + "\n", + "print('predicted visitors:', predicted_visitors)\n", + "print('predicted sold items:', predicted_sold_items)\n", + "\n", + "# Calculate MSE\n", + "mse_visitors = mean_squared_error(scaled_Data_mms_df['Number of Visitors'].values.reshape(-1, 1), predicted_visitors)\n", + "mse_sold_items = mean_squared_error(scaled_Data_mms_df['Number of sold items'].values.reshape(-1, 1), predicted_sold_items)\n", + "\n", + "print('MSE of visitors: ', mse_visitors)\n", + "print('MSE of sold items: ', mse_sold_items)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Jyb9Q-whdjTN", + "outputId": "97fa62e6-c29c-4470-be2b-c57e44ca5096" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "predicted visitors: [13.201084277969446, 14.208477082306558, 8.164120256283885, 7.156727451946773, 7.156727451946773, 0.1049778215869886, 0.1049778215869886, 0.1049778215869886, 9.171513060620997, 10.178905864958109]\n", + "predicted sold items: [4398.808345002317, 2932.5289985865347, 549.8250606608892, 6048.3726097200715, 1099.6798155668075, 733.109978962862, 0, 549.8250606608892, 1430.5090931018683, 2565.959161982589]\n", + "MSE of visitors: 65.92838783134934\n", + "MSE of sold items: 7549335.969611017\n" + ] + } + ] + } + ] +} \ No newline at end of file From c6ee74ed86a743508c4a9a8a8bac3eb25f3b9a7f Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 29 Jul 2023 21:48:24 +0900 Subject: [PATCH 51/99] Update README_GrowTopia_STAT.md --- MachineLearning/READMES/README_GrowTopia_STAT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MachineLearning/READMES/README_GrowTopia_STAT.md b/MachineLearning/READMES/README_GrowTopia_STAT.md index 13e7e53..807167b 100644 --- a/MachineLearning/READMES/README_GrowTopia_STAT.md +++ b/MachineLearning/READMES/README_GrowTopia_STAT.md @@ -1,7 +1,7 @@ # 직접 하는 회귀 분석 ## 게임 내 아이템 거래 시장에 대한 통계적 분석이 필요하여 직접 데이터를 기록하고 적합한 선형 회귀 모델을 만들어 앞으로의 활동을 전략적으로 해 나가려는 목적(Profit Maximization). --- -- 작성한 ipynb 파일(1차) : [ipynb file](https://github.com/CharmStrange/Snippet/blob/main/Python/ipynb/GrowTopia_stat(V2).ipynb) +- 작성한 ipynb 파일(1차) : [ipynb file](https://github.com/CharmStrange/Study/blob/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5/MachineLearning/ipynb/GrowTopia_stat(V2).ipynb) - 작성한 py 파일(1차) : [py file](https://github.com/CharmStrange/Snippet/blob/main/Python/growtopia_stat(V2).py) --- ### 1. 분석에 필요한 데이터의 정의, 수집 From 63767529a487b178e424e4bc53bc2ab709d2ab9d Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 29 Jul 2023 21:49:27 +0900 Subject: [PATCH 52/99] Add files via upload --- .../ipynb/GrowTopia_stat(V1).ipynb | 278 ++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 MachineLearning/ipynb/GrowTopia_stat(V1).ipynb diff --git a/MachineLearning/ipynb/GrowTopia_stat(V1).ipynb b/MachineLearning/ipynb/GrowTopia_stat(V1).ipynb new file mode 100644 index 0000000..c535120 --- /dev/null +++ b/MachineLearning/ipynb/GrowTopia_stat(V1).ipynb @@ -0,0 +1,278 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Kff5QHWGhut3" + }, + "outputs": [], + "source": [ + "import statistics\n", + "import random\n", + "from sklearn.linear_model import LinearRegression\n", + "\n", + "# Function to get user input as a list of integers\n", + "def get_user_input(prompt):\n", + " values = input(prompt).split()\n", + " return [int(value) for value in values]\n", + "\n", + "# Get user input for the data : This is vector!\n", + "daily_restock = get_user_input(\"Enter daily restock values (separated by spaces): \")\n", + "daily_visitors = get_user_input(\"Enter daily visitors values (separated by spaces): \")\n", + "soldout_seeds = get_user_input(\"Enter soldout seeds values (separated by spaces): \")\n", + "daily_my_ads = get_user_input(\"Enter daily My ADS values (separated by spaces): \")\n", + "\n", + "# Calculate statistics\n", + "restock_mean = statistics.mean(daily_restock)\n", + "restock_var = statistics.variance(daily_restock)\n", + "restock_sd = statistics.stdev(daily_restock)\n", + "\n", + "visitors_mean = statistics.mean(daily_visitors)\n", + "visitors_var = statistics.variance(daily_visitors)\n", + "visitors_sd = statistics.stdev(daily_visitors)\n", + "\n", + "seeds_mean = statistics.mean(soldout_seeds)\n", + "seeds_var = statistics.variance(soldout_seeds)\n", + "seeds_sd = statistics.stdev(soldout_seeds)\n", + "\n", + "ads_mean = statistics.mean(daily_my_ads)\n", + "ads_var = statistics.variance(daily_my_ads)\n", + "ads_sd = statistics.stdev(daily_my_ads)\n", + "\n", + "print(\"Daily Restock - Mean:\", restock_mean, \"Variance:\", restock_var, \"Standard Deviation:\", restock_sd)\n", + "print(\"Daily Visitors - Mean:\", visitors_mean, \"Variance:\", visitors_var, \"Standard Deviation:\", visitors_sd)\n", + "print(\"Soldout Seeds - Mean:\", seeds_mean, \"Variance:\", seeds_var, \"Standard Deviation:\", seeds_sd)\n", + "print(\"Daily My ADS - Mean:\", ads_mean, \"Variance:\", ads_var, \"Standard Deviation:\", ads_sd)\n", + "\n", + "# Regression model: daily visitors as a function of daily My ADS\n", + "regression_model_visitors = LinearRegression()\n", + "regression_model_visitors.fit([[ads] for ads in daily_my_ads], daily_visitors)\n", + "\n", + "# Regression model: soldout seeds as a function of daily restock\n", + "regression_model_seeds = LinearRegression()\n", + "regression_model_seeds.fit([[restock] for restock in daily_restock], soldout_seeds)\n", + "\n", + "# Predict new values\n", + "new_ads = get_user_input(\"Enter new values of daily My ADS (separated by spaces): \")\n", + "new_restock = get_user_input(\"Enter new values of daily restock (separated by spaces): \")\n", + "\n", + "predicted_visitors = regression_model_visitors.predict([[ads] for ads in new_ads])\n", + "predicted_seeds = regression_model_seeds.predict([[restock] for restock in new_restock])\n", + "\n", + "print(\"Predicted Visitors:\", predicted_visitors)\n", + "print(\"Predicted Seeds:\", predicted_seeds)" + ] + }, + { + "cell_type": "code", + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "# Visualize daily_my_ads and daily_visitors with regression line\n", + "plt.scatter(daily_my_ads, daily_visitors, color='b', label='Data')\n", + "plt.plot(daily_my_ads, regression_model_visitors.predict([[ads] for ads in daily_my_ads]), color='r', label='Linear Regression')\n", + "plt.xlabel('Daily My ADS')\n", + "plt.ylabel('Daily Visitors')\n", + "plt.title('Relationship between Daily My ADS and Daily Visitors')\n", + "plt.legend()\n", + "plt.show()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 472 + }, + "id": "OMljSlUIc-7X", + "outputId": "44f43c3e-50a8-4b90-b7be-80f3a217428b" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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\n" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "code", + "source": [ + "import statistics\n", + "import random\n", + "from sklearn.linear_model import LinearRegression\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Function to generate random data\n", + "def generate_random_data(min_val, max_val, num_samples):\n", + " return [random.randint(min_val, max_val) for _ in range(num_samples)]\n", + "\n", + "# Generate random data\n", + "daily_my_ads = generate_random_data(0, 15, 50)\n", + "daily_visitors = [ads * 2 + random.randint(-2, 2) for ads in daily_my_ads]\n", + "\n", + "# Calculate statistics\n", + "ads_mean = statistics.mean(daily_my_ads)\n", + "ads_var = statistics.variance(daily_my_ads)\n", + "ads_sd = statistics.stdev(daily_my_ads)\n", + "\n", + "visitors_mean = statistics.mean(daily_visitors)\n", + "visitors_var = statistics.variance(daily_visitors)\n", + "visitors_sd = statistics.stdev(daily_visitors)\n", + "\n", + "print(\"Daily My ADS - Mean:\", ads_mean, \"Variance:\", ads_var, \"Standard Deviation:\", ads_sd)\n", + "print(\"Daily Visitors - Mean:\", visitors_mean, \"Variance:\", visitors_var, \"Standard Deviation:\", visitors_sd)\n", + "\n", + "# Regression model: daily visitors as a function of daily My ADS\n", + "regression_model_visitors = LinearRegression()\n", + "regression_model_visitors.fit([[ads] for ads in daily_my_ads], daily_visitors)\n", + "\n", + "# Generate data for plotting regression line\n", + "x_values = np.linspace(0, 15, 100)\n", + "y_values = regression_model_visitors.predict([[x] for x in x_values])\n", + "\n", + "# Visualize daily_my_ads and daily_visitors with regression line\n", + "plt.scatter(daily_my_ads, daily_visitors, color='b', label='Data')\n", + "plt.plot(x_values, y_values, color='r', label='Linear Regression')\n", + "plt.xlabel('Daily My ADS')\n", + "plt.ylabel('Daily Visitors')\n", + "plt.title('Relationship between Daily My ADS and Daily Visitors')\n", + "plt.legend()\n", + "plt.show()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 509 + }, + "id": "T6QUQkdrh2j-", + "outputId": "72144d5d-dff2-4464-aa66-789885e50f19" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Daily My ADS - Mean: 7.1 Variance: 21.887755102040817 Standard Deviation: 4.678435112517947\n", + "Daily Visitors - Mean: 14.06 Variance: 88.62897959183674 Standard Deviation: 9.414296553212925\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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1q+//mr9+++/1rFjx6y5c+dauXPntnx9fa1jx4452tarV88qW7asdePGDce+qKgoq1q1alaxYsUc+1auXGkB1sqVKx37rl27FuPcQ4cOtWw2m3XkyBHHvm7dullx/YgBa/DgwY7tZs2aWT4+PtbBgwcd+06ePGllzpzZevLJJ2M8x/r161tRUVGO/b1797a8vb2tS5cuWZZlWfPnz7cAa/PmzXG+XocOHbIAK2fOnNaFCxcc+xcsWGAB1qJFixz7Bg8eHOO5ABZgbdmyxbHvyJEjVrp06axnn302zvNa1n+va758+ayIiAjH/tmzZ1uANWbMGMuyzM+kWLFiVnBwsNPzvXbtmlWoUCGrQYMGjn0jRoywAOvQoUNO59q8ebMFWD///LNlWZa1c+dOC7Cef/55q0qVKo52zzzzjFWhQgXH9pAhQ6yMGTNaf/31l9PxBg4caHl7e1tHjx61LMuy1q5dawHWjBkznNotWbIkxv4CBQpYgLVmzRrHvrNnz1q+vr7WG2+8cc/XzLLMa96tW7c47+/Zs6cFWDt27LAsy7Ju375tRUZGOrW5ePGilSdPHqtTp04xjn3nezL6vRb9etrtdiswMNB64YUXnB43atQoy2azWf/88889Y+/QoYOVMWNGy7Isq0WLFla9evUcx/X397fef/99x3tyxIgRjsd9+eWXFmDt27fPse/mzZtWrly5rA4dOtzznNFtc+bMab311luOfW3atLHKly8fo22tWrWs0qVLx3ms6N+rO9+ftWrVsgArT548VuvWra0JEyY4fQ7ci6s/n4T8rj766KNWQECA47PAsizrl19+sQCrQIEC8caU0NfAsmL/TAwODrYKFy4c49i1atWK8bxCQ0Md+1q3bm3lzZvXstvtjn3btm2L0S42t2/ftgICAqyqVas67f/iiy8swFq6dKlj393vb1c+My0r5u9JXJ8727dvtwCrc+fOTvv79u1rAdaKFSsc+6I/F5YsWeLU9rPPPrMA699//71nTJ6mHplEUL9+fXLnzk1QUBAtWrQgY8aMLFy4kMDAQMBk5ytWrKBly5ZcvnyZc+fOce7cOc6fP09wcDAHDhy45yynOzP6q1evcu7cOapVq4ZlWbF2icbHbrfzyy+/0KxZMwoXLuzYHxAQQJs2bVi3bp3jL+xor7zyitOlnpo1a2K32zly5AiAY9DZjz/+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\n" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "code", + "source": [ + "import statistics\n", + "import random\n", + "from sklearn.linear_model import LinearRegression\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Function to generate random data\n", + "def generate_random_data(min_val, max_val, num_samples):\n", + " return [random.randint(min_val, max_val) for _ in range(num_samples)]\n", + "\n", + "# Generate random data\n", + "daily_my_ads = generate_random_data(0, 15, 50)\n", + "daily_visitors = [ads * 2 + random.randint(-2, 2) for ads in daily_my_ads]\n", + "\n", + "# Calculate statistics\n", + "ads_mean = statistics.mean(daily_my_ads)\n", + "ads_var = statistics.variance(daily_my_ads)\n", + "ads_sd = statistics.stdev(daily_my_ads)\n", + "\n", + "visitors_mean = statistics.mean(daily_visitors)\n", + "visitors_var = statistics.variance(daily_visitors)\n", + "visitors_sd = statistics.stdev(daily_visitors)\n", + "\n", + "print(\"Daily My ADS - Mean:\", ads_mean, \"Variance:\", ads_var, \"Standard Deviation:\", ads_sd)\n", + "print(\"Daily Visitors - Mean:\", visitors_mean, \"Variance:\", visitors_var, \"Standard Deviation:\", visitors_sd)\n", + "\n", + "# Regression model: daily visitors as a function of daily My ADS\n", + "regression_model_visitors = LinearRegression()\n", + "regression_model_visitors.fit([[ads] for ads in daily_my_ads], daily_visitors)\n", + "\n", + "# Generate data for plotting regression line\n", + "x_values = np.linspace(0, 15, 100)\n", + "y_values = regression_model_visitors.predict([[x] for x in x_values])\n", + "\n", + "# Calculate residuals\n", + "residuals = [actual - predicted for actual, predicted in zip(daily_visitors, regression_model_visitors.predict([[ads] for ads in daily_my_ads]))]\n", + "\n", + "# Visualize daily_my_ads and daily_visitors with residuals\n", + "plt.scatter(daily_my_ads, daily_visitors, color='b', label='Data')\n", + "plt.plot(x_values, y_values, color='r', label='Linear Regression')\n", + "plt.xlabel('Daily My ADS')\n", + "plt.ylabel('Daily Visitors')\n", + "plt.title('Relationship between Daily My ADS and Daily Visitors')\n", + "\n", + "# Add residual lines\n", + "for x, y, residual in zip(daily_my_ads, daily_visitors, residuals):\n", + " plt.plot([x, x], [y, y - residual], color='g')\n", + "\n", + "plt.legend()\n", + "plt.show()\n" + ], + "metadata": { + "id": "A6sTEkSEiW4G", + "outputId": "39884768-cc36-4f1c-fe5b-f4b758d49ce4", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 509 + } + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Daily My ADS - Mean: 7.58 Variance: 25.309795918367346 Standard Deviation: 5.030884208403862\n", + "Daily Visitors - Mean: 15.26 Variance: 101.7065306122449 Standard Deviation: 10.084965573180947\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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\n" + }, + "metadata": {} + } + ] + } + ] +} From 7dc4536ccec3714d139086a511e8626c2a388ac3 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 29 Jul 2023 21:50:49 +0900 Subject: [PATCH 53/99] Update README_GrowTopia_STAT.md --- MachineLearning/READMES/README_GrowTopia_STAT.md | 1 - 1 file changed, 1 deletion(-) diff --git a/MachineLearning/READMES/README_GrowTopia_STAT.md b/MachineLearning/READMES/README_GrowTopia_STAT.md index 807167b..6fb14d8 100644 --- a/MachineLearning/READMES/README_GrowTopia_STAT.md +++ b/MachineLearning/READMES/README_GrowTopia_STAT.md @@ -2,7 +2,6 @@ ## 게임 내 아이템 거래 시장에 대한 통계적 분석이 필요하여 직접 데이터를 기록하고 적합한 선형 회귀 모델을 만들어 앞으로의 활동을 전략적으로 해 나가려는 목적(Profit Maximization). --- - 작성한 ipynb 파일(1차) : [ipynb file](https://github.com/CharmStrange/Study/blob/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5/MachineLearning/ipynb/GrowTopia_stat(V2).ipynb) -- 작성한 py 파일(1차) : [py file](https://github.com/CharmStrange/Snippet/blob/main/Python/growtopia_stat(V2).py) --- ### 1. 분석에 필요한 데이터의 정의, 수집 먼저 아이템 거래에 대해 분석을 하려면 '***재고 보충량***', '***팔린 물품 수***', '***광고 게재 수***', '***방문자 수***' 정보가 필요하다. 여기서 모든 수치는 하루 기준이며 하루가 지나면 새로 기록을 해 주어야 한다. From 596f66e8b3685278a4fcb7955ec63bdb8ab47957 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 30 Jul 2023 19:56:55 +0900 Subject: [PATCH 54/99] =?UTF-8?q?Update=20and=20rename=20LinAlg.py=20to=20?= =?UTF-8?q?=ED=96=89=EB=A0=AC=5F=EC=97=B0=EC=82=B0=5F=EA=B5=AC=ED=98=84.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\240\254_\354\227\260\354\202\260_\352\265\254\355\230\204.py" | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename "\352\270\260\354\264\210/Algorithm/LinAlg.py" => "\352\270\260\354\264\210/Algorithm/\355\226\211\353\240\254_\354\227\260\354\202\260_\352\265\254\355\230\204.py" (100%) diff --git "a/\352\270\260\354\264\210/Algorithm/LinAlg.py" "b/\352\270\260\354\264\210/Algorithm/\355\226\211\353\240\254_\354\227\260\354\202\260_\352\265\254\355\230\204.py" similarity index 100% rename from "\352\270\260\354\264\210/Algorithm/LinAlg.py" rename to "\352\270\260\354\264\210/Algorithm/\355\226\211\353\240\254_\354\227\260\354\202\260_\352\265\254\355\230\204.py" From a291ad22e19b3223aa74a8f3be9b1bca7bc389d6 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 9 Sep 2023 14:24:35 +0900 Subject: [PATCH 55/99] Create Feature_Engineering.md --- MachineLearning/Data/Feature_Engineering.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 MachineLearning/Data/Feature_Engineering.md diff --git a/MachineLearning/Data/Feature_Engineering.md b/MachineLearning/Data/Feature_Engineering.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/MachineLearning/Data/Feature_Engineering.md @@ -0,0 +1 @@ + From b26169c8ab63d1c9df35b8c9ab4fb62e748fd514 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 10 Sep 2023 12:51:51 +0900 Subject: [PATCH 56/99] Create Pipeline-sklearn.md --- MachineLearning/Data/Pipeline-sklearn.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 MachineLearning/Data/Pipeline-sklearn.md diff --git a/MachineLearning/Data/Pipeline-sklearn.md b/MachineLearning/Data/Pipeline-sklearn.md new file mode 100644 index 0000000..e980345 --- /dev/null +++ b/MachineLearning/Data/Pipeline-sklearn.md @@ -0,0 +1,12 @@ +### 실제 코드에서 사용 가능한 파이프라인 +scikit-learn (sklearn)은 파이썬에서 머신 러닝 모델을 개발하고 사용하는 데 도움을 주는 강력한 라이브러리입니다. Pipeline은 scikit-learn에서 모델 개발 및 평가를 간편하게 수행할 수 있도록 도와주는 중요한 도구 중 하나입니다. + +Pipeline은 다음과 같은 주요 기능을 제공합니다: + +각 단계의 연속성: Pipeline은 여러 단계로 구성된 머신 러닝 워크플로우를 정의합니다. 각 단계는 전처리, 특성 선택, 모델 훈련 등과 같은 다양한 처리 단계를 포함할 수 있습니다. + +처리 단계 순서: 각 단계는 정의된 순서대로 실행됩니다. 이렇게 하면 데이터 처리 및 모델 훈련과 같은 작업을 단순화하고 일관성 있게 수행할 수 있습니다. + +하나의 추정기로 취급: Pipeline은 마지막 단계가 머신 러닝 모델 추정기(estimator)인 것처럼 동작합니다. 이렇게 하면 전체 워크플로우를 하나의 추정기로 간주하고 다른 scikit-learn 함수와 상호 작용할 수 있습니다. + +Pipeline을 사용하여 데이터 처리와 모델 훈련을 단일 객체로 래핑하면 코드를 보다 간결하게 작성하고 모델의 가독성을 향상시킬 수 있습니다. 또한 Pipeline은 교차 검증(cross-validation) 및 하이퍼파라미터 최적화와 같은 작업을 쉽게 수행할 수 있도록 도와줍니다. From bb36ea009241c1488e8b48c5ac0ba3ab107fdca8 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 10 Sep 2023 12:52:15 +0900 Subject: [PATCH 57/99] Update Pipeline-sklearn.md --- MachineLearning/Data/Pipeline-sklearn.md | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/MachineLearning/Data/Pipeline-sklearn.md b/MachineLearning/Data/Pipeline-sklearn.md index e980345..f60bbe7 100644 --- a/MachineLearning/Data/Pipeline-sklearn.md +++ b/MachineLearning/Data/Pipeline-sklearn.md @@ -10,3 +10,30 @@ Pipeline은 다음과 같은 주요 기능을 제공합니다: 하나의 추정기로 취급: Pipeline은 마지막 단계가 머신 러닝 모델 추정기(estimator)인 것처럼 동작합니다. 이렇게 하면 전체 워크플로우를 하나의 추정기로 간주하고 다른 scikit-learn 함수와 상호 작용할 수 있습니다. Pipeline을 사용하여 데이터 처리와 모델 훈련을 단일 객체로 래핑하면 코드를 보다 간결하게 작성하고 모델의 가독성을 향상시킬 수 있습니다. 또한 Pipeline은 교차 검증(cross-validation) 및 하이퍼파라미터 최적화와 같은 작업을 쉽게 수행할 수 있도록 도와줍니다. + +```Python +from sklearn.pipeline import Pipeline +from sklearn.preprocessing import StandardScaler +from sklearn.decomposition import PCA +from sklearn.svm import SVC + +# 각 단계를 정의합니다. +scaler = StandardScaler() +pca = PCA(n_components=2) +svm_classifier = SVC(kernel='linear') + +# Pipeline 객체를 생성합니다. +# 데이터는 스케일링, 차원 축소, SVM 분류 모델 순서로 처리됩니다. +model = Pipeline([ + ('scaler', scaler), + ('pca', pca), + ('svm', svm_classifier) +]) + +# 모델을 훈련합니다. +model.fit(X_train, y_train) + +# 모델을 사용하여 예측을 수행합니다. +y_pred = model.predict(X_test) + +``` From dd8a6b891d2c89dfa3d7c1e5dd7a97c0a37eee9a Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Thu, 21 Sep 2023 20:58:59 +0900 Subject: [PATCH 58/99] Create README.md --- DataBase/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 DataBase/README.md diff --git a/DataBase/README.md b/DataBase/README.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/DataBase/README.md @@ -0,0 +1 @@ + From 15ca9c04fbfdb5db551191c2c183fb71c1822be7 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:09:57 +0900 Subject: [PATCH 59/99] Update README.md --- DataBase/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/DataBase/README.md b/DataBase/README.md index 8b13789..f1fa1c9 100644 --- a/DataBase/README.md +++ b/DataBase/README.md @@ -1 +1,11 @@ +# 데이터베이스 모델링 / 데이터 모델링 +> 정보 시스템 구축을 위해 ***(분석) - (설계) - (구현) - (시험) - (유지 및 보수)*** 단계를 거친다. ***(분석) - (설계)*** 가 전체 단계 중 가장 중요한 부분이다. + +> #### 데이터베이스 모델링과 관련되어 필수적으로 알아야 할 용어 +> 1. 테이블(table) +> 2. 필드(field=column) +> 3. 레코드(record=row) +> 4. 기본 키(primary key) : 각 행을 구분하는 유일한 특징을 지닌 열 +> 5. 외래 키(foreign key) : 테이블 간 관계와 관련됨 +> 6. SQL From 0a1621f618fe9301797c72cb732ca190bc8ffa2b Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:36:10 +0900 Subject: [PATCH 60/99] Update README.md --- DataBase/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/DataBase/README.md b/DataBase/README.md index f1fa1c9..cfb7d6b 100644 --- a/DataBase/README.md +++ b/DataBase/README.md @@ -2,6 +2,15 @@ > 정보 시스템 구축을 위해 ***(분석) - (설계) - (구현) - (시험) - (유지 및 보수)*** 단계를 거친다. ***(분석) - (설계)*** 가 전체 단계 중 가장 중요한 부분이다. +> **개념적**, **논리적**, **물리적** 데이터 모델링, **추상화**, **단순화**, **명확화**가 모델링에 있어서 고려해야 할 주요 요소다. + +> #### **외부**, **개념**, **내부** Schema Structure +> **외부 스키마**는 데이터베이스를 이용하는 외부, 고객과 같은 사용자 입장에서 고려한 스키마 +> +> **개념 스키마**는 데이터베이스 설계 시 외부와 내부에 대한 구조를 고려한 스키마 +> +> **내부 스키마**는 데이터베이스를 직접 설계, 관리하는 개발자 혹은 관리자가 데이터베이스의 물리적 구조를 고려한 스키마 + > #### 데이터베이스 모델링과 관련되어 필수적으로 알아야 할 용어 > 1. 테이블(table) > 2. 필드(field=column) From d24b1d8861aba57b615a04468b752db5aef1b3eb Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:53:31 +0900 Subject: [PATCH 61/99] Rename README.md to DatabaseBasic.md --- DataBase/{README.md => DatabaseBasic.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename DataBase/{README.md => DatabaseBasic.md} (100%) diff --git a/DataBase/README.md b/DataBase/DatabaseBasic.md similarity index 100% rename from DataBase/README.md rename to DataBase/DatabaseBasic.md From 5d9f3c5318ea04f11609f2b7ba82fef8791c793e Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 22 Sep 2023 12:03:13 +0900 Subject: [PATCH 62/99] Create Entity&ERD.md --- DataBase/Entity&ERD.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 DataBase/Entity&ERD.md diff --git a/DataBase/Entity&ERD.md b/DataBase/Entity&ERD.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/DataBase/Entity&ERD.md @@ -0,0 +1 @@ + From 9a7929d25549ad7d124b004cdb3b05312e66d815 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 23 Sep 2023 13:18:42 +0900 Subject: [PATCH 63/99] =?UTF-8?q?Create=20=EB=B2=A1=ED=84=B0=EC=99=80?= =?UTF-8?q?=ED=96=89=EB=A0=AC.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...3\262\241\355\204\260\354\231\200\355\226\211\353\240\254.md" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "\352\270\260\354\264\210/\354\210\230\355\225\231/\353\262\241\355\204\260\354\231\200\355\226\211\353\240\254.md" diff --git "a/\352\270\260\354\264\210/\354\210\230\355\225\231/\353\262\241\355\204\260\354\231\200\355\226\211\353\240\254.md" "b/\352\270\260\354\264\210/\354\210\230\355\225\231/\353\262\241\355\204\260\354\231\200\355\226\211\353\240\254.md" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/\352\270\260\354\264\210/\354\210\230\355\225\231/\353\262\241\355\204\260\354\231\200\355\226\211\353\240\254.md" @@ -0,0 +1 @@ + From 55f2f17e1b37f07e74d61d123faf7b32b50f766a Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 23 Sep 2023 16:18:20 +0900 Subject: [PATCH 64/99] Update Entity&ERD.md --- DataBase/Entity&ERD.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/DataBase/Entity&ERD.md b/DataBase/Entity&ERD.md index 8b13789..2ff4da5 100644 --- a/DataBase/Entity&ERD.md +++ b/DataBase/Entity&ERD.md @@ -1 +1,8 @@ - +# Entity & ERD +> 데이터베이스 내에서 개체를 **Entity**(**엔티티**)라 부른다 +> : **데이터베이스 전체적 관점에서 봤을 때, 작업에 필요한 정보 또는 대상** +> > 테이블, 인덱스, 뷰, 트리거, 함수, 커서 등이 **Entity** +> > +> 1. *저장되고 관리되는 데이터의 집합* +> 2. *개념, 장소, 사건 등* +> 3. *유형 또는 무형의 대상* From 2adca6de0fedd10dd2def406925baaf9b0f340ff Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 23 Sep 2023 20:11:08 +0900 Subject: [PATCH 65/99] Update Entity&ERD.md --- DataBase/Entity&ERD.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DataBase/Entity&ERD.md b/DataBase/Entity&ERD.md index 2ff4da5..cc48132 100644 --- a/DataBase/Entity&ERD.md +++ b/DataBase/Entity&ERD.md @@ -1,8 +1,10 @@ # Entity & ERD > 데이터베이스 내에서 개체를 **Entity**(**엔티티**)라 부른다 > : **데이터베이스 전체적 관점에서 봤을 때, 작업에 필요한 정보 또는 대상** -> > 테이블, 인덱스, 뷰, 트리거, 함수, 커서 등이 **Entity** +> > *테이블, 인덱스, 뷰, 트리거, 함수, 커서 등이 **Entity*** > > > 1. *저장되고 관리되는 데이터의 집합* > 2. *개념, 장소, 사건 등* > 3. *유형 또는 무형의 대상* +> +> 특징으로는 **유일한 식별자**와 **속성**의 존재, **다른 개체와의 관계**가 있어야 한다는 것이다. From 16781b3f181f9b8838b8fed9cea3901dfb689bfb Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 23 Sep 2023 21:10:48 +0900 Subject: [PATCH 66/99] Update Entity&ERD.md --- DataBase/Entity&ERD.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/DataBase/Entity&ERD.md b/DataBase/Entity&ERD.md index cc48132..61b3082 100644 --- a/DataBase/Entity&ERD.md +++ b/DataBase/Entity&ERD.md @@ -8,3 +8,8 @@ > 3. *유형 또는 무형의 대상* > > 특징으로는 **유일한 식별자**와 **속성**의 존재, **다른 개체와의 관계**가 있어야 한다는 것이다. + +> ### 유형 / 무형에 따른 Entity +> **유형**, **개념**, **사건** Entity +> ### 발생에 따른 Entity +> **기본**, **중심**, **행위** Entity From bbffae7879ed9d8b9c4b31613a27059472a10df9 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 23 Sep 2023 21:14:05 +0900 Subject: [PATCH 67/99] Update Entity&ERD.md --- DataBase/Entity&ERD.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DataBase/Entity&ERD.md b/DataBase/Entity&ERD.md index 61b3082..0845b70 100644 --- a/DataBase/Entity&ERD.md +++ b/DataBase/Entity&ERD.md @@ -13,3 +13,5 @@ > **유형**, **개념**, **사건** Entity > ### 발생에 따른 Entity > **기본**, **중심**, **행위** Entity +--- +> **ERD**는 *Entity Relation Diagram* 의 약자, 개체 관계 다이어그램으로 해석되며 데이터베이스의 개체 관계를 구조적으로 표현하기 위해 제작한 다이어그램. From 7e1cdae8f11ca5ce9497eddd7f95113b960e101d Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 24 Sep 2023 13:27:36 +0900 Subject: [PATCH 68/99] =?UTF-8?q?Create=20=EC=86=8D=EC=84=B1=EA=B3=BC?= =?UTF-8?q?=EA=B4=80=EA=B3=84.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...4\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" diff --git "a/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" "b/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" @@ -0,0 +1 @@ + From c80f7f345707caa76b11a727cbfe908905ccaf81 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 24 Sep 2023 13:33:24 +0900 Subject: [PATCH 69/99] =?UTF-8?q?Update=20=EC=86=8D=EC=84=B1=EA=B3=BC?= =?UTF-8?q?=EA=B4=80=EA=B3=84.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...215\354\204\261\352\263\274\352\264\200\352\263\204.md" | 7 +++++++ 1 file changed, 7 insertions(+) diff --git "a/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" "b/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" index 8b13789..a63cffb 100644 --- "a/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" +++ "b/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" @@ -1 +1,8 @@ +# 속성 +데이터베이스 개체가 가지고 있는 특징, 개체는 속성으로 설명할 수 있다. 또한 한 번(시점/동시)에 여러 가지의 값을 가질 수 없으며 분리되지 않는 최소의 데이터 단위라고 볼 수 있다. +# 관계 + + +# +[이 문서](https://github.com/CharmStrange/Study/blob/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5/DataBase/Entity%26ERD.md)와 연결됨. From 689dd7eb77b1c0f9529a4f055483d9338a1af411 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 24 Sep 2023 13:36:50 +0900 Subject: [PATCH 70/99] =?UTF-8?q?Update=20=EC=86=8D=EC=84=B1=EA=B3=BC?= =?UTF-8?q?=EA=B4=80=EA=B3=84.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...5\354\204\261\352\263\274\352\264\200\352\263\204.md" | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git "a/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" "b/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" index a63cffb..9f9240e 100644 --- "a/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" +++ "b/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" @@ -1,6 +1,15 @@ # 속성 데이터베이스 개체가 가지고 있는 특징, 개체는 속성으로 설명할 수 있다. 또한 한 번(시점/동시)에 여러 가지의 값을 가질 수 없으며 분리되지 않는 최소의 데이터 단위라고 볼 수 있다. +>#### 기본 속성 +> *작업에 필요한 데이터의 원형* + +>#### 설계 속성 +> *작업 규칙화를 위해 설계, 변형한 데이터의 속성* + +>#### 파생 속성 +> *다른 데이터의 속성 영향을 받는 속성* + # 관계 From 279e3959c699d363f1605c4b0bb43fabe936a94c Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 24 Sep 2023 13:49:37 +0900 Subject: [PATCH 71/99] =?UTF-8?q?Update=20=EC=86=8D=EC=84=B1=EA=B3=BC?= =?UTF-8?q?=EA=B4=80=EA=B3=84.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...354\204\261\352\263\274\352\264\200\352\263\204.md" | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git "a/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" "b/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" index 9f9240e..982198b 100644 --- "a/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" +++ "b/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" @@ -1,5 +1,5 @@ # 속성 -데이터베이스 개체가 가지고 있는 특징, 개체는 속성으로 설명할 수 있다. 또한 한 번(시점/동시)에 여러 가지의 값을 가질 수 없으며 분리되지 않는 최소의 데이터 단위라고 볼 수 있다. +데이터베이스 개체가 가지고 있는 특징, 개체는 속성으로 설명할 수 있다. 또한 한 번(시점/동시)에 여러 가지의 값을 가질 수 없으며 분리되지 않는 최소의 데이터 단위라고도 볼 수 있다. >#### 기본 속성 > *작업에 필요한 데이터의 원형* @@ -10,6 +10,14 @@ >#### 파생 속성 > *다른 데이터의 속성 영향을 받는 속성* +위 세 특성은 *단일*, *복합*, *다중값* 속성으로도 구분 가능한데, 그 기준은 속성 자체에 대한 분해 여부이다. 그 중 *복합*, *다중값* 속성은 데이터 전처리와 같은 작업을 통해 하나의 의미만 가지도록 해야 한다. + +*단일 속성* : 속성의 값이 분해되지 않는, 최소 단위인 하나의 의미로 구성된 속성 + +*복합 속성* : 주소(시, 군, 동 ...)와 같이 여러 의미로 구분 가능한 속성 + +*다중값 속성* : 속성의 값 자체에 서로 다른 여러 값이 존재하는 속성으로, 처리 시 개체로 분해해도 됨 + # 관계 From 9fd49446415ca3345c3ff3310cdd20cdc3c03000 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 24 Sep 2023 21:02:53 +0900 Subject: [PATCH 72/99] Update README_GrowTopia_STAT.md --- MachineLearning/READMES/README_GrowTopia_STAT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MachineLearning/READMES/README_GrowTopia_STAT.md b/MachineLearning/READMES/README_GrowTopia_STAT.md index 6fb14d8..517c7fb 100644 --- a/MachineLearning/READMES/README_GrowTopia_STAT.md +++ b/MachineLearning/READMES/README_GrowTopia_STAT.md @@ -63,7 +63,7 @@ plt.show() image image -데이터 분포의 선형성을 확인하기 위해 시각화를 해 보았다. 데이터가 10개임에도 불구하고 뚜렷하게 선형성이 나타는 것으로 보아 회귀 분석이 적합할 것으로 예상된다. +데이터 분포의 선형성을 확인하기 위해 시각화를 해 보았다. 데이터가 10개임에도 불구하고 선형성이 나타는 것으로 보아 회귀 분석이 적합할 것으로 예상된다. --- ### 3. 분석 시작 From 8ae7cce6309db518fbb624a9ccb7af72185932f3 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 24 Sep 2023 21:04:11 +0900 Subject: [PATCH 73/99] Update README_GrowTopia_STAT.md --- MachineLearning/READMES/README_GrowTopia_STAT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MachineLearning/READMES/README_GrowTopia_STAT.md b/MachineLearning/READMES/README_GrowTopia_STAT.md index 517c7fb..b4c21a0 100644 --- a/MachineLearning/READMES/README_GrowTopia_STAT.md +++ b/MachineLearning/READMES/README_GrowTopia_STAT.md @@ -1,4 +1,4 @@ -# 직접 하는 회귀 분석 +# 직접 하는 회귀 분석(개인 공부용, 프로젝트 연습) ## 게임 내 아이템 거래 시장에 대한 통계적 분석이 필요하여 직접 데이터를 기록하고 적합한 선형 회귀 모델을 만들어 앞으로의 활동을 전략적으로 해 나가려는 목적(Profit Maximization). --- - 작성한 ipynb 파일(1차) : [ipynb file](https://github.com/CharmStrange/Study/blob/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5/MachineLearning/ipynb/GrowTopia_stat(V2).ipynb) From 0499b6248a222dfb48125613f85c87870e706d86 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Thu, 28 Sep 2023 17:56:37 +0900 Subject: [PATCH 74/99] =?UTF-8?q?Update=20=EC=86=8D=EC=84=B1=EA=B3=BC?= =?UTF-8?q?=EA=B4=80=EA=B3=84.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...54\204\261\352\263\274\352\264\200\352\263\204.md" | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git "a/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" "b/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" index 982198b..40f8978 100644 --- "a/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" +++ "b/DataBase/\354\206\215\354\204\261\352\263\274\352\264\200\352\263\204.md" @@ -19,6 +19,17 @@ *다중값 속성* : 속성의 값 자체에 서로 다른 여러 값이 존재하는 속성으로, 처리 시 개체로 분해해도 됨 # 관계 +데이터베이스의 개체 간 관계를 정의하지 않을 수 없다. 관계를 정의하려면 *관계명*, *관계 차수*, *관계 선택 사양* 세 가지 요소를 고려해야 하고, 관계는 크게 **존재적 관계**와 **행위에 의한 관계**가 있다. + +> #### 관계명 +> *개체 간 관계에서, 개체가 관계에 속한 형태를 이르는 말* + +> #### 관계 차수 +> *개체 간 관계에서, 관계 참여자의 수를 표현하는 말*, `1:1`/`1:M`/`M:N` 로 구분 + +> #### 관계 선택 사양 +> *개체의 관계 참여 여부를 표현하는 말*, `필수` 또는 `선택` + # From c066499a7a8c5a55df2979083f278e7b698a0068 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Thu, 28 Sep 2023 18:08:08 +0900 Subject: [PATCH 75/99] Update Entity&ERD.md --- DataBase/Entity&ERD.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DataBase/Entity&ERD.md b/DataBase/Entity&ERD.md index 0845b70..9766599 100644 --- a/DataBase/Entity&ERD.md +++ b/DataBase/Entity&ERD.md @@ -14,4 +14,5 @@ > ### 발생에 따른 Entity > **기본**, **중심**, **행위** Entity --- -> **ERD**는 *Entity Relation Diagram* 의 약자, 개체 관계 다이어그램으로 해석되며 데이터베이스의 개체 관계를 구조적으로 표현하기 위해 제작한 다이어그램. +> **ERD**는 *Entity Relation Diagram* 의 약자, 개체 관계 다이어그램으로 해석되며 데이터베이스의 개체 관계를 구조적으로 표현하기 위해 제작하는 다이어그램. +> ![image](https://github.com/CharmStrange/Study/assets/105769152/b6d7c64e-d5ad-42be-bfa3-4fdb74d5a916) From 8069f72e7a6d07cce1a6fcad69aee5883d80da55 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Thu, 28 Sep 2023 18:08:29 +0900 Subject: [PATCH 76/99] Update Entity&ERD.md --- DataBase/Entity&ERD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataBase/Entity&ERD.md b/DataBase/Entity&ERD.md index 9766599..145c4ad 100644 --- a/DataBase/Entity&ERD.md +++ b/DataBase/Entity&ERD.md @@ -15,4 +15,4 @@ > **기본**, **중심**, **행위** Entity --- > **ERD**는 *Entity Relation Diagram* 의 약자, 개체 관계 다이어그램으로 해석되며 데이터베이스의 개체 관계를 구조적으로 표현하기 위해 제작하는 다이어그램. -> ![image](https://github.com/CharmStrange/Study/assets/105769152/b6d7c64e-d5ad-42be-bfa3-4fdb74d5a916) +> ![image](https://github.com/CharmStrange/Study/assets/105769152/b6d7c64e-d5ad-42be-bfa3-4fdb74d5a916) (Wikipedia) From 734135fc191478f70051b90a95edfdbb5204fd95 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 29 Sep 2023 19:12:40 +0900 Subject: [PATCH 77/99] Create README.md --- PipeLine/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 PipeLine/README.md diff --git a/PipeLine/README.md b/PipeLine/README.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/PipeLine/README.md @@ -0,0 +1 @@ + From 4f0a822eb9b6d7c43a00bbc80227f989a7c485f2 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 29 Sep 2023 19:13:53 +0900 Subject: [PATCH 78/99] Update Pipeline-sklearn.md --- MachineLearning/Data/Pipeline-sklearn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MachineLearning/Data/Pipeline-sklearn.md b/MachineLearning/Data/Pipeline-sklearn.md index f60bbe7..eee25bd 100644 --- a/MachineLearning/Data/Pipeline-sklearn.md +++ b/MachineLearning/Data/Pipeline-sklearn.md @@ -1,4 +1,4 @@ -### 실제 코드에서 사용 가능한 파이프라인 +### 실제 코드로 이해하는 파이프라인 scikit-learn (sklearn)은 파이썬에서 머신 러닝 모델을 개발하고 사용하는 데 도움을 주는 강력한 라이브러리입니다. Pipeline은 scikit-learn에서 모델 개발 및 평가를 간편하게 수행할 수 있도록 도와주는 중요한 도구 중 하나입니다. Pipeline은 다음과 같은 주요 기능을 제공합니다: From ec2f5e16f830377f9d4d872dbcc7fff54d5a5306 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 29 Sep 2023 19:19:14 +0900 Subject: [PATCH 79/99] Update README.md --- PipeLine/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PipeLine/README.md b/PipeLine/README.md index 8b13789..ca922c7 100644 --- a/PipeLine/README.md +++ b/PipeLine/README.md @@ -1 +1,4 @@ +# 데이터 파이프라인 +데이터를 다루는 영역에 있어서, 데이터의 지속적 관리와 활용을 위해 구축된 환경(요소) +데이터 파이프라인의 공정을 **ETL**이라 부르며 이는 **Extract**, **Transform**, **Loading** 작업을 뜻한다. From 1e115e3de4f84c899fbddc0101ba7a82a3fc6a58 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 29 Sep 2023 19:34:35 +0900 Subject: [PATCH 80/99] Update README.md --- PipeLine/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/PipeLine/README.md b/PipeLine/README.md index ca922c7..473f406 100644 --- a/PipeLine/README.md +++ b/PipeLine/README.md @@ -1,4 +1,11 @@ # 데이터 파이프라인 데이터를 다루는 영역에 있어서, 데이터의 지속적 관리와 활용을 위해 구축된 환경(요소) -데이터 파이프라인의 공정을 **ETL**이라 부르며 이는 **Extract**, **Transform**, **Loading** 작업을 뜻한다. +데이터 파이프라인의 공정을 **ETL**이라 부르며 이는 **Extract**, **Transform**, **Loading** 작업을 뜻한다. 이는 **데어터 웨어하우스** : **잘 정돈된 데이터가 저장되는 시스템**을 구축하는 일련의 과정으로도 이해할 수 있다. (**ELT**도 있다) + + 데이터 웨어하우스와는 별개로 **데이터 레이크**란 개념도 있는데 이는 바로 수집되어 정돈되지 않은 상태의 데이터가 모이는 곳이다. + +더 발전하여 **데이터 마트**란 개념도 있다. 이는 데이터 웨어하우스의 상위 개념으로, 데이터 웨어하우스의 잘 정돈된 데이터들을 특정 목적을 위해 따로 분류된 데이터가 모이는 곳으로 볼 수 있다. +즉, +#### [ 데이터 레이크 -> 데이터 웨어하우스 -> 데이터 마트 ] +의 큰 과정으로 보면 된다. From eb0fbe7d5a1155dd34179db8343e9a82b2c43dd1 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 29 Sep 2023 19:43:27 +0900 Subject: [PATCH 81/99] Update README.md --- PipeLine/README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/PipeLine/README.md b/PipeLine/README.md index 473f406..c0b6ce5 100644 --- a/PipeLine/README.md +++ b/PipeLine/README.md @@ -6,6 +6,12 @@ 데이터 웨어하우스와는 별개로 **데이터 레이크**란 개념도 있는데 이는 바로 수집되어 정돈되지 않은 상태의 데이터가 모이는 곳이다. 더 발전하여 **데이터 마트**란 개념도 있다. 이는 데이터 웨어하우스의 상위 개념으로, 데이터 웨어하우스의 잘 정돈된 데이터들을 특정 목적을 위해 따로 분류된 데이터가 모이는 곳으로 볼 수 있다. -즉, -#### [ 데이터 레이크 -> 데이터 웨어하우스 -> 데이터 마트 ] -의 큰 과정으로 보면 된다. +즉, ***[ 데이터 레이크 -> 데이터 웨어하우스 -> 데이터 마트 ]*** 의 큰 과정으로 보면 된다. + +--- + +## ETL vs ELT? + +### ETL : 데이터를 얻어 알맞은 형태로 변환한 후 데이터 웨어하우스에 담기 + +### ELT : 데이터를 얻어 데이터 레이크에 담은 후, 필요하면 데이터의 변환 작업을 수행 From 3d1ab960685ca71f096dfce53d15f692d320990b Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 30 Sep 2023 11:21:04 +0900 Subject: [PATCH 82/99] Update DatabaseBasic.md --- DataBase/DatabaseBasic.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/DataBase/DatabaseBasic.md b/DataBase/DatabaseBasic.md index cfb7d6b..6792184 100644 --- a/DataBase/DatabaseBasic.md +++ b/DataBase/DatabaseBasic.md @@ -18,3 +18,12 @@ > 4. 기본 키(primary key) : 각 행을 구분하는 유일한 특징을 지닌 열 > 5. 외래 키(foreign key) : 테이블 간 관계와 관련됨 > 6. SQL + +> #### 데이터베이스의 데이터 특징 +> - 데이터의 무결성 +> - 데이터의 독립성 +> - 보안 +> - 데이터 중복 최소화 +> - 응용 프로그램 제작 및 수정 용이 +> - 데이터의 안정성 + From c8785c365b390ef16f0cc1d4efdb20a8f930ba3e Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 30 Sep 2023 11:25:05 +0900 Subject: [PATCH 83/99] Update DatabaseBasic.md --- DataBase/DatabaseBasic.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataBase/DatabaseBasic.md b/DataBase/DatabaseBasic.md index 6792184..5fa1c89 100644 --- a/DataBase/DatabaseBasic.md +++ b/DataBase/DatabaseBasic.md @@ -15,7 +15,7 @@ > 1. 테이블(table) > 2. 필드(field=column) > 3. 레코드(record=row) -> 4. 기본 키(primary key) : 각 행을 구분하는 유일한 특징을 지닌 열 +> 4. 기본 키(primary key) : 각 행을 구분하는 유일한 특징을 지닌 열, 중복 값과 비어있는 값을 가질 수 없다. -> 데이터의 유일성 보장 > 5. 외래 키(foreign key) : 테이블 간 관계와 관련됨 > 6. SQL From 4d18675a83807aad6823d0c9ec4aaf6005f3750d Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Tue, 3 Oct 2023 14:29:25 +0900 Subject: [PATCH 84/99] Update README.md --- PipeLine/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PipeLine/README.md b/PipeLine/README.md index c0b6ce5..16e1449 100644 --- a/PipeLine/README.md +++ b/PipeLine/README.md @@ -15,3 +15,7 @@ ### ETL : 데이터를 얻어 알맞은 형태로 변환한 후 데이터 웨어하우스에 담기 ### ELT : 데이터를 얻어 데이터 레이크에 담은 후, 필요하면 데이터의 변환 작업을 수행 + +--- + +[데이터 파이프라인 구축 연습](https://github.com/CharmStrange/Project/tree/main/Python/DataFlows) From 6cd8fe92cce4ebc8a2563a1aec03537730b246a7 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Wed, 4 Oct 2023 16:30:56 +0900 Subject: [PATCH 85/99] Update README.md --- PipeLine/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/PipeLine/README.md b/PipeLine/README.md index 16e1449..7a28a10 100644 --- a/PipeLine/README.md +++ b/PipeLine/README.md @@ -1,3 +1,8 @@ +# 컴퓨터 과학에서의 파이프라인 +한 데이터 처리 단계의 출력이 다음 단계의 입력으로 이어지는 형태로 연결된 구조를 가리킨다. + +--- + # 데이터 파이프라인 데이터를 다루는 영역에 있어서, 데이터의 지속적 관리와 활용을 위해 구축된 환경(요소) From b566f679acab32b689c0052583c4c5a17a4df0c3 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Wed, 4 Oct 2023 16:32:36 +0900 Subject: [PATCH 86/99] Update README.md --- PipeLine/README.md | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/PipeLine/README.md b/PipeLine/README.md index 7a28a10..8d34631 100644 --- a/PipeLine/README.md +++ b/PipeLine/README.md @@ -1,26 +1,24 @@ # 컴퓨터 과학에서의 파이프라인 -한 데이터 처리 단계의 출력이 다음 단계의 입력으로 이어지는 형태로 연결된 구조를 가리킨다. +한 데이터 처리 단계의 출력이 다음 단계의 입력으로 이어지는 형태로 연결된 구조를 가리킨다. 모듈 개념과 연관되어 이해할 수 있다. (각 프로세스의 독립적 처리) --- -# 데이터 파이프라인 -데이터를 다루는 영역에 있어서, 데이터의 지속적 관리와 활용을 위해 구축된 환경(요소) - -데이터 파이프라인의 공정을 **ETL**이라 부르며 이는 **Extract**, **Transform**, **Loading** 작업을 뜻한다. 이는 **데어터 웨어하우스** : **잘 정돈된 데이터가 저장되는 시스템**을 구축하는 일련의 과정으로도 이해할 수 있다. (**ELT**도 있다) - - 데이터 웨어하우스와는 별개로 **데이터 레이크**란 개념도 있는데 이는 바로 수집되어 정돈되지 않은 상태의 데이터가 모이는 곳이다. - -더 발전하여 **데이터 마트**란 개념도 있다. 이는 데이터 웨어하우스의 상위 개념으로, 데이터 웨어하우스의 잘 정돈된 데이터들을 특정 목적을 위해 따로 분류된 데이터가 모이는 곳으로 볼 수 있다. -즉, ***[ 데이터 레이크 -> 데이터 웨어하우스 -> 데이터 마트 ]*** 의 큰 과정으로 보면 된다. +> # 데이터 파이프라인 +> 데이터를 다루는 영역에 있어서, 데이터의 지속적 관리와 활용을 위해 구축된 환경(요소) +> +> 데이터 파이프라인의 공정을 **ETL**이라 부르며 이는 **Extract**, **Transform**, **Loading** 작업을 뜻한다. 이는 **데어터 웨어하우스** : **잘 정돈된 데이터가 저장되는 시스템**을 구축하는 일련의 과정으로도 이해할 수 있다. (**ELT**도 있다) +> +> 데이터 웨어하우스와는 별개로 **데이터 레이크**란 개념도 있는데 이는 바로 수집되어 정돈되지 않은 상태의 데이터가 모이는 곳이다. +> +>더 발전하여 **데이터 마트**란 개념도 있다. 이는 데이터 웨어하우스의 상위 개념으로, 데이터 웨어하우스의 잘 정돈된 데이터들을 특정 목적을 위해 따로 분류된 데이터가 모이는 곳으로 볼 수 있다. +>즉, ***[ 데이터 레이크 -> 데이터 웨어하우스 -> 데이터 마트 ]*** 의 큰 과정으로 보면 된다. +> +> ## ETL vs ELT? +> +> ### ETL : 데이터를 얻어 알맞은 형태로 변환한 후 데이터 웨어하우스에 담기 +> +> ### ELT : 데이터를 얻어 데이터 레이크에 담은 후, 필요하면 데이터의 변환 작업을 수행 +> +> [데이터 파이프라인 구축 연습](https://github.com/CharmStrange/Project/tree/main/Python/DataFlows) --- - -## ETL vs ELT? - -### ETL : 데이터를 얻어 알맞은 형태로 변환한 후 데이터 웨어하우스에 담기 - -### ELT : 데이터를 얻어 데이터 레이크에 담은 후, 필요하면 데이터의 변환 작업을 수행 - ---- - -[데이터 파이프라인 구축 연습](https://github.com/CharmStrange/Project/tree/main/Python/DataFlows) From c64dd0d99e6b91dc4fc6dc22d9e59b3c6d73c469 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Wed, 4 Oct 2023 20:07:10 +0900 Subject: [PATCH 87/99] =?UTF-8?q?Create=20=EC=8B=9D=EB=B3=84=EC=9E=90.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "DataBase/\354\213\235\353\263\204\354\236\220.md" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "DataBase/\354\213\235\353\263\204\354\236\220.md" diff --git "a/DataBase/\354\213\235\353\263\204\354\236\220.md" "b/DataBase/\354\213\235\353\263\204\354\236\220.md" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/DataBase/\354\213\235\353\263\204\354\236\220.md" @@ -0,0 +1 @@ + From 0d62260fb00185c75baff0a2223ed1e2a6d3e908 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 6 Oct 2023 15:50:51 +0900 Subject: [PATCH 88/99] =?UTF-8?q?Update=20=EC=8B=9D=EB=B3=84=EC=9E=90.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "DataBase/\354\213\235\353\263\204\354\236\220.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/DataBase/\354\213\235\353\263\204\354\236\220.md" "b/DataBase/\354\213\235\353\263\204\354\236\220.md" index 8b13789..f7a593f 100644 --- "a/DataBase/\354\213\235\353\263\204\354\236\220.md" +++ "b/DataBase/\354\213\235\353\263\204\354\236\220.md" @@ -1 +1 @@ - +# 식별자 From aab6d9ad4dda077ed4d83f2d03c2e92c0ea7237d Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 6 Oct 2023 15:53:12 +0900 Subject: [PATCH 89/99] =?UTF-8?q?Update=20=EC=8B=9D=EB=B3=84=EC=9E=90.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "DataBase/\354\213\235\353\263\204\354\236\220.md" | 1 + 1 file changed, 1 insertion(+) diff --git "a/DataBase/\354\213\235\353\263\204\354\236\220.md" "b/DataBase/\354\213\235\353\263\204\354\236\220.md" index f7a593f..6f76177 100644 --- "a/DataBase/\354\213\235\353\263\204\354\236\220.md" +++ "b/DataBase/\354\213\235\353\263\204\354\236\220.md" @@ -1 +1,2 @@ # 식별자 +식별자는 데이터베이스 내 개체들의 속성을 대표하는 From f5761b96c81b3c7afbff84f36f20fe01df28b581 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 6 Oct 2023 15:53:52 +0900 Subject: [PATCH 90/99] Update Entity&ERD.md --- DataBase/Entity&ERD.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DataBase/Entity&ERD.md b/DataBase/Entity&ERD.md index 145c4ad..7cca739 100644 --- a/DataBase/Entity&ERD.md +++ b/DataBase/Entity&ERD.md @@ -1,5 +1,5 @@ # Entity & ERD -> 데이터베이스 내에서 개체를 **Entity**(**엔티티**)라 부른다 +> 데이터베이스 내에서 개체를 **Entity**(**엔티티**)라 부른다. > : **데이터베이스 전체적 관점에서 봤을 때, 작업에 필요한 정보 또는 대상** > > *테이블, 인덱스, 뷰, 트리거, 함수, 커서 등이 **Entity*** > > @@ -14,5 +14,5 @@ > ### 발생에 따른 Entity > **기본**, **중심**, **행위** Entity --- -> **ERD**는 *Entity Relation Diagram* 의 약자, 개체 관계 다이어그램으로 해석되며 데이터베이스의 개체 관계를 구조적으로 표현하기 위해 제작하는 다이어그램. +> **ERD**는 *Entity Relation Diagram* 의 약자, 개체 관계 다이어그램으로 해석되며 데이터베이스의 개체 관계를 구조적으로 표현하기 위해 제작하는 다이어그램이다. > ![image](https://github.com/CharmStrange/Study/assets/105769152/b6d7c64e-d5ad-42be-bfa3-4fdb74d5a916) (Wikipedia) From 4112b2ce3f246c2239feac8d7b32c322d37dd190 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 6 Oct 2023 16:37:26 +0900 Subject: [PATCH 91/99] =?UTF-8?q?Update=20=EC=8B=9D=EB=B3=84=EC=9E=90.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "DataBase/\354\213\235\353\263\204\354\236\220.md" | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git "a/DataBase/\354\213\235\353\263\204\354\236\220.md" "b/DataBase/\354\213\235\353\263\204\354\236\220.md" index 6f76177..f1f0694 100644 --- "a/DataBase/\354\213\235\353\263\204\354\236\220.md" +++ "b/DataBase/\354\213\235\353\263\204\354\236\220.md" @@ -1,2 +1,13 @@ # 식별자 -식별자는 데이터베이스 내 개체들의 속성을 대표하는 +식별자는 데이터베이스 내 개체들의 속성을 대표한다. 데이터베이스의 각 개체들은 반드시 유일한 식별자가 존재해야 하며 논리적 모델링을 할 때 미리 설계를 해야 한다. + +### 식별자의 종류 +- **주식별자** : 개체를 구분할 수 있게 하는 구분자이며, 다른 개체와 참조 관계를 연결할 수 있다. 유일성, 최소성, 불변성, 존재성 모두를 충족해야 하며, 존재성은 `Not Null`을 의미한다. +- **보조식별자** : 다른 개체와의 참조 관계를 연결할 수 없다. 주식별자에 비해 대표성이 떨어진다는 특징이 있는 식별자. +- **내부식별자** : 개체 내부에서 자체적으로 생성되는 정보를 함축하고 있는 식별자. +- **외부식별자** : 다른 개체와의 관계를 통해 그 관계를 알 수 있는 정보가 담긴 식별자다. 다른 개체를 통해 가져오는 식별자. +- **단일식별자** : 속성이 하나로 구성된 식별자. +- **복합식별자** : 두 개 이상의 속성으로 구성된 식별자. + +### 고려해 보아야 하는 것 +**주식별자**는 자주 사용되는 속성으로 정하는 것이 좋고, 범위가 넓고 애매한 명칭의 속성은 주식별자로 지정하지 않는 것이 좋다. From 838e93e7ad0eac79ba0d713597e00ffd4a0bb237 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sat, 7 Oct 2023 17:34:14 +0900 Subject: [PATCH 92/99] Create README.md --- "\352\270\260\354\264\210/\354\210\230\355\225\231/README.md" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "\352\270\260\354\264\210/\354\210\230\355\225\231/README.md" diff --git "a/\352\270\260\354\264\210/\354\210\230\355\225\231/README.md" "b/\352\270\260\354\264\210/\354\210\230\355\225\231/README.md" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/\352\270\260\354\264\210/\354\210\230\355\225\231/README.md" @@ -0,0 +1 @@ + From 224713b4dd9cc75cbe4e6cf5e31188da5ba3b269 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 15 Oct 2023 19:44:18 +0900 Subject: [PATCH 93/99] Create README.md --- Data Handling/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Data Handling/README.md diff --git a/Data Handling/README.md b/Data Handling/README.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Data Handling/README.md @@ -0,0 +1 @@ + From b41cc209151f48de86d058445d7162a5daa5ded8 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 15 Oct 2023 19:51:42 +0900 Subject: [PATCH 94/99] Update README.md --- Data Handling/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Data Handling/README.md b/Data Handling/README.md index 8b13789..ca58e4f 100644 --- a/Data Handling/README.md +++ b/Data Handling/README.md @@ -1 +1,10 @@ +# 데이터 핸들링 기초 +> ## 데이터 탐색 +> > - 데이터를 어떻게 수집할 것인가? +> > +> > **First-Party Data** : 직접 수집한 데이터 +> > +> > **Second-Party Data** : 다른 주체에 의해 수집되어 제공되는 데이터 +> > +> > **Third-Party Data** : 데이터를 직접 수집하지 않은 주체에 의해 제공되는 데이터 From 78f4e1ada23d409ea7717816a9fb20b9dbd3397c Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 15 Oct 2023 19:54:42 +0900 Subject: [PATCH 95/99] Update README.md --- Data Handling/README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Data Handling/README.md b/Data Handling/README.md index ca58e4f..761c161 100644 --- a/Data Handling/README.md +++ b/Data Handling/README.md @@ -1,10 +1,16 @@ # 데이터 핸들링 기초 -> ## 데이터 탐색 -> > - 데이터를 어떻게 수집할 것인가? +> ### 데이터 탐색 +> - 데이터를 어떻게 수집할 것인가? > > > > **First-Party Data** : 직접 수집한 데이터 > > > > **Second-Party Data** : 다른 주체에 의해 수집되어 제공되는 데이터 > > > > **Third-Party Data** : 데이터를 직접 수집하지 않은 주체에 의해 제공되는 데이터 +> +> - 데이터를 얼마나 수집할 것인가? +> > +> > <**샘플의 크기를 고려**> +> > +> > <**시간 프레임을 고려**> From 93249c303c7e32839ffec2183446e584a8a187b8 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 15 Oct 2023 20:02:38 +0900 Subject: [PATCH 96/99] Update README.md --- Data Handling/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Data Handling/README.md b/Data Handling/README.md index 761c161..b84df5d 100644 --- a/Data Handling/README.md +++ b/Data Handling/README.md @@ -14,3 +14,15 @@ > > <**샘플의 크기를 고려**> > > > > <**시간 프레임을 고려**> + +> ### 데이터 유형 +> - **Primary Data** : 연구, 실험에 의해 수집된 데이터 +> - **Secondary Data** : 일반인, 기업에 의해 (불규칙적으로)수집된 데이터 +> - **Internal Data** : 비공개 데이터 또는 내부 데이터 +> - **External Data** : 공개 데이터 또는 외부 데이터 +> - ***Continuous Data*** : 수치형 값을 가진 데이터 +> - ***Discrete Data*** : 이산적 값을 가진 데이터 +> - **Qualitative** : 질적 데이터 또는 범주형 데이터 +> - **Quantative** : 양적 데이터 또는 수치형 데이터 +> - **Nominal** : 특정 패턴이 없는 데이터 또는 독립적인 데이터 +> - **Ordinal** : 패턴이 존재하는 데이터 또는 규칙화된 데이터 From 387848b5b1022668aa8dfeed81ed720d8857d662 Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Sun, 15 Oct 2023 20:17:48 +0900 Subject: [PATCH 97/99] Update README.md --- Data Handling/README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Data Handling/README.md b/Data Handling/README.md index b84df5d..ba8ce51 100644 --- a/Data Handling/README.md +++ b/Data Handling/README.md @@ -1,7 +1,7 @@ # 데이터 핸들링 기초 > ### 데이터 탐색 -> - 데이터를 어떻게 수집할 것인가? +> - 데이터를 어떻게 수집할 것인가? > > > > **First-Party Data** : 직접 수집한 데이터 > > @@ -26,3 +26,12 @@ > - **Quantative** : 양적 데이터 또는 수치형 데이터 > - **Nominal** : 특정 패턴이 없는 데이터 또는 독립적인 데이터 > - **Ordinal** : 패턴이 존재하는 데이터 또는 규칙화된 데이터 +> > + #### 데이터 구조 +> > - **Structured Data** : 정형 데이터, 행렬과 같은 형태 +> > - **Unstructured Data** : 비정형 데이터 + +> ### 데이터 모델링 +> #### 데이터를 어떻게 구성, 구조화할 지 설명 +> - **Conceptional Modeling** : 상위 계층에서 데이터 구조를 정의하며, 포괄적인 흐름 정도를 나타내는 모델링 +> - **Logical Modeling** : 중위 계층에서 좀 더 상세한 데이터 구조와 흐름을 나타내는 모델링 +> - **Physical Modeling** : 하위 계층에서 자세한 데이터 구조와 흐름의 기술적 정의를 나타내는 모델링 From 368ba80b09837ca6a37b019648cdeb45421d2e5a Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 5 Apr 2024 21:02:22 +0900 Subject: [PATCH 98/99] =?UTF-8?q?Delete=20=EA=B8=B0=EC=B4=88/=EC=88=98?= =?UTF-8?q?=ED=95=99/=EB=B2=A1=ED=84=B0=EC=99=80=ED=96=89=EB=A0=AC.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...3\262\241\355\204\260\354\231\200\355\226\211\353\240\254.md" | 1 - 1 file changed, 1 deletion(-) delete mode 100644 "\352\270\260\354\264\210/\354\210\230\355\225\231/\353\262\241\355\204\260\354\231\200\355\226\211\353\240\254.md" diff --git "a/\352\270\260\354\264\210/\354\210\230\355\225\231/\353\262\241\355\204\260\354\231\200\355\226\211\353\240\254.md" "b/\352\270\260\354\264\210/\354\210\230\355\225\231/\353\262\241\355\204\260\354\231\200\355\226\211\353\240\254.md" deleted file mode 100644 index 8b13789..0000000 --- "a/\352\270\260\354\264\210/\354\210\230\355\225\231/\353\262\241\355\204\260\354\231\200\355\226\211\353\240\254.md" +++ /dev/null @@ -1 +0,0 @@ - From 3efcccea5ddd9338961c6cd412d685d1fd5cbb6c Mon Sep 17 00:00:00 2001 From: LKH <105769152+CharmStrange@users.noreply.github.com> Date: Fri, 5 Apr 2024 21:07:51 +0900 Subject: [PATCH 99/99] Create Gradient.md --- "\352\270\260\354\264\210/\354\210\230\355\225\231/Gradient.md" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "\352\270\260\354\264\210/\354\210\230\355\225\231/Gradient.md" diff --git "a/\352\270\260\354\264\210/\354\210\230\355\225\231/Gradient.md" "b/\352\270\260\354\264\210/\354\210\230\355\225\231/Gradient.md" new file mode 100644 index 0000000..6a25e68 --- /dev/null +++ "b/\352\270\260\354\264\210/\354\210\230\355\225\231/Gradient.md" @@ -0,0 +1 @@ +[Post](https://blog.naver.com/zetmond/223405967977)