diff --git a/App.py b/App.py
index c55aeb24..3eb3eb1a 100644
--- a/App.py
+++ b/App.py
@@ -3,153 +3,223 @@
st.set_page_config(page_title="Predictive Calc - Machine Learning Models", page_icon="🤖")
st.title("Welcome to Predictive Calc!")
-st.image('machine-learning.gif', caption='Your Hub for Predictive Insights', use_column_width=True)
st.markdown("""
-## Explore Cutting-edge Machine Learning Models
+## Explore Cutting-Edge Machine Learning Models
**Predictive Calc** offers a powerful suite of machine learning models designed to assist you in making informed decisions. Whether it's predicting house prices, determining loan eligibility, or evaluating health risks, we have you covered.
""")
+# Why Choose Calc?
st.markdown("""
-## Why Choose Predictive Calc?
-- **Accurate Predictions**: Leverage state-of-the-art algorithms for highly accurate predictions.
-- **User-friendly Interface**: Seamlessly interact with models tailored for real-world applications.
-- **Comprehensive Calculators**: A collection of models designed for diverse decision-making needs.
-- **Health & Financial Models**: Predict house prices, assess loan eligibility, and evaluate health risks such as Parkinson's and stress levels.
-""")
-
-st.markdown("""
----
-**Ready to get started?** Select a calculator from the sidebar to begin your predictive journey!
-""")
+## Why Choose Predictive Calc? """)
+features = [
+ {
+ "title": "Accurate Predictions",
+ "icon": "🔍",
+ "description": "Harness cutting-edge machine learning algorithms that provide reliable and precise predictions."
+ },
+ {
+ "title": "User-Friendly Interface",
+ "icon": "💻",
+ "description": "Enjoy a seamless, intuitive experience with models designed for practical applications across various domains."
+ },
+ {
+ "title": "Comprehensive Calculators",
+ "icon": "📊",
+ "description": "Access a diverse set of models for financial analysis, health assessments, security checks, and more, all in one place."
+ },
+ {
+ "title": "Health & Financial Insights",
+ "icon": "🏥💰",
+ "description": "From estimating house prices and checking loan eligibility to evaluating health risks like Parkinson’s and stress levels, Predictive Calc offers essential tools for everyday decision-making."
+ },
+ {
+ "title": "Enhanced Document Analysis & Language Tools",
+ "icon": "📄🌐",
+ "description": "With a built-in text summarizer and translator, streamline your reading experience and break language barriers effortlessly. PDF Malware Detection also helps keep your documents safe."
+ }
+]
+
+# Display features in a structured card format
+for feature in features:
+ st.markdown(
+ f"""
+
+
{feature["icon"]}
+
+
{feature["title"]}
+
{feature["description"]}
+
+
+ """,
+ unsafe_allow_html=True
+ )
st.markdown("---")
-
-# List of available calculators
-st.subheader("Available Calculators:")
-st.write(
- "- **Customer Income Estimation**: Estimate the annual income of a person based on socio-economic and demographic information."
-)
-st.write(
- "- **House Price Prediction**: Estimate the price of a house based on various features."
-)
-st.write("- **Loan Eligibility**: Check your eligibility for different types of loans.")
-st.write(
- "- **Stress Level Detector**: Analyze your mental stress levels based on social media interactions."
-)
-st.write(
- "- **Parkinson's Disease Detector**: Assess your risk of Parkinson's Disease with advanced machine learning algorithms."
-)
-st.write(
- "- **Insurance Cost Predictor**: Estimate your insurance costs based on personal factors like age, BMI, smoker status, and more using machine learning algorithms."
-)
-
-# Parkinson's Disease Detector Section
-with st.expander("Parkinson's Disease Detector - More Information"):
- st.subheader("Introduction")
- st.write(
- """
- Parkinson's disease (PD) is a progressive neurodegenerative disorder that primarily affects movement. It often starts with subtle symptoms such as tremors, stiffness, and slow movement.
- """
- )
-
- # Dataset section
- st.subheader("Oxford Parkinson's Disease Detection Dataset (UCI ML Repository)")
- st.write(
- """
- The dataset contains biomedical voice measurements from 31 people, 23 of whom have Parkinson's disease (PD). The main goal is to differentiate between healthy individuals and those with PD using the "status" column, where 0 indicates healthy and 1 indicates PD.
- """
- )
-
- # Input features section
- st.subheader("Additional Variable Information")
- st.write(
- """
- - **MDVP_Fo(Hz)**: Average vocal fundamental frequency.
- - **MDVP_Fhi(Hz)**: Maximum vocal fundamental frequency.
- - **MDVP_Flo(Hz)**: Minimum vocal fundamental frequency.
- - **MDVP_Jitter(%)**, **MDVP_Jitter(Abs)**, **MDVP_RAP**, **MDVP_PPQ**, **Jitter_DDP**: Measures of variation in fundamental frequency.
- - **MDVP_Shimmer**, **MDVP_Shimmer(dB)**, **Shimmer_APQ3**, **Shimmer_APQ5**, **MDVP_APQ**, **Shimmer_DDA**: Measures of variation in amplitude.
- - **NHR**, **HNR**: Noise-to-tonal ratio measures in the voice.
- - **status**: Health status of the subject (1 - Parkinson's, 0 - healthy).
- - **RPDE**, **D2**: Nonlinear dynamical complexity measures.
- - **DFA**: Signal fractal scaling exponent.
- - **spread1**, **spread2**, **PPE**: Nonlinear measures of fundamental frequency variation.
- """
- )
-
-st.write(
- "- **Gold Price Predictor**: Predict future gold prices leverages financial metrics and machine learning algorithm."
-)
-
-# Gold Price Predictor Section
-with st.expander("Gold Price Predictor - More Information"):
- st.subheader("Introduction")
- st.write(
- """
- The Gold Price Predictor leverages financial metrics and machine learning algorithms to forecast the price of gold (GLD). Gold prices are influenced by various economic factors, and this tool aims to provide accurate predictions based on historical data.
- """
- )
-
- # Dataset section
- st.subheader("Gold Price Dataset")
- st.write(
- """
- The dataset used for this model contains daily financial data, including stock market indices, commodity prices, and currency exchange rates. The goal is to predict the gold price (GLD) using features such as the S&P 500 Index (SPX), crude oil price (USO), silver price (SLV), and the EUR/USD exchange rate.
- """
- )
-
- # Input features section
- st.subheader("Additional Variable Information")
- st.write(
- """
- - **SPX**: The S&P 500 index value, which tracks the performance of 500 large companies listed on stock exchanges in the United States.
- - **USO**: The price of United States Oil Fund (USO), which reflects crude oil prices.
- - **SLV**: The price of iShares Silver Trust (SLV), which reflects silver prices.
- - **EUR/USD**: The Euro-to-U.S. Dollar exchange rate, which indicates the strength of the euro relative to the U.S. dollar.
- - **GLD**: The price of SPDR Gold Shares (GLD), which is the target variable representing gold prices.
- """
- )
-
-#Insurance Cost Predictor
-with st.expander("Insurance Cost Predictor - More Information"):
- st.subheader("Introduction")
- st.write(
+st.markdown("## Available Calculators")
+
+# Calculator information in a structured format
+calculators = [
+ {
+ "name": "Income Estimator",
+ "description": "Estimate the annual income based on socio-economic and demographic information.",
+ "details": """
+ This calculator uses demographic and socio-economic variables to predict income level, providing insights into income patterns.
"""
- The Insurance Cost Predictor leverages personal metrics and machine learning algorithms to predict insurance costs. This tool aims to provide accurate predictions based on user inputs like age, BMI, smoker status, and region.
+ },
+ {
+ "name": "Gold Price Predictor",
+ "description": "Predict future gold prices using various financial metrics.",
+ "details": """
+ ### Introduction
+ The Gold Price Predictor leverages financial metrics and machine learning algorithms to forecast the price of gold (GLD). Gold prices are influenced by various economic factors, and this tool aims to provide accurate predictions based on historical data.
+
+ ### Gold Price Dataset
+ The dataset used for this model contains daily financial data, including stock market indices, commodity prices, and currency exchange rates. The goal is to predict the gold price (GLD) using features such as the S&P 500 Index (SPX), crude oil price (USO), silver price (SLV), and the EUR/USD exchange rate.
+
+ ### Additional Variable Information
+ - **SPX**: The S&P 500 index value, which tracks the performance of 500 large companies listed on stock exchanges in the United States.
+ - **USO**: The price of United States Oil Fund (USO), which reflects crude oil prices.
+ - **SLV**: The price of iShares Silver Trust (SLV), which reflects silver prices.
+ - **EUR/USD**: The Euro-to-U.S. Dollar exchange rate, which indicates the strength of the euro relative to the U.S. dollar.
+ - **GLD**: The price of SPDR Gold Shares (GLD), which is the target variable representing gold prices.
"""
- )
-
- # Dataset section
- st.subheader("Insurance Dataset")
- st.write(
+ },
+ {
+ "name": "House Price Estimator",
+ "description": "Predict the price of a house based on various features.",
+ "details": """
+ Using historical and current market data, this tool predicts the house price based on features like location, size, and amenities.
"""
- The dataset used for this model contains data on individuals' personal factors, including age, sex, BMI, number of children, smoking status, and region. The goal is to predict the insurance cost (charges) based on these features.
+ },
+ {
+ "name": "Loan Eligibility",
+ "description": "Check your eligibility for various types of loans based on your financial profile.",
+ "details": """
+ This calculator assesses loan eligibility by analyzing credit scores, income, and other relevant financial details.
"""
- )
-
- # Input features section
- st.subheader("Additional Variable Information")
- st.write(
+ },
+ {
+ "name": "Parkinson's Disease",
+ "description": "Assess your risk of Parkinson's Disease with advanced ML algorithms.",
+ "details": """
+ ### Introduction
+ Parkinson's disease (PD) is a progressive neurodegenerative disorder that primarily affects movement. It often starts with subtle symptoms such as tremors, stiffness, and slow movement.
+
+ ### Oxford Parkinson's Disease Detection Dataset (UCI ML Repository)
+ The dataset contains biomedical voice measurements from 31 people, 23 of whom have Parkinson's disease (PD). The main goal is to differentiate between healthy individuals and those with PD using the "status" column, where 0 indicates healthy and 1 indicates PD.
+
+ ### Additional Variable Information
+ - **MDVP_Fo(Hz)**: Average vocal fundamental frequency.
+ - **MDVP_Fhi(Hz)**: Maximum vocal fundamental frequency.
+ - **MDVP_Flo(Hz)**: Minimum vocal fundamental frequency.
+ - **MDVP_Jitter(%)**, **MDVP_Jitter(Abs)**, **MDVP_RAP**, **MDVP_PPQ**, **Jitter_DDP**: Measures of variation in fundamental frequency.
+ - **MDVP_Shimmer**, **MDVP_Shimmer(dB)**, **Shimmer_APQ3**, **Shimmer_APQ5**, **MDVP_APQ**, **Shimmer_DDA**: Measures of variation in amplitude.
+ - **NHR**, **HNR**: Noise-to-tonal ratio measures in the voice.
+ - **status**: Health status of the subject (1 - Parkinson's, 0 - healthy).
+ - **RPDE**, **D2**: Nonlinear dynamical complexity measures.
+ - **DFA**: Signal fractal scaling exponent.
+ - **spread1**, **spread2**, **PPE**: Nonlinear measures of fundamental frequency variation.
"""
- - **Age**: The age of the individual.
- - **Sex**: The sex of the individual (Male or Female).
- - **BMI**: Body Mass Index (BMI), a measure of body fat based on height and weight.
- - **Children**: The number of children the individual has.
- - **Smoker**: Whether the individual is a smoker (Yes or No).
- - **Region**: The geographical region (Southeast, Southwest, Northeast, or Northwest).
- - **Charges**: The insurance cost (the target variable to be predicted).
+ },
+ {
+ "name": "PDF Malware Detector",
+ "description": "Identify and alert users about potential malware in PDF files.",
+ "details": """
+ ### Overview
+ The PDF Malware Detector scans uploaded PDF files for malicious content, ensuring user safety and data protection.
+
+ ### Key Features
+ - **File Upload**: Simple drag-and-drop interface for easy file submission.
+ - **Malware Detection**: Comprehensive analysis to detect harmful elements within PDFs.
+ - **File Size Limit**: Supports files up to 200MB.
+
+ ### Use Cases
+ Perfect for users needing to verify the integrity of PDF documents before opening or sharing.
"""
- )
-#Text Summarization Section
-
-st.write(
- "- *Text Summarizer*: Save time with concise, professional summaries of lengthy texts—tailored to meet your needs and streamline your reading experience."
-)
-with st.expander("Text Summarizer - More Information"):
- st.subheader("Introduction")
- st.write(
- """
- Many struggle with summarizing large texts or learning from lengthy materials. This model simplifies the process, offering concise summaries that enhance understanding and speed up learning—perfect for students and professionals alike.
- """
- )
+ },
+ {
+ "name": "Stress Level Detector",
+ "description": "Analyze your mental stress levels based on social media interactions.",
+ "details": """
+ The model uses text analysis on social media data to identify signs of stress, helping users understand their mental health patterns.
+ """
+ },
+ {
+ "name": "Text Summarizer",
+ "description": "Save time with concise, professional summaries of lengthy texts.",
+ "details": """
+ Generate quick and comprehensive summaries of lengthy documents, ideal for students, researchers, and professionals.
+ """
+ },
+ {
+ "name": "Real-Time Language Translator",
+ "description": "Translate spoken language into other languages instantly for seamless communication.",
+ "details": """
+ ### Overview
+ The Real-Time Language Translator uses advanced speech recognition and NLP to provide immediate translations between languages, enhancing communication in diverse settings.
+
+ ### Key Features
+ - **Instant Translation**: Real-time spoken language translation.
+ - **Multiple Languages**: Supports a variety of source and target languages.
+ - **User-Friendly Interface**: Easy to navigate for all users.
+
+ ### Use Cases
+ Ideal for travel, business meetings, and language learning, breaking down language barriers effortlessly.
+ """
+ },
+]
+
+# Define shades of blue for calculators
+blue_shades = [
+ "#D1E8E2", # Light Blue
+ "#A0D6E0", # Soft Blue
+ "#7FB3E8", # Sky Blue
+]
+
+# Display calculators in a table layout with two columns per row
+for i in range(0, len(calculators), 2):
+ cols = st.columns(2)
+ for j, col in enumerate(cols):
+ if i + j < len(calculators):
+ calc = calculators[i + j]
+ # Use modulo to cycle through the blue shades
+ color_index = (i + j) % len(blue_shades)
+ color = blue_shades[color_index]
+ with col:
+ # Styled container for heading and description with different blue shades
+ st.markdown(
+ f"""
+
+
{calc['name']}
+
{calc['description']}
+
+ """,
+ unsafe_allow_html=True
+ )
+ # More Info expander
+ with st.expander("More Info"):
+ st.write(calc["details"])
+ st.markdown("---")
+
+# Add a "Get Started" section at the bottom
+st.markdown("## Get Started Today!")
+st.markdown("Explore our calculators and take control of your predictive analytics journey!")
+
+
+st.write("Developed with ❤️ by Yashasvini Sharma | [Github](https://www.github.com/yashasvini121) | [LinkedIn](https://www.linkedin.com/in/yashasvini121/)")
+
diff --git a/assets/images/machine_learning.png b/assets/images/machine_learning.png
new file mode 100644
index 00000000..e0a8d302
Binary files /dev/null and b/assets/images/machine_learning.png differ
diff --git a/models/house_price/ImprovedModel.py b/models/house_price/ImprovedModel.py
new file mode 100644
index 00000000..5f0df513
--- /dev/null
+++ b/models/house_price/ImprovedModel.py
@@ -0,0 +1,196 @@
+import pandas as pd
+from sklearn.model_selection import train_test_split, cross_val_score
+from sklearn.preprocessing import StandardScaler, OneHotEncoder
+from sklearn.compose import ColumnTransformer
+from sklearn.pipeline import Pipeline
+from sklearn.feature_selection import RFE
+from sklearn.linear_model import LinearRegression
+from sklearn.ensemble import RandomForestRegressor
+import warnings
+import pickle
+from .ModelEvaluation import ModelEvaluation
+import os
+import logging
+import streamlit as st
+import numpy as np
+warnings.filterwarnings("ignore")
+
+# Define the directory for logs
+log_directory = 'models/house_price/logs'
+os.makedirs(log_directory, exist_ok=True) # Create the directory if it doesn't exist
+
+# Set up logging
+log_file = os.path.join(log_directory, 'model_training.log')
+logging.basicConfig(
+ filename=log_file,
+ level=logging.INFO,
+ format='%(asctime)s - %(levelname)s - %(message)s'
+)
+
+df = pd.read_csv("models/house_price/data/housing.csv")
+original_df = df.copy(deep=True)
+
+# Target and Feature Identification
+target = "price"
+features = [col for col in df.columns if col != target]
+
+# Separates numerical and categorical features based on unique values
+nu = df[features].nunique()
+numerical_features = [col for col in features if nu[col] > 16]
+categorical_features = [col for col in features if nu[col] <= 16]
+
+# Removing outliers using IQR
+def remove_outliers(df, numerical_features):
+ for feature in numerical_features:
+ Q1 = df[feature].quantile(0.25)
+ Q3 = df[feature].quantile(0.75)
+ IQR = Q3 - Q1
+ df = df[(df[feature] >= (Q1 - 1.5 * IQR)) & (df[feature] <= (Q3 + 1.5 * IQR))]
+ return df.reset_index(drop=True)
+
+
+# Handling missing values
+def handle_missing_values(df):
+ null_summary = df.isnull().sum()
+ null_percentage = (null_summary / df.shape[0]) * 100
+ return pd.DataFrame(
+ {"Total Null Values": null_summary, "Percentage": null_percentage}
+ ).sort_values(by="Percentage", ascending=False)
+
+
+# Removes outliers from numerical features
+df = remove_outliers(df, numerical_features)
+
+# Filters categorical features without missing values
+null_value_summary = handle_missing_values(df)
+valid_categorical_features = [
+ col
+ for col in categorical_features
+ if col not in null_value_summary[null_value_summary["Percentage"] != 0].index
+]
+
+# Encoding categorical features
+def encode_categorical_features(df, categorical_features):
+ for feature in categorical_features:
+ # Binary encoding for features with 2 unique values
+ if df[feature].nunique() == 2:
+ df[feature] = pd.get_dummies(df[feature], drop_first=True, prefix=feature)
+ # Dummy encoding for features with more than 2 unique values
+ elif 2 < df[feature].nunique() <= 16:
+ df = pd.concat(
+ [
+ df.drop([feature], axis=1),
+ pd.get_dummies(df[feature], drop_first=True, prefix=feature),
+ ],
+ axis=1,
+ )
+ return df
+
+df = encode_categorical_features(df, valid_categorical_features)
+
+# Renames columns to avoid invalid characters
+df.columns = [col.replace("-", "_").replace(" ", "_") for col in df.columns]
+
+# Splitting the data into training & testing sets
+X = df.drop([target], axis=1)
+Y = df[target]
+Train_X, Test_X, Train_Y, Test_Y = train_test_split(
+ X, Y, train_size=0.8, test_size=0.2, random_state=100
+)
+
+# Feature Scaling (Standardization)
+std = StandardScaler()
+Train_X_std = pd.DataFrame(std.fit_transform(Train_X), columns=X.columns)
+Test_X_std = pd.DataFrame(std.transform(Test_X), columns=X.columns)
+
+#Random Forest Algorithm
+rf_model = RandomForestRegressor(random_state=42, n_estimators=200, max_depth=8, min_samples_split=12)
+rf_model.fit(Train_X_std, Train_Y)
+
+
+pred_train = rf_model.predict(Train_X_std)
+pred_test = rf_model.predict(Test_X_std)
+
+# Calculate RMSE for train and test sets
+# train_rmse = np.sqrt(mean_squared_error(Train_Y, pred_train))
+# test_rmse = np.sqrt(mean_squared_error(Test_Y, pred_test))
+
+
+def prepare_input_data(
+ area,
+ mainroad,
+ guestroom,
+ basement,
+ hotwaterheating,
+ airconditioning,
+ prefarea,
+ additional_bedrooms,
+ bathrooms,
+ stories,
+ parking,
+ furnishingstatus,
+):
+ # Creates a dictionary for the input features
+ input_data = {
+ "area": [area],
+ "mainroad": True if mainroad == "Yes" else False,
+ "guestroom": True if guestroom == "Yes" else False,
+ "basement": True if basement == "Yes" else False,
+ "hotwaterheating": True if hotwaterheating == "Yes" else False,
+ "airconditioning": True if airconditioning == "Yes" else False,
+ "prefarea": True if prefarea == "Yes" else False,
+ "bedrooms_2": additional_bedrooms == 2,
+ "bedrooms_3": additional_bedrooms == 3,
+ "bedrooms_4": additional_bedrooms == 4,
+ "bedrooms_5": additional_bedrooms == 5,
+ "bedrooms_6": additional_bedrooms == 6,
+ "bathrooms_2": bathrooms == 2,
+ "bathrooms_3": bathrooms == 3,
+ "bathrooms_4": bathrooms == 4,
+ "stories_2": stories == 2,
+ "stories_3": stories == 3,
+ "stories_4": stories == 4,
+ "parking_1": parking == 1,
+ "parking_2": parking == 2,
+ "parking_3": parking == 3,
+ "furnishingstatus_semi_furnished": furnishingstatus == "semi_furnished",
+ "furnishingstatus_unfurnished": furnishingstatus == "unfurnished",
+ }
+
+ return pd.DataFrame(input_data)
+
+# Note: Not removing this fxn because of the warning in predict.py file
+
+
+### Final Endpoint ###
+def get_predicted(area=0, mainroad=False, guestroom=False, basement=False, hotwaterheating=False,
+ airconditioning=False, prefarea=False,bedrooms=0, bathrooms=2,stories=1, parking=1,
+ furnishingstatus="semi_furnished",):
+
+ input_df = prepare_input_data(area, mainroad, guestroom,basement, hotwaterheating, airconditioning, prefarea,
+ bedrooms, bathrooms, stories, parking, furnishingstatus)
+
+ input_std = pd.DataFrame(std.transform(input_df), columns=input_df.columns)
+ predicted_price = rf_model.predict(input_std)
+ return round(predicted_price[0],2)
+
+def save_model():
+ # todo: Ask the user for the model name, and warn that the model will be overwritten
+
+ with open("./saved_models/model_02.pkl", "wb") as file:
+ pickle.dump(rf_model, file)
+
+
+def save_scaler():
+ with open("./saved_models/scaler_02.pkl", "wb") as file:
+ pickle.dump(std, file)
+
+
+def get_evaluator():
+ evaluator = ModelEvaluation(rf_model, Train_X_std, Train_Y, Test_X_std, Test_Y)
+ return evaluator
+
+if __name__ == "__main__":
+ save_model()
+ save_scaler()
+ # model_evaluation()
diff --git a/models/house_price/predict.py b/models/house_price/predict.py
index db5544fc..50b58685 100644
--- a/models/house_price/predict.py
+++ b/models/house_price/predict.py
@@ -1,6 +1,7 @@
import pickle
import pandas as pd
-from models.house_price.model import get_evaluator
+# from models.house_price.model import get_evaluator
+from models.house_price.ImprovedModel import get_evaluator
"""
Predict.py file:
@@ -102,8 +103,8 @@ def get_prediction(
)
# Load the model and the scaler
- model = load_model("models/house_price/saved_models/model_01.pkl")
- scaler = load_model("models/house_price/saved_models/scaler_01.pkl")
+ model = load_model("models/house_price/saved_models/model_02.pkl")
+ scaler = load_model("models/house_price/saved_models/scaler_02.pkl")
# Scale the input data
input_scaled = scaler.transform(input_df)
diff --git a/models/house_price/saved_models/model_02.pkl b/models/house_price/saved_models/model_02.pkl
new file mode 100644
index 00000000..7e0aa358
Binary files /dev/null and b/models/house_price/saved_models/model_02.pkl differ
diff --git a/models/house_price/saved_models/scaler_02.pkl b/models/house_price/saved_models/scaler_02.pkl
new file mode 100644
index 00000000..ce74f356
Binary files /dev/null and b/models/house_price/saved_models/scaler_02.pkl differ
diff --git a/page_handler.py b/page_handler.py
index 56c72b11..75836c50 100644
--- a/page_handler.py
+++ b/page_handler.py
@@ -78,7 +78,7 @@ def render_model_details(self, model_module,tab):
if model_details_function:
metrics, prediction_plot, error_plot, performance_plot = model_details_function().evaluate()
- st.subheader(f"Model Accuracy: {metrics['Test_R2']:.2%}")
+ st.subheader(f"Model Accuracy: {metrics['Test_R2']:.2f}")
#mentioning the title of the scores
st.subheader(f"Scores: Training: {metrics['Train_R2']:.2f}, Testing: {metrics['Test_R2']:.2f}")
diff --git a/readme.md b/readme.md
index 6c474386..d4f52a3d 100644
--- a/readme.md
+++ b/readme.md
@@ -13,7 +13,7 @@ The project has been successfully tested in local environments, and current effo
2. Or create new issues to discuss new ideas, suggest features, or report bugs.
3. Fork the repository and create a new branch for your contribution.
4. Implement your changes and submit a pull request with a clear description.
-5. Futher details can be found in the [contributing.md](contributing.md) file.
+5. Further details can be found in the [contributing.md](contributing.md) file.
## Setup Instructions
1. Fork or clone the repository.