Skip to content

Commit

Permalink
Resolved merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
om2007464 committed Jul 18, 2024
0 parents commit a27f4fb
Show file tree
Hide file tree
Showing 11 changed files with 930 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
33 changes: 33 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "Python 3",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/python:1-3.11-bullseye",
"customizations": {
"codespaces": {
"openFiles": [
"README.md",
"app/main.py"
]
},
"vscode": {
"settings": {},
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance"
]
}
},
"updateContentCommand": "[ -f packages.txt ] && sudo apt update && sudo apt upgrade -y && sudo xargs apt install -y <packages.txt; [ -f requirements.txt ] && pip3 install --user -r requirements.txt; pip3 install --user streamlit; echo '✅ Packages installed and Requirements met'",
"postAttachCommand": {
"server": "streamlit run app/main.py --server.enableCORS false --server.enableXsrfProtection false"
},
"portsAttributes": {
"8501": {
"label": "Application",
"onAutoForward": "openPreview"
}
},
"forwardPorts": [
8501
]
}
4 changes: 4 additions & 0 deletions .streamlit/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[theme]
base="light"
backgroundColor="#ffc0cb"
font="serif"
19 changes: 19 additions & 0 deletions CSS/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.css-j5r0tf {
padding: 1rem;
border-radius: 0.5rem;
background-color: #7E99AB;
}

.diagnosis {
color: #fff;
padding: 0.2em 0.5em;
border-radius: 0.5em;
}

.diagnosis.benign {
background-color: #01DB4B
}

.diagnosis.malicious {
background-color: #d30000
}
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Breast Cancer Predictor Using Machine Learning

Imagine a cutting-edge Breast Cancer Diagnosis app, crafted with powerful machine learning capabilities, tailored to support medical professionals in accurately diagnosing breast cancer. This innovative tool analyzes a comprehensive set of measurements to predict whether a breast mass is benign or malignant, transforming complex data into a clear, visual radar chart. It not only delivers a precise diagnosis but also presents the probability of the mass being benign or malignant, empowering healthcare providers with crucial insights.

Accessible and versatile, the app offers seamless integration with cytology labs, enabling automated data retrieval directly from lab machines for swift analysis. Please note, while the app seamlessly interfaces with lab equipment, the connection to the laboratory machine itself is managed independently. This ensures efficiency and accuracy in diagnosing breast cancer, revolutionizing medical diagnostics with advanced technology at its core.
## Tech Stack
`numpy`
`pandas`
`pickle`
`plotly`
`scikit_learn`
`streamlit`
`altair`
`streamlit`
## Installation

You can run this inside a virtual environment to make it easier to manage dependencies
`conda` to create a new environment and install the required packages

```bash
conda create -n breast-cancer-diagnosis python=3.10
```
Then, activate the environment:
```bash
conda activate breast-cancer-diagnosis
```
To install the required packages, run:

```bash
pip install -r requirements.txt
```
This will install all the necessary dependencies, including Streamlit

Datasets - https://www.kaggle.com/datasets/uciml/breast-cancer-wisconsin-data
## Usage

```bash
streamlit run app/main.py
```

193 changes: 193 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import streamlit as st
import pickle
import pandas as pd
import plotly.graph_objects as go
import numpy as np

# Function to load and clean the data
def get_clean_data():
data = pd.read_csv("data/data.csv") # Load data
data = data.drop(['Unnamed: 32', 'id'], axis=1) # Drop unnecessary columns
data['diagnosis'] = data['diagnosis'].map({'M': 1, 'B': 0}) # Map diagnosis to binary values
return data

# Function to add sidebar elements
def add_sidebar():
st.sidebar.header("Cell Nuclei Measurements") # Sidebar header

data = get_clean_data() # Get cleaned data

# Define slider labels and corresponding keys
slider_labels = [
("Radius (mean)", "radius_mean"),
("Texture (mean)", "texture_mean"),
("Perimeter (mean)", "perimeter_mean"),
("Area (mean)", "area_mean"),
("Smoothness (mean)", "smoothness_mean"),
("Compactness (mean)", "compactness_mean"),
("Concavity (mean)", "concavity_mean"),
("Concave points (mean)", "concave points_mean"),
("Symmetry (mean)", "symmetry_mean"),
("Fractal dimension (mean)", "fractal_dimension_mean"),
("Radius (se)", "radius_se"),
("Texture (se)", "texture_se"),
("Perimeter (se)", "perimeter_se"),
("Area (se)", "area_se"),
("Smoothness (se)", "smoothness_se"),
("Compactness (se)", "compactness_se"),
("Concavity (se)", "concavity_se"),
("Concave points (se)", "concave points_se"),
("Symmetry (se)", "symmetry_se"),
("Fractal dimension (se)", "fractal_dimension_se"),
("Radius (worst)", "radius_worst"),
("Texture (worst)", "texture_worst"),
("Perimeter (worst)", "perimeter_worst"),
("Area (worst)", "area_worst"),
("Smoothness (worst)", "smoothness_worst"),
("Compactness (worst)", "compactness_worst"),
("Concavity (worst)", "concavity_worst"),
("Concave points (worst)", "concave points_worst"),
("Symmetry (worst)", "symmetry_worst"),
("Fractal dimension (worst)", "fractal_dimension_worst"),
]

input_dict = {} # Dictionary to store slider values

# Add sliders to the sidebar
for label, key in slider_labels:
input_dict[key] = st.sidebar.slider(
label,
min_value=float(0),
max_value=float(data[key].max()),
value=float(data[key].mean())
)

return input_dict

# Function to scale the input values
def get_scaled_values(input_dict):
data = get_clean_data() # Get cleaned data
X = data.drop(['diagnosis'], axis=1) # Drop the target variable

scaled_dict = {} # Dictionary to store scaled values

# Scale each input value
for key, value in input_dict.items():
max_val = X[key].max()
min_val = X[key].min()
scaled_value = (value - min_val) / (max_val - min_val)
scaled_dict[key] = scaled_value

return scaled_dict

# Function to create a radar chart
def get_radar_chart(input_data):
input_data = get_scaled_values(input_data) # Scale input data

# Define categories for radar chart
categories = ['Radius', 'Texture', 'Perimeter', 'Area',
'Smoothness', 'Compactness',
'Concavity', 'Concave Points',
'Symmetry', 'Fractal Dimension']

fig = go.Figure()

# Add traces for mean, standard error, and worst values
fig.add_trace(go.Scatterpolar(
r=[
input_data['radius_mean'], input_data['texture_mean'], input_data['perimeter_mean'],
input_data['area_mean'], input_data['smoothness_mean'], input_data['compactness_mean'],
input_data['concavity_mean'], input_data['concave points_mean'], input_data['symmetry_mean'],
input_data['fractal_dimension_mean']
],
theta=categories,
fill='toself',
name='Mean Value'
))
fig.add_trace(go.Scatterpolar(
r=[
input_data['radius_se'], input_data['texture_se'], input_data['perimeter_se'], input_data['area_se'],
input_data['smoothness_se'], input_data['compactness_se'], input_data['concavity_se'],
input_data['concave points_se'], input_data['symmetry_se'], input_data['fractal_dimension_se']
],
theta=categories,
fill='toself',
name='Standard Error'
))
fig.add_trace(go.Scatterpolar(
r=[
input_data['radius_worst'], input_data['texture_worst'], input_data['perimeter_worst'],
input_data['area_worst'], input_data['smoothness_worst'], input_data['compactness_worst'],
input_data['concavity_worst'], input_data['concave points_worst'], input_data['symmetry_worst'],
input_data['fractal_dimension_worst']
],
theta=categories,
fill='toself',
name='Worst Value'
))

fig.update_layout(
polar=dict(
radialaxis=dict(
visible=True,
range=[0, 1]
)),
showlegend=True
)

return fig

# Function to add prediction results
def add_predictions(input_data):
model = pickle.load(open("model/model.pkl", "rb")) # Load model
scaler = pickle.load(open("model/scaler.pkl", "rb")) # Load scaler

input_array = np.array(list(input_data.values())).reshape(1, -1) # Convert input to array

input_array_scaled = scaler.transform(input_array) # Scale input array

prediction = model.predict(input_array_scaled) # Predict diagnosis

st.subheader("Cell cluster prediction")
st.write("The cell cluster is:")

# Display prediction result
if prediction[0] == 0:
st.write("<span class='diagnosis benign'>Benign</span>", unsafe_allow_html=True)
else:
st.write("<span class='diagnosis malicious'>Malicious</span>", unsafe_allow_html=True)

# Display prediction probabilities
st.write("Probability of being benign: ", model.predict_proba(input_array_scaled)[0][0])
st.write("Probability of being malicious: ", model.predict_proba(input_array_scaled)[0][1])

st.write("This app can assist medical professionals in making a diagnosis, but should not be used as a substitute for a professional diagnosis.")

# Main function to run the app
def main():
st.set_page_config(
page_title="Breast Cancer Predictor",
page_icon=":female-doctor:",
layout="wide",
initial_sidebar_state="expanded"
)

with open("CSS/style.css") as f:
st.markdown("<style>{}</style>".format(f.read()), unsafe_allow_html=True)

input_data = add_sidebar() # Get input data from sidebar

with st.container():
st.title("Breast Cancer Predictor")
st.write("This app determines whether a breast mass is benign or malignant based on measurements received from your cytology lab. You can also manually adjust these measurements using the sliders in the sidebar.")

col1, col2 = st.columns([4, 1])

with col1:
radar_chart = get_radar_chart(input_data) # Generate radar chart
st.plotly_chart(radar_chart)
with col2:
add_predictions(input_data) # Add prediction results

if __name__ == '__main__':
main()
Loading

0 comments on commit a27f4fb

Please sign in to comment.