diff --git a/notebooks/1.0_DataLoading.ipynb b/notebooks/1.0_DataLoading.ipynb
index 4be0e38..a28ca32 100644
--- a/notebooks/1.0_DataLoading.ipynb
+++ b/notebooks/1.0_DataLoading.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
@@ -18,7 +18,7 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 11,
"metadata": {},
"outputs": [
{
@@ -216,7 +216,7 @@
"[5 rows x 37 columns]"
]
},
- "execution_count": 3,
+ "execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
@@ -228,7 +228,27 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(87, 37)"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "data.shape"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
"metadata": {},
"outputs": [
{
@@ -249,7 +269,7 @@
" 33.11848833, 2. ]])"
]
},
- "execution_count": 4,
+ "execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
@@ -262,7 +282,27 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(87, 37)"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "data.shape"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
@@ -275,7 +315,7 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 16,
"metadata": {},
"outputs": [
{
@@ -321,7 +361,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "practice1",
+ "display_name": "che4230",
"language": "python",
"name": "python3"
},
@@ -335,7 +375,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.9"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/notebooks/2.0_Test_DataLoading.ipynb b/notebooks/2.0_Test_DataLoading.ipynb
index 7c55704..4358ca2 100644
--- a/notebooks/2.0_Test_DataLoading.ipynb
+++ b/notebooks/2.0_Test_DataLoading.ipynb
@@ -2,16 +2,16 @@
"cells": [
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
- "'c:\\\\Users\\\\Gabi\\\\git\\\\meter_Hw4'"
+ "'/Users/sanyao1/Library/CloudStorage/OneDrive-LouisianaStateUniversity(2)/lsu spring-25/CHE 4230/homeworks/Assignment 4'"
]
},
- "execution_count": 2,
+ "execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
@@ -34,7 +34,7 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
@@ -43,58 +43,25 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 6,
"metadata": {},
"outputs": [
{
- "name": "stdout",
- "output_type": "stream",
- "text": [
- " 0 1 2 3 4 5 6 \\\n",
- "0 0.841499 1.009367 0.993816 8.469805 10.278727 10.037759 8.501365 \n",
- "1 0.842250 1.006584 0.996605 7.531891 9.139924 8.951618 7.612213 \n",
- "2 0.840723 1.011647 0.998152 6.641699 7.975464 7.857692 6.593117 \n",
- "3 0.841119 1.017807 0.996812 5.687524 6.824334 6.689885 5.615428 \n",
- "4 0.840358 1.016534 0.996221 5.660385 6.829560 6.675628 5.623977 \n",
- "\n",
- " 7 8 9 ... 27 28 29 \\\n",
- "0 8.581726 10.247763 10.058822 ... 32.451173 34.568685 33.082683 \n",
- "1 7.623325 9.106345 8.945142 ... 32.428385 34.441732 33.081055 \n",
- "2 6.681572 7.964596 7.814698 ... 32.428385 34.275715 33.113605 \n",
- "3 5.763315 6.801051 6.686639 ... 32.485350 34.080403 33.170573 \n",
- "4 5.736818 6.813453 6.672377 ... 32.503255 34.122720 33.164062 \n",
- "\n",
- " 30 31 32 33 34 35 36 \n",
- "0 36.722005 36.969403 36.075847 36.051432 35.174155 32.729490 1 \n",
- "1 36.687825 36.933595 36.054688 35.979818 34.847005 32.731122 1 \n",
- "2 36.661785 36.873370 36.002605 35.963542 34.689128 32.771810 1 \n",
- "3 36.673177 36.811525 35.974935 35.955403 34.500328 32.849935 1 \n",
- "4 36.673177 36.826173 35.996095 35.968425 34.474283 32.853190 1 \n",
- "\n",
- "[5 rows x 37 columns]\n"
+ "ename": "FileNotFoundError",
+ "evalue": "[Errno 2] No such file or directory: 'data/Meter_A.txt'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[6], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m preprocessor \u001b[38;5;241m=\u001b[39m DataPreprocessing()\n\u001b[0;32m----> 3\u001b[0m \u001b[43mpreprocessor\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload_data\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mdata/Meter_A.txt\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n",
+ "File \u001b[0;32m~/Library/CloudStorage/OneDrive-LouisianaStateUniversity(2)/lsu spring-25/CHE 4230/homeworks/Assignment 4/meter_Hw4/src/data_preprocess.py:9\u001b[0m, in \u001b[0;36mDataPreprocessing.load_data\u001b[0;34m(self, path)\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mload_data\u001b[39m(\u001b[38;5;28mself\u001b[39m, path):\n\u001b[0;32m----> 9\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[43mpd\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mread_csv\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpath\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msep\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;130;43;01m\\t\u001b[39;49;00m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mheader\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mdropna()\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28mprint\u001b[39m(data\u001b[38;5;241m.\u001b[39mhead())\n\u001b[1;32m 13\u001b[0m data \u001b[38;5;241m=\u001b[39m data\u001b[38;5;241m.\u001b[39mto_numpy()\n",
+ "File \u001b[0;32m/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/pandas/io/parsers/readers.py:1026\u001b[0m, in \u001b[0;36mread_csv\u001b[0;34m(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, date_format, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options, dtype_backend)\u001b[0m\n\u001b[1;32m 1013\u001b[0m kwds_defaults \u001b[38;5;241m=\u001b[39m _refine_defaults_read(\n\u001b[1;32m 1014\u001b[0m dialect,\n\u001b[1;32m 1015\u001b[0m delimiter,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1022\u001b[0m dtype_backend\u001b[38;5;241m=\u001b[39mdtype_backend,\n\u001b[1;32m 1023\u001b[0m )\n\u001b[1;32m 1024\u001b[0m kwds\u001b[38;5;241m.\u001b[39mupdate(kwds_defaults)\n\u001b[0;32m-> 1026\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_read\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfilepath_or_buffer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkwds\u001b[49m\u001b[43m)\u001b[49m\n",
+ "File \u001b[0;32m/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/pandas/io/parsers/readers.py:620\u001b[0m, in \u001b[0;36m_read\u001b[0;34m(filepath_or_buffer, kwds)\u001b[0m\n\u001b[1;32m 617\u001b[0m _validate_names(kwds\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnames\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;28;01mNone\u001b[39;00m))\n\u001b[1;32m 619\u001b[0m \u001b[38;5;66;03m# Create the parser.\u001b[39;00m\n\u001b[0;32m--> 620\u001b[0m parser \u001b[38;5;241m=\u001b[39m \u001b[43mTextFileReader\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfilepath_or_buffer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwds\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 622\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m chunksize \u001b[38;5;129;01mor\u001b[39;00m iterator:\n\u001b[1;32m 623\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m parser\n",
+ "File \u001b[0;32m/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/pandas/io/parsers/readers.py:1620\u001b[0m, in \u001b[0;36mTextFileReader.__init__\u001b[0;34m(self, f, engine, **kwds)\u001b[0m\n\u001b[1;32m 1617\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moptions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mhas_index_names\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m kwds[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mhas_index_names\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n\u001b[1;32m 1619\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mhandles: IOHandles \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m-> 1620\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_engine \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_make_engine\u001b[49m\u001b[43m(\u001b[49m\u001b[43mf\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mengine\u001b[49m\u001b[43m)\u001b[49m\n",
+ "File \u001b[0;32m/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/pandas/io/parsers/readers.py:1880\u001b[0m, in \u001b[0;36mTextFileReader._make_engine\u001b[0;34m(self, f, engine)\u001b[0m\n\u001b[1;32m 1878\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mb\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m mode:\n\u001b[1;32m 1879\u001b[0m mode \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mb\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m-> 1880\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mhandles \u001b[38;5;241m=\u001b[39m \u001b[43mget_handle\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1881\u001b[0m \u001b[43m \u001b[49m\u001b[43mf\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1882\u001b[0m \u001b[43m \u001b[49m\u001b[43mmode\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1883\u001b[0m \u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mencoding\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1884\u001b[0m \u001b[43m \u001b[49m\u001b[43mcompression\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcompression\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1885\u001b[0m \u001b[43m \u001b[49m\u001b[43mmemory_map\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mmemory_map\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1886\u001b[0m \u001b[43m \u001b[49m\u001b[43mis_text\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mis_text\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1887\u001b[0m \u001b[43m \u001b[49m\u001b[43merrors\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mencoding_errors\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mstrict\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1888\u001b[0m \u001b[43m \u001b[49m\u001b[43mstorage_options\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mstorage_options\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1889\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1890\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mhandles \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 1891\u001b[0m f \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mhandles\u001b[38;5;241m.\u001b[39mhandle\n",
+ "File \u001b[0;32m/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/pandas/io/common.py:873\u001b[0m, in \u001b[0;36mget_handle\u001b[0;34m(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options)\u001b[0m\n\u001b[1;32m 868\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(handle, \u001b[38;5;28mstr\u001b[39m):\n\u001b[1;32m 869\u001b[0m \u001b[38;5;66;03m# Check whether the filename is to be opened in binary mode.\u001b[39;00m\n\u001b[1;32m 870\u001b[0m \u001b[38;5;66;03m# Binary mode does not support 'encoding' and 'newline'.\u001b[39;00m\n\u001b[1;32m 871\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m ioargs\u001b[38;5;241m.\u001b[39mencoding \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mb\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m ioargs\u001b[38;5;241m.\u001b[39mmode:\n\u001b[1;32m 872\u001b[0m \u001b[38;5;66;03m# Encoding\u001b[39;00m\n\u001b[0;32m--> 873\u001b[0m handle \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mopen\u001b[39;49m\u001b[43m(\u001b[49m\n\u001b[1;32m 874\u001b[0m \u001b[43m \u001b[49m\u001b[43mhandle\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 875\u001b[0m \u001b[43m \u001b[49m\u001b[43mioargs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmode\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 876\u001b[0m \u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mioargs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 877\u001b[0m \u001b[43m \u001b[49m\u001b[43merrors\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43merrors\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 878\u001b[0m \u001b[43m \u001b[49m\u001b[43mnewline\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 879\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 880\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 881\u001b[0m \u001b[38;5;66;03m# Binary mode\u001b[39;00m\n\u001b[1;32m 882\u001b[0m handle \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mopen\u001b[39m(handle, ioargs\u001b[38;5;241m.\u001b[39mmode)\n",
+ "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'data/Meter_A.txt'"
]
- },
- {
- "data": {
- "text/plain": [
- "array([[ 0.84149871, 1.00936653, 0.99381601, ..., 35.174155 ,\n",
- " 32.72949 , 1. ],\n",
- " [ 0.84225022, 1.00658369, 0.99660521, ..., 34.847005 ,\n",
- " 32.73112167, 1. ],\n",
- " [ 0.84072314, 1.01164657, 0.99815174, ..., 34.68912833,\n",
- " 32.77181 , 1. ],\n",
- " ...,\n",
- " [ 0.79347112, 1.00955964, 1.00111012, ..., 33.82487 ,\n",
- " 33.02083167, 2. ],\n",
- " [ 0.79672987, 1.01057037, 0.99902897, ..., 33.81673167,\n",
- " 33.01106667, 2. ],\n",
- " [ 0.79019427, 1.00419541, 0.99553749, ..., 33.66862167,\n",
- " 33.11848833, 2. ]])"
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
}
],
"source": [
@@ -106,7 +73,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "practice1",
+ "display_name": "che4230",
"language": "python",
"name": "python3"
},
@@ -120,7 +87,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.9"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/notebooks/3.0_Model_built.ipynb b/notebooks/3.0_Model_built.ipynb
index 35cc720..a596c4f 100644
--- a/notebooks/3.0_Model_built.ipynb
+++ b/notebooks/3.0_Model_built.ipynb
@@ -8,7 +8,7 @@
{
"data": {
"text/plain": [
- "'c:\\\\Users\\\\Gabi\\\\git\\\\meter_Hw4'"
+ "'/Users/sanyao1/Library/CloudStorage/OneDrive-LouisianaStateUniversity(2)/lsu spring-25/CHE 4230/homeworks/Assignment 4/meter_Hw4'"
]
},
"execution_count": 1,
@@ -36,7 +36,7 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 3,
"metadata": {},
"outputs": [
{
@@ -76,7 +76,7 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": 4,
"metadata": {},
"outputs": [
{
@@ -85,7 +85,7 @@
"numpy.ndarray"
]
},
- "execution_count": 7,
+ "execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
@@ -103,7 +103,7 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
@@ -112,7 +112,7 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
@@ -123,7 +123,7 @@
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
@@ -132,7 +132,7 @@
},
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
@@ -143,16 +143,16 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
- "{1.0, 2.0}"
+ "{np.float64(1.0), np.float64(2.0)}"
]
},
- "execution_count": 11,
+ "execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
@@ -166,7 +166,7 @@
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
@@ -175,7 +175,7 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
@@ -184,7 +184,7 @@
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": 13,
"metadata": {},
"outputs": [
{
@@ -192,7 +192,8 @@
"text/html": [
"
DecisionTreeClassifier(criterion='entropy', max_depth=3) In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org. "
+ "DecisionTreeClassifier(criterion='entropy', max_depth=3) In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org. "
],
"text/plain": [
"DecisionTreeClassifier(criterion='entropy', max_depth=3)"
]
},
- "execution_count": 14,
+ "execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
@@ -611,7 +622,7 @@
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -621,7 +632,7 @@
},
{
"cell_type": "code",
- "execution_count": 16,
+ "execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
@@ -630,7 +641,7 @@
},
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": 16,
"metadata": {},
"outputs": [
{
@@ -639,7 +650,7 @@
"0.9285714285714286"
]
},
- "execution_count": 17,
+ "execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
@@ -658,7 +669,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "practice1",
+ "display_name": "che4230",
"language": "python",
"name": "python3"
},
@@ -672,7 +683,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.9"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/notebooks/4.0_Test_Model_built.ipynb b/notebooks/4.0_Test_Model_built.ipynb
index 7fe4319..fe21833 100644
--- a/notebooks/4.0_Test_Model_built.ipynb
+++ b/notebooks/4.0_Test_Model_built.ipynb
@@ -8,7 +8,7 @@
{
"data": {
"text/plain": [
- "'c:\\\\Users\\\\Gabi\\\\git\\\\meter_Hw4'"
+ "'/Users/sanyao1/Library/CloudStorage/OneDrive-LouisianaStateUniversity(2)/lsu spring-25/CHE 4230/homeworks/Assignment 4/meter_Hw4'"
]
},
"execution_count": 1,
@@ -36,7 +36,7 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 4,
"metadata": {},
"outputs": [
{
@@ -76,7 +76,7 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 5,
"metadata": {},
"outputs": [
{
@@ -85,7 +85,7 @@
"numpy.ndarray"
]
},
- "execution_count": 4,
+ "execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
@@ -103,7 +103,7 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
@@ -112,7 +112,7 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
@@ -123,7 +123,7 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
@@ -136,7 +136,7 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
@@ -145,7 +145,7 @@
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": null,
"metadata": {},
"outputs": [
{
@@ -154,7 +154,7 @@
"0.9285714285714286"
]
},
- "execution_count": 9,
+ "execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
@@ -170,7 +170,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "practice1",
+ "display_name": "che4230",
"language": "python",
"name": "python3"
},
@@ -184,7 +184,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.9"
+ "version": "3.12.9"
}
},
"nbformat": 4,
diff --git a/notebooks/5.0_ann_model.ipynb b/notebooks/5.0_ann_model.ipynb
new file mode 100644
index 0000000..8eaa493
--- /dev/null
+++ b/notebooks/5.0_ann_model.ipynb
@@ -0,0 +1,313 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'/Users/sanyao1/Library/CloudStorage/OneDrive-LouisianaStateUniversity(2)/lsu spring-25/CHE 4230/homeworks/Assignment 4/meter_Hw4'"
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "import os\n",
+ "import warnings\n",
+ "\n",
+ "os.chdir(\"../\")\n",
+ "\n",
+ "os.getcwd()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from src.data_preprocess import DataPreprocessing"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " 0 1 2 3 4 5 6 \\\n",
+ "0 0.841499 1.009367 0.993816 8.469805 10.278727 10.037759 8.501365 \n",
+ "1 0.842250 1.006584 0.996605 7.531891 9.139924 8.951618 7.612213 \n",
+ "2 0.840723 1.011647 0.998152 6.641699 7.975464 7.857692 6.593117 \n",
+ "3 0.841119 1.017807 0.996812 5.687524 6.824334 6.689885 5.615428 \n",
+ "4 0.840358 1.016534 0.996221 5.660385 6.829560 6.675628 5.623977 \n",
+ "\n",
+ " 7 8 9 ... 27 28 29 \\\n",
+ "0 8.581726 10.247763 10.058822 ... 32.451173 34.568685 33.082683 \n",
+ "1 7.623325 9.106345 8.945142 ... 32.428385 34.441732 33.081055 \n",
+ "2 6.681572 7.964596 7.814698 ... 32.428385 34.275715 33.113605 \n",
+ "3 5.763315 6.801051 6.686639 ... 32.485350 34.080403 33.170573 \n",
+ "4 5.736818 6.813453 6.672377 ... 32.503255 34.122720 33.164062 \n",
+ "\n",
+ " 30 31 32 33 34 35 36 \n",
+ "0 36.722005 36.969403 36.075847 36.051432 35.174155 32.729490 1 \n",
+ "1 36.687825 36.933595 36.054688 35.979818 34.847005 32.731122 1 \n",
+ "2 36.661785 36.873370 36.002605 35.963542 34.689128 32.771810 1 \n",
+ "3 36.673177 36.811525 35.974935 35.955403 34.500328 32.849935 1 \n",
+ "4 36.673177 36.826173 35.996095 35.968425 34.474283 32.853190 1 \n",
+ "\n",
+ "[5 rows x 37 columns]\n"
+ ]
+ }
+ ],
+ "source": [
+ "preprocessor = DataPreprocessing()\n",
+ "\n",
+ "data = preprocessor.load_data(\"data/Meter_A.txt\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "numpy.ndarray"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "type(data)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Data Preprocessing"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import train_test_split\n",
+ "from sklearn.preprocessing import StandardScaler"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Split the dataset into training/validation and test sets\n",
+ "train_validation, test = train_test_split(data, test_size = 0.2, random_state=12)\n",
+ "\n",
+ "# Split the remaining into traning and validation sets\n",
+ "train, validation = train_test_split(train_validation, test_size = 0.2, random_state=99)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Isolate the features and target variable of training dataset\n",
+ "X_train = train[:, :-1]\n",
+ "y_train = train[:, -1]\n",
+ "\n",
+ "# Ensure all duplicates are removed\n",
+ "#set(y_train)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Isolate the features and target variable of test dataset\n",
+ "X_test = test[:, :-1]\n",
+ "y_test = test[:, -1] \n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Standardize the features of training data\n",
+ "scaler = StandardScaler()\n",
+ "X_train_scaled = scaler.fit_transform(X_train)\n",
+ "X_test_scaled = scaler.transform(X_test)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Train ANN model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Import MLPRegressor from sklearn neural network\n",
+ "from sklearn.neural_network import MLPRegressor\n",
+ "from sklearn.metrics import mean_squared_error, r2_score"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet.\n",
+ " warnings.warn(\n",
+ "/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet.\n",
+ " warnings.warn(\n",
+ "/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet.\n",
+ " warnings.warn(\n",
+ "/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet.\n",
+ " warnings.warn(\n",
+ "/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet.\n",
+ " warnings.warn(\n",
+ "/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet.\n",
+ " warnings.warn(\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Optimized ANN Regression - MSE: 0.0452, R² Score: 0.8192\n",
+ "Best Parameters: {'hidden_layer_sizes': (100, 50, 25, 10), 'learning_rate_init': 0.001, 'max_iter': 500}\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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sU/vu+8+O5mXqndV3frSSy/ZoRAWL16c4fdX4KZAyL2sPJTG1lRoqkvtO3bsmO6QEAqZatSoke77ukFyPIZF6Nevnxk5cqQd11hVt/fee6/59NNPbaCtib4U5Cj4Xr58uR3CQcGRKjU1dIXG+rz77rttdbDG4NXz3OAwmio+jRWsUHro0KE2lFY4pcnrVPGqSeief/55G57qcyo81fbTZ9+7d69drwqr3IBQVbd6b1X8anxTVYGrLyhcdAO7UHovVWh3797dtkWTrykM0/tWqlTJjrucKKF9NBKNy6pxoBXOqWJSwzvoBILCMe9JAQ33oT506aWX2m2qwEzDkqjq1nsyROtMfV9jU6vyUvuGqkU3btxo+6mqtkePHh22LUOGDLFDASgs1+uqelPbRev7eIZPOJ59O5Hcz6STJKHvqSpi9XEF8apM9/b3aLdZJOrfWqfq+wpUNaSCKuoXLVpkhxxxad9UtfJdd91lGjZsaJdTWyLR8nodVXgrYNVYxgq7j7e9smbNGnvFg+j4qvWi/VaV1OprolBdYwdru+o4p/2uXLlyZvPmzbbSXH1TQXKiPj/gWw4AAAAAnEDGjx+v0lBn0aJFaS43c+ZM5/zzz3fy58/vFC5c2LniiiucVatWpVpuxowZTs2aNZ08efI4p59+uvPOO+84gwcPtu/hpd/79u2bbvu2b9/u5MqVy7n++usjLnPgwAGnQIECTocOHdL9TN26dbOP1ahRI+j+ihUrOm3atEm1/K+//urkzJnTPufDDz9Ms63r1q2zyz399NNhH7/xxhvta61du9b+vnfvXueBBx5wqlWrZtdXiRIlnMaNGzvPPPOMc/jw4cDzdu7c6Vx77bVOoUKFnCJFitjX+f777+17vffee0GfrWDBghHb9+qrrzr169e321CvVatWLWfAgAHOli1b7OOLFy92rrnmGufUU0918ubN65QqVcq5/PLLnR9++CHwGh999JHTsmVL+5jarGV79erlbN26NbDMrFmzbNv0r9f777/v1KtXz752sWLFnK5duzp//PFH0DKRPkO4PhRO8+bNU23bUG77QrenPn+rVq2ck046yfanCy+80Jk7d26q5y9btsy+T758+Zxy5co5jz32mDNu3Dj7muoDoe+l19R20/JVq1a128+7TkM/21dffeW0a9fOKVu2rF3H+lfbZc2aNRn6/On1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f5uTTz7ZpKSkxK9lAAAAAAAAAIDkh8LhFCtWLB4vAwAAAAAAAADIaqGwho4YNmyY+eqrr8yOHTvMsWPHgh7//fff49k+AAAAAAAAAEAyQ+GbbrrJfPPNN+b66683ZcqUYcgIAAAAAAAAAMjOofAXX3xhpk6das4///zEtAgAAAAAAAAAkDA5Yn2CJpRjDOGs7dlnnzXly5c3uXLlMuvXr4+4nKq8P/nkk4iPz5492y6za9euiMu88cYbpmjRomm255FHHjF169Y1mSWaNmV10az7rKBZs2ZmwoQJyW6GWbVqle3zGt4mO6339PbR7EzHLn3+pUuXRv2czD7WIL4uuOAC079/f+NHjz76qMmXL5/tvwsWLEh2cwAAAAD4QMyh8GOPPWYefvhhc+DAgcS0CMfl4MGD5v777zc33HCDWbdunalQoULQF24FptFq3Lix2bp1qylSpEiCWoussO4VhFaqVCnm53366adm+/btpkuXLoH7Xn31VdvPChcuHDFc/fvvv03Xrl3tMgrve/bsafbt2xe0zLJly0zTpk1tSKI+PHz48DTbctZZZ5lzzz3XPPfcczF/DrUzrZMnyaQ+cNlll5nsGOCmR9tdn79mzZpRP+eee+6x4927brzxRtO+ffu4bPONGzeaNm3amAIFCphSpUqZe++91xw5ciTN58Sjr69cudJceeWVdh9Vu0eOHGkyQs/Xvp6VTZo0yf4/hrfNGf284cS63X/66SdzzTXX2O2SP39+c+aZZ5rnn38+1XJar2effbbJmzevqVatWti/sy+++KL9PNrOjRo1MgsXLgx6/O6777b7j97niSeeyOAnBAAAAIAEhsKqQp0+fbopXbq0qVWrlv0i5L0huXbu3GmDio4dO9ovsjlz5szwa+XJk8eccsopjBudQf/991+2XvcvvPCC6d69u8mR4/8/jOhk0aWXXmoefPDBiM9TSKag68svvzSfffaZ+fbbb80tt9wSeHzPnj2mZcuWpmLFiubHH380Tz/9tK0AVeCcFrXlpZdeSjeoSzbHcaJuo/qAgqZkOXz4cNLeW8cufX5d8RCtk046yRQvXjzubTl69KgNhLU+5s6da958800b/OkEaVri0de1T1WpUsVO8Kr1kZ3pKqRChQplmX6sbaITAO+8847djgMHDjQPPPCAGT16dGAZnXxV37jwwgttqKtKZ829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ap577jn7BWb37t3mrrvuMh07drRfVlVFivjZuXOnDQe0fvVFM2fOnBl+LVUgKcTPquFWVvfff/9l63X/wgsvmO7du9v92HXgwAEbpKYVUCiEXblypfnyyy9tddu3335rbrnllsDje/bsMS1btrSTUv7444/m6aeftscJBc6xUlsUkLm3iRMnxtQWN1zWZ83qdPItmopmHRPUt3QlQbKEBmSZKSP7lgLkRFR6Z6SvazsrENY6nDt3rnnzzTdtKPrwww8Hlvn3339NyZIlzaBBg0ydOnVMdpaobZPRPqqQVvvhK6+8Yo8tI0aMMC+//HLQMTGa7a5te80119iAecmSJbYaWrcVK1YEllHoXKVKFdsfNm/efJyfGAAAAACi4MSoSpUqzmeffWZ/Pumkk5y1a9fan59//nnnmmuuifXlkIZ169Y52kRLlixJ9Vjz5s2d8ePHB37Xcq+99prTvn17J3/+/E61atWcKVOmBB6fNWuWXeaff/4J3KfnV6hQwS6v5z3zzDNOkSJFgt5n6NChTqlSpey27tGjh3Pfffc5derUCVpG73vGGWc4efPmdU4//XTnxRdfTPUZPv74Y+eCCy6w71W7dm1n7ty5Ua0DtdHbJvW3tm3b2jYVLFjQadCggfPll18GHn/00UedGjVqpHodtXnQoEExtfm9995zmjVrZpfxrutw1q9f71x++eVO0aJFnQIFCjhnnXWWM3Xq1LDrXttOv4fe9L6i5Xr27OmUKFHCKVSokHPhhRc6S5cuDbyXfta61DbR42effbazaNGiwHtVrFjRicWOHTuclJQUZ8WKFWEfD9d3ZNWqVfZ+973liy++sK+1efNm+/uYMWOck08+2fn3338Dy6gPaZ3Holu3bk67du0iPh5NW2TDhg12Ofe4FQ23P0Tqk/LJJ5849erVs32lcuXKziOPPOL8999/gcefffZZp2bNmrZvlC9f3undu7ezd+/eVK+pffbMM890cubMad9X2/KJJ55wunfvbre39tdXXnkl4jHC3VYzZ8506tevb/e38847z/nll1+C2vvYY485JUuWtK+pvhZuv05vWzz++ONOmTJlnEqVKtn733rrLfuees3SpUvbvwfbt28Paqf3pteRo0ePOk8++aR9nXz58tnjw4cffhhVW0L7prsep02bZvdvHSNatWrlbNmyJVX73Z/D7Yeh2zwaGenrn3/+uZMjRw5n27Ztgfteeuklp3DhwkGv49Kxo1+/fjG1K62/GS+//LLTpk0b20+0vnRc/vXXX+2y6qvqO959Jb3j788//2xf69133w3c9/7779vtunLlynTbGM22keXLlzuXXnqpbYPact111zk7d+4M+qx9+/a166p48eL2eCnan9Rnjsfw4cPtPh7Ldu/UqZNdz16NGjVyevXqler1wx1forF79267jvTviajifZ+lugEAAABwEvrdIOZK4W3bttlLH+Wkk06y1cJy+eWXm6lTp8b6ckjDoUOH7L+65D3aKu5OnTrZS1lbt25tKyd1SX04CxYssFVLt912mx2P9MILLzSPP/540DIffPCBrXh68sknzQ8//GDKlCljxowZE7SMLsVXVdsTTzxhfv75Z7vsQw89ZCvevAYOHGjuuece+166DFpVU95LpKOl4QD02b766itbcaXq0SuuuMJegi09evSw7Vi0aFHgOVpO60SVsLG0WUN39OvXzy7TqlWrNNvVt29fW9Gn6tTly5ebp556yu4f4UyaNCmo4lWV4KeffropXbq0ffzqq682O3bsMF988YWtPDv77LPNRRddFNiW2q4aZ1qfUY+rnZH6iHsZfFqXTH/33Xf20vUzzzzTxGLevHm2qq9BgwaB+y6++GJbbaz+5S6jsYpV0enSuly9erX5559/Yno/fQZdXq911bt3b/PXX3/F1BY59dRT7XqeM2eOiRe9loZ4UV9ZtWqVrSpUtaf6l0vtUIWyqg3Vz77++mszYMCAoNdRZbb6zdixY+1y+qzuuOL6XOrHffr0sZ9d6y8t2t/0PO23qiLWfuFS/1fb9F7qP1onL730UkyfWfuf2uBWZbvV9I899pj56aef7Pjm6nuqzBZd6fDxxx/bn/U89XsNFSBDhw41b731lq3A1Oe+8847zXXXXWe++eYbkxFajxri6O2337b7o44NOvaEozacd9555uabbw7sj95hery0H6U1/EJG+rqeo7+n7r7vPkfVp1oXiabtpb6r47KGLdAwFb169TIPPPCA7TvKjvU3Itrjr15D6179VPf98ccf5tZbb7V97ayzzoqpbZG2jYYfadGihalXr55to8YK19A3+tvnpf1M2+L777+3fSscDU/h9tFo6f95vENlRbPdtYyOR15aRveH0rFcf0vSo2XUT7w3AAAAAIhJ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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "from sklearn.model_selection import GridSearchCV\n",
+ "\n",
+ "# Define hyperparameter grid\n",
+ "param_grid = {\n",
+ " 'hidden_layer_sizes': [(50,), (100,), (50, 100), (100, 50), (100, 50, 25, 10)],\n",
+ " 'learning_rate_init': [0.001, 0.01, 0.1],\n",
+ " 'max_iter': [200, 500, 1000]\n",
+ "}\n",
+ "\n",
+ "# Initialize the MLPRegressor\n",
+ "mlp = MLPRegressor(random_state=42)\n",
+ "\n",
+ "# Initialize GridSearchCV\n",
+ "grid_search = GridSearchCV(estimator=mlp, param_grid=param_grid, cv=3, scoring='r2', n_jobs=-1)\n",
+ "\n",
+ "# Fit GridSearchCV\n",
+ "grid_search.fit(X_train_scaled, y_train)\n",
+ "\n",
+ "# Get the best estimator\n",
+ "best_mlp = grid_search.best_estimator_\n",
+ "\n",
+ "# Fit the best estimator on the training data\n",
+ "best_mlp.fit(X_train_scaled, y_train)\n",
+ "\n",
+ "# Predict on the test data\n",
+ "y_pred_best_mlp = best_mlp.predict(X_test_scaled)\n",
+ "\n",
+ "# Calculate the MSE and R² score\n",
+ "mse_best_mlp = mean_squared_error(y_test, y_pred_best_mlp)\n",
+ "r2_best_mlp = r2_score(y_test, y_pred_best_mlp)\n",
+ "\n",
+ "print(f\"Optimized ANN Regression - MSE: {mse_best_mlp:.4f}, R² Score: {r2_best_mlp:.4f}\")\n",
+ "print(f\"Best Parameters: {grid_search.best_params_}\")\n",
+ "\n",
+ "# Extract four models from worst to best\n",
+ "results = grid_search.cv_results_\n",
+ "sorted_indices = np.argsort(results['mean_test_score'])\n",
+ "four_indices = [sorted_indices[0], sorted_indices[len(sorted_indices)//3], sorted_indices[2*len(sorted_indices)//3], sorted_indices[-1]]\n",
+ "\n",
+ "mse_values = -results['mean_test_score'][four_indices]\n",
+ "param_labels = [str(results['params'][i]) for i in four_indices]\n",
+ "\n",
+ "plt.figure(figsize=(10,6))\n",
+ "plt.barh(param_labels, mse_values)\n",
+ "plt.xlabel(\"Mean Squared Error\")\n",
+ "plt.ylabel(\"Hyperparameter Combinations\")\n",
+ "plt.title(\"Four ANN Regression Models from Worst to Best\")\n",
+ "plt.gca().invert_yaxis()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In the excercise above, i used the gridsearch to find the best combination of hyperparameters that minimizes the MSE value and optimizes the R2 score. In the above plot, the combination of hidden layer sizes: (100, 50), learning rate init of 0.01 and max iter of 200 initially yielded a good MSE value, however, the R2 score was still low. To improve this, i increased the number of hidden layers to four - (100, 50, 25, 10). This together 'learning_rate_init': 0.001, and 'max_iter': 500 increased the R2 score to an acceptable level. "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "che4230",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/notebooks/6.0_Test_annmodel.ipynb b/notebooks/6.0_Test_annmodel.ipynb
new file mode 100644
index 0000000..e494341
--- /dev/null
+++ b/notebooks/6.0_Test_annmodel.ipynb
@@ -0,0 +1,207 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'/Users/sanyao1/Library/CloudStorage/OneDrive-LouisianaStateUniversity(2)/lsu spring-25/CHE 4230/homeworks/Assignment 4/meter_Hw4'"
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "import os\n",
+ "\n",
+ "os.chdir(\"../\")\n",
+ "\n",
+ "os.getcwd()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from src.data_preprocess import DataPreprocessing"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " 0 1 2 3 4 5 6 \\\n",
+ "0 0.841499 1.009367 0.993816 8.469805 10.278727 10.037759 8.501365 \n",
+ "1 0.842250 1.006584 0.996605 7.531891 9.139924 8.951618 7.612213 \n",
+ "2 0.840723 1.011647 0.998152 6.641699 7.975464 7.857692 6.593117 \n",
+ "3 0.841119 1.017807 0.996812 5.687524 6.824334 6.689885 5.615428 \n",
+ "4 0.840358 1.016534 0.996221 5.660385 6.829560 6.675628 5.623977 \n",
+ "\n",
+ " 7 8 9 ... 27 28 29 \\\n",
+ "0 8.581726 10.247763 10.058822 ... 32.451173 34.568685 33.082683 \n",
+ "1 7.623325 9.106345 8.945142 ... 32.428385 34.441732 33.081055 \n",
+ "2 6.681572 7.964596 7.814698 ... 32.428385 34.275715 33.113605 \n",
+ "3 5.763315 6.801051 6.686639 ... 32.485350 34.080403 33.170573 \n",
+ "4 5.736818 6.813453 6.672377 ... 32.503255 34.122720 33.164062 \n",
+ "\n",
+ " 30 31 32 33 34 35 36 \n",
+ "0 36.722005 36.969403 36.075847 36.051432 35.174155 32.729490 1 \n",
+ "1 36.687825 36.933595 36.054688 35.979818 34.847005 32.731122 1 \n",
+ "2 36.661785 36.873370 36.002605 35.963542 34.689128 32.771810 1 \n",
+ "3 36.673177 36.811525 35.974935 35.955403 34.500328 32.849935 1 \n",
+ "4 36.673177 36.826173 35.996095 35.968425 34.474283 32.853190 1 \n",
+ "\n",
+ "[5 rows x 37 columns]\n"
+ ]
+ }
+ ],
+ "source": [
+ "preprocessor = DataPreprocessing()\n",
+ "\n",
+ "data = preprocessor.load_data(\"data/Meter_A.txt\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import train_test_split"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "train_validation, test = train_test_split(data, test_size = 0.2, random_state=12)\n",
+ "\n",
+ "train, validation = train_test_split(train_validation, test_size = 0.2, random_state=99)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn.preprocessing import StandardScaler"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Isolate the features and target variable of training dataset\n",
+ "X_train = train[:, :-1]\n",
+ "y_train = train[:, -1]\n",
+ "\n",
+ "X_val = validation[:, :-1]\n",
+ "y_val = validation[:, -1]\n",
+ "\n",
+ "# Standardize the features of training data\n",
+ "scaler = StandardScaler()\n",
+ "X_train_scaled = scaler.fit_transform(X_train)\n",
+ "X_val_scaled = scaler.transform(X_val)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from src.model_builder import annModel"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet.\n",
+ " warnings.warn(\n",
+ "/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet.\n",
+ " warnings.warn(\n",
+ "/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet.\n",
+ " warnings.warn(\n",
+ "/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet.\n",
+ " warnings.warn(\n",
+ "/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet.\n",
+ " warnings.warn(\n",
+ "/opt/anaconda3/envs/che4230/lib/python3.12/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet.\n",
+ " warnings.warn(\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Optimized ANN Regression - MSE: 0.0580, R² Score: 0.7633\n",
+ "Best Parameters: {'hidden_layer_sizes': (100, 50, 25, 10), 'learning_rate_init': 0.001, 'max_iter': 500}\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "0.7632979300279283"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model_builder = annModel()\n",
+ "\n",
+ "ann_model = model_builder.dt(X_train=X_train_scaled, X_test=X_val_scaled, y_train=train[:, -1], y_test = validation[:, -1])\n",
+ "\n",
+ "model_builder.mse_best_mlp\n",
+ "model_builder.r2_best_mlp"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "che4230",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/src/model_builder.py b/src/model_builder.py
index 8677c95..576fe4d 100644
--- a/src/model_builder.py
+++ b/src/model_builder.py
@@ -1,6 +1,9 @@
from sklearn.tree import DecisionTreeClassifier
import numpy as np
from sklearn.metrics import accuracy_score
+from sklearn.neural_network import MLPRegressor
+from sklearn.metrics import mean_squared_error, r2_score
+from sklearn.model_selection import GridSearchCV
# Importing the parent: DataPreprocessing class from data_preprocess.py
from src.data_preprocess import DataPreprocessing
@@ -29,4 +32,46 @@ def dt(self, X_train, X_test, y_train, y_test):
#get performance
self.accuracy = accuracy_score(y_test, DT_predicted)
- return DT_classifier
\ No newline at end of file
+ return DT_classifier
+
+class annModel(DataPreprocessing):
+ def __init__(self, *args, **kwargs):
+ super(annModel, self).__init__(*args, **kwargs)
+
+ def dt(self, X_train, X_test, y_train, y_test):
+ # Initialize the MLPRegressor
+ mlp = MLPRegressor(random_state=42)
+
+ # Define hyperparameter grid
+ param_grid = {
+ 'hidden_layer_sizes': [(50,), (100,), (50, 100), (100, 50), (100, 50, 25, 10)],
+ 'learning_rate_init': [0.001, 0.01, 0.1],
+ 'max_iter': [200, 500, 1000]
+ }
+ # Initialize GridSearchCV
+ grid_search = GridSearchCV(estimator=mlp, param_grid=param_grid, cv=3, scoring='r2', n_jobs=-1)
+
+ # Fit GridSearchCV
+ grid_search.fit(X_train, y_train)
+
+ # Get the best estimator
+ best_mlp = grid_search.best_estimator_
+
+ # Fit the best estimator on the training data
+ best_mlp.fit(X_train, y_train)
+
+ # Predict on the test data
+ y_pred_best_mlp = best_mlp.predict(X_test)
+
+ # Calculate the MSE and R² score
+ mse_best_mlp = mean_squared_error(y_test, y_pred_best_mlp)
+ r2_best_mlp = r2_score(y_test, y_pred_best_mlp)
+
+ print(f"Optimized ANN Regression - MSE: {mse_best_mlp:.4f}, R² Score: {r2_best_mlp:.4f}")
+ print(f"Best Parameters: {grid_search.best_params_}")
+
+ #get performance
+ self.mse_best_mlp = mean_squared_error(y_test, y_pred_best_mlp)
+ self.r2_best_mlp = r2_score(y_test, y_pred_best_mlp)
+
+ return mlp
\ No newline at end of file