Ссылка на репозиторий github — https://github.com/priya-nath/Breast_Cancer_Prediction_Using_ML_Classification

Источник изображения — https://images.app.goo.gl/6vpi6R2tszq3NJUS7

Согласно статистике, около 12–13% женщин во всем мире страдают от рака молочной железы, и со временем этот показатель увеличивается. Пациент может даже умереть, если вовремя не поставить диагноз и не принять надлежащие лекарства. Врачи могут определить только на 70–80% точно, что может представлять серьезную угрозу для невыявленных пациенток, страдающих раком молочной железы. Используя машинное обучение, его можно диагностировать с точностью более 95%.

Цель проекта

Проект направлен на создание классификатора машинного обучения, который с использованием заданных параметров из набора данных предсказывает, является ли клетка злокачественной (раковой) или доброкачественной (не раковой).

Импорт различных библиотек Python

In [1]:

import io
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
/usr/local/lib/python3.6/dist-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
  import pandas.util.testing as tm

In [2]:

from google.colab import files
uploaded = files.upload()
Saving Breast_cancer_Data.csv to Breast_cancer_Data.csv

Чтение набора данных

Набор данных взят с kaggle (https://www.kaggle.com/uciml/breast-cancer-wisconsin-data).

In [3]:

df = pd.read_csv(io.BytesIO(uploaded['Breast_cancer_Data.csv']))

Описание набора данных

Набор данных содержит 569 строк и 32 столбца. Некоторые столбцы описаны ниже.

id — этот номер идентификатора. назначается каждому пациенту и является уникальным.

диагностика — это будет наша целевая переменная, «M» означает злокачественную опухоль (раковую), а «B» означает доброкачественную опухоль (нераковую).

радиус — Расстояние от центра до периметра ячейки

текстура — Стандартное отклонение значений шкалы серого

perimeter_mean — Среднее значение периметра

area_mean — Среднее значение площади ячейки

гладкость — Локальное изменение в длинах радиуса

concavity — Серьезность вогнутых узоров на контуре

симметрия

fractal_dimension

Среднее значение, стандартная ошибка и наихудшие признаки были рассчитаны для каждого изображения, в результате чего было получено 30 признаков.

In [4]:

df.head()

Выход[4]:

In [5]:

df.columns

Выход[5]:

Index(['id', 'diagnosis', 'radius_mean', 'texture_mean', 'perimeter_mean',
       'area_mean', 'smoothness_mean', 'compactness_mean', 'concavity_mean',
       'concave points_mean', 'symmetry_mean', 'fractal_dimension_mean',
       'radius_se', 'texture_se', 'perimeter_se', 'area_se', 'smoothness_se',
       'compactness_se', 'concavity_se', 'concave points_se', 'symmetry_se',
       'fractal_dimension_se', 'radius_worst', 'texture_worst',
       'perimeter_worst', 'area_worst', 'smoothness_worst',
       'compactness_worst', 'concavity_worst', 'concave points_worst',
       'symmetry_worst', 'fractal_dimension_worst', 'Unnamed: 32'],
      dtype='object')

In [6]:

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 569 entries, 0 to 568
Data columns (total 33 columns):
 #   Column                   Non-Null Count  Dtype  
---  ------                   --------------  -----  
 0   id                       569 non-null    int64  
 1   diagnosis                569 non-null    object 
 2   radius_mean              569 non-null    float64
 3   texture_mean             569 non-null    float64
 4   perimeter_mean           569 non-null    float64
 5   area_mean                569 non-null    float64
 6   smoothness_mean          569 non-null    float64
 7   compactness_mean         569 non-null    float64
 8   concavity_mean           569 non-null    float64
 9   concave points_mean      569 non-null    float64
 10  symmetry_mean            569 non-null    float64
 11  fractal_dimension_mean   569 non-null    float64
 12  radius_se                569 non-null    float64
 13  texture_se               569 non-null    float64
 14  perimeter_se             569 non-null    float64
 15  area_se                  569 non-null    float64
 16  smoothness_se            569 non-null    float64
 17  compactness_se           569 non-null    float64
 18  concavity_se             569 non-null    float64
 19  concave points_se        569 non-null    float64
 20  symmetry_se              569 non-null    float64
 21  fractal_dimension_se     569 non-null    float64
 22  radius_worst             569 non-null    float64
 23  texture_worst            569 non-null    float64
 24  perimeter_worst          569 non-null    float64
 25  area_worst               569 non-null    float64
 26  smoothness_worst         569 non-null    float64
 27  compactness_worst        569 non-null    float64
 28  concavity_worst          569 non-null    float64
 29  concave points_worst     569 non-null    float64
 30  symmetry_worst           569 non-null    float64
 31  fractal_dimension_worst  569 non-null    float64
 32  Unnamed: 32              0 non-null      float64
dtypes: float64(31), int64(1), object(1)
memory usage: 146.8+ KB

In [7]:

df.describe()

Выход[7]:

In [8]:

df.isnull().sum()

Выход[8]:

id                           0
diagnosis                    0
radius_mean                  0
texture_mean                 0
perimeter_mean               0
area_mean                    0
smoothness_mean              0
compactness_mean             0
concavity_mean               0
concave points_mean          0
symmetry_mean                0
fractal_dimension_mean       0
radius_se                    0
texture_se                   0
perimeter_se                 0
area_se                      0
smoothness_se                0
compactness_se               0
concavity_se                 0
concave points_se            0
symmetry_se                  0
fractal_dimension_se         0
radius_worst                 0
texture_worst                0
perimeter_worst              0
area_worst                   0
smoothness_worst             0
compactness_worst            0
concavity_worst              0
concave points_worst         0
symmetry_worst               0
fractal_dimension_worst      0
Unnamed: 32                569
dtype: int64

Замечено, что только 1 столбец имеет все записи NULL. Этот столбец удален.

In [9]:

df = df.drop(['Unnamed: 32'], axis = 1)

Визуализация данных

Можно заметить, что 62,7% (357 из 569) людей имели доброкачественные опухоли (нераковые) и 37,3% (212 из 569) из них имели злокачественные опухоли (раковые).

In [10]:

df['diagnosis'].value_counts()

Выход[10]:

B    357
M    212
Name: diagnosis, dtype: int64

In [11]:

f,ax=plt.subplots(1,2,figsize=(18,8))
df['diagnosis'].value_counts().plot.pie(explode=[0,0.1],autopct='%1.1f%%',ax=ax[0],shadow=True)
ax[0].set_title('diagnosis')
ax[0].set_ylabel('')
sns.countplot('diagnosis',data=df,ax=ax[1])
ax[1].set_title('diagnosis')
plt.show()
# M is for malignant, B is for benign

Построен парный график всех некоторых соответствующих функций, который визуализирует взаимосвязь между ними.

In [12]:

#pairplot of a sample of features
sns.set()
cols = ['radius_mean', 'texture_mean', 'perimeter_mean', 'area_mean', 'smoothness_mean', 'compactness_mean',	'concavity_mean', 'diagnosis']
sns.pairplot(df[cols], hue = 'diagnosis', height = 2.5)
plt.show();

Синие обозначают злокачественную опухоль, а оранжевые - доброкачественную опухоль.

In [13]:

# Histogram betweeen radius_mean and diagnosis
g=sns.FacetGrid(df, col = 'diagnosis')
g.map(plt.hist,'radius_mean', bins = 20)

Исход[13]:

Теперь категориальные признаки, т. е. B (доброкачественные) и M (раковые), сопоставляются от 0 до 1 соответственно.

In [14]:

mapping = {'B':0, 'M':1}
df['diagnosis'] = df['diagnosis'].map(mapping)

Матрица корреляции с использованием тепловой карты

In [15]:

#correlation matrix
corrmat = df.corr()
f, ax = plt.subplots(figsize=(40, 30))
sns.heatmap(corrmat, vmax=.8, square=True, annot = True, cmap = 'Spectral');

Гистограмма корреляции

Показана корреляция между различными переменными и целью.

In [16]:

#a new dataframe is created dropping our target variable
df1 = df.drop(['diagnosis'], axis = 1)

Существует положительная корреляция между диагностированным доброкачественным состоянием и «ошибкой_гладкости», очень слабая положительная корреляция с «среднее_фрактальное_размерность», «ошибка_текстуры» и «ошибка_симметрии». Все остальные факторы показывают отрицательную корреляцию с диагнозом «доброкачественный» (0).

In [17]:

# visualize correlation barplot
plt.figure(figsize = (16,5))
ax = sns.barplot(df1.corrwith(df.diagnosis).index, df1.corrwith(df.diagnosis))
ax.tick_params(labelrotation = 90)

Предварительная обработка данных

In [18]:

df_new = df

Менее коррелированные значения отбрасываются, чтобы получить лучший набор данных.

In [19]:

df_new = df_new.drop(['id','fractal_dimension_mean','texture_se','smoothness_se','symmetry_se','fractal_dimension_se'],axis = 1)

Нормализация некоторых входных переменных

Целью нормализации/преобразования Гаусса является приведение значений числовых столбцов в наборе данных к общему масштабу, не искажая различий в диапазонах значений. Некоторые модели машинного обучения, такие как линейная и логистическая регрессия, предполагают, что переменные нормально распределены. Если переменная не имеет нормального распределения, ее можно преобразовать с помощью некоторых методов преобразования Гаусса.

In [20]:

from scipy.stats import norm
from scipy import stats
def diagnostic_plots(df_new, variable):## defining a function to plot histogram and Q-Q plot
    plt.figure(figsize = (15,6))
    plt.subplot(1,2,1)
    sns.distplot(df_new[variable], fit=norm);
    plt.subplot(1,2,2)
    stats.probplot(df_new[variable], dist = 'norm', plot = plt)
    plt.show()

Гистограмму и график QQ различных функций можно визуализировать, как показано ниже. Признаки, которые требуют нормализации, чтобы соответствовать распределению Гаусса, преобразуются с использованием логарифмического преобразования.

In [21]:

diagnostic_plots(df_new, 'radius_mean')
diagnostic_plots(df_new, 'texture_mean')
diagnostic_plots(df_new, 'perimeter_mean')
diagnostic_plots(df_new, 'area_mean')
diagnostic_plots(df_new, 'smoothness_mean')
diagnostic_plots(df_new, 'area_worst')
diagnostic_plots(df_new, 'perimeter_worst')
diagnostic_plots(df_new, 'radius_worst')
diagnostic_plots(df_new, 'texture_worst')
diagnostic_plots(df_new, 'perimeter_se')

In [22]:

#applying log transformation to convert radius_mean into a gaussian distribution
df_new['radius_mean'] = np.log(df_new['radius_mean'] + 1)# +1 is added in case there is any 0 input to it which would create issue in taking log
diagnostic_plots(df_new, 'radius_mean')
#applying log transformation to convert texture_mean into a gaussian distribution
##df_new['texture_mean'] = np.log(df_new['texture_mean'] + 1)# +1 is added in case there is any 0 input to it which would create issue in taking log
##diagnostic_plots(df_new, 'texture_mean')
#applying log transformation
df_new['perimeter_mean'] = np.log(df_new['perimeter_mean'] + 1)# +1 is added in case there is any 0 input to it which would create issue in taking log
diagnostic_plots(df_new, 'perimeter_mean')
#applying log transformation
df_new['area_mean'] = np.log(df_new['area_mean'] + 1)# +1 is added in case there is any 0 input to it which would create issue in taking log
diagnostic_plots(df_new, 'area_mean')
#applying log transformation
df_new['area_worst'] = np.log(df_new['area_worst'] + 1)# +1 is added in case there is any 0 input to it which would create issue in taking log
diagnostic_plots(df_new, 'area_worst')
#applying log transformation
df_new['perimeter_worst'] = np.log(df_new['perimeter_worst'] + 1)# +1 is added in case there is any 0 input to it which would create issue in taking log
diagnostic_plots(df_new, 'perimeter_worst')
#applying log transformation
df_new['radius_worst'] = np.log(df_new['radius_worst'] + 1)# +1 is added in case there is any 0 input to it which would create issue in taking log
diagnostic_plots(df_new, 'radius_worst')
#applying log transformation
df_new['texture_worst'] = np.log(df_new['texture_worst'] + 1)# +1 is added in case there is any 0 input to it which would create issue in taking log
diagnostic_plots(df_new, 'texture_worst')
#applying log transformation
df_new['perimeter_se'] = np.log(df_new['perimeter_se'] + 1)# +1 is added in case there is any 0 input to it which would create issue in taking log
diagnostic_plots(df_new, 'perimeter_se')

После логарифмического преобразования график Q-Q для этих величин больше похож на прямую линию. Следовательно, эти переменные нормированы.

Выбор функции

Я использовал ExtraTreesClassifier из модуля обучения scikit, который представляет собой классификатор на основе дерева и может использоваться для вычисления важности функций на основе примесей, которые, в свою очередь, могут использоваться для отбрасывания ненужных функций.

In [23]:

y = df_new['diagnosis'] ### Our target variable
X = df_new.drop(['diagnosis'], axis = 1) ### Input features
y.head(3)

Вышли[23]:

0    1
1    1
2    1
Name: diagnosis, dtype: int64

In [24]:

###splitting dataset into train and test sets with train to test set ratio as 80:20
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

Принимая во внимание 25 наиболее важных функций, визуализация показана ниже:

In [26]:

from sklearn.ensemble import ExtraTreesClassifier
model = ExtraTreesClassifier()
model.fit(X,y)
print(model.feature_importances_)
feat_imp = pd.Series(model.feature_importances_, index = X.columns)
feat_imp.nlargest(25).plot(kind = 'barh')
plt.show()
[0.06236089 0.01664255 0.06431599 0.06131801 0.00779287 0.01805748
 0.05806302 0.07369793 0.00736599 0.02505073 0.03310965 0.03901086
 0.00898383 0.0088296  0.00887307 0.07699415 0.02399726 0.09562853
 0.09071223 0.02535813 0.03152734 0.03820249 0.09576173 0.01724264
 0.01110302]

Удаление менее релевантных функций для получения лучшего набора данных.

In [27]:

df_new = df_new.drop(['compactness_se','smoothness_mean','concavity_se','symmetry_mean',\
                      'fractal_dimension_worst','texture_mean'],axis = 1)

In [28]:

y = df_new['diagnosis'] ### Our target variable
X = df_new.drop(['diagnosis'], axis = 1) ### Input features
y.head(3)

Вышли[28]:

0    1
1    1
2    1
Name: diagnosis, dtype: int64

In [30]:

# Feature scaling
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train_sc = sc.fit_transform(X_train)
X_test_sc = sc.transform(X_test)

Стандартизация преобразует данные, чтобы иметь среднее значение, равное нулю, и стандартное отклонение, равное 1, что улучшает производительность линейной модели. Такие модели, как логистическая регрессия, машина опорных векторов, K ближайших соседей, демонстрируют улучшенные характеристики модели, тогда как модель на основе дерева и методы ансамбля не требуют выполнения масштабирования признаков, поскольку они не чувствительны к дисперсии данных.

Моделирование

In [29]:

###splitting dataset into train and test sets with train to test set ratio as 80:20
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

In [31]:

from sklearn.metrics import accuracy_score

In [32]:

#logistic regression
from sklearn.linear_model import LogisticRegression
logreg = LogisticRegression()
logreg.fit(X_train, y_train)
Y_pred_log = logreg.predict(X_test)
accu_reg = accuracy_score(y_test, Y_pred_log)
print("Accuracy score using Logistic Regression:", accu_reg*100)
Accuracy score using Logistic Regression: 96.49122807017544
/usr/local/lib/python3.6/dist-packages/sklearn/linear_model/_logistic.py:940: ConvergenceWarning: lbfgs failed to converge (status=1):
STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.
Increase the number of iterations (max_iter) or scale the data as shown in:
    https://scikit-learn.org/stable/modules/preprocessing.html
Please also refer to the documentation for alternative solver options:
    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression
  extra_warning_msg=_LOGISTIC_SOLVER_CONVERGENCE_MSG)

In [33]:

#logistic regression with feature scaling
from sklearn.linear_model import LogisticRegression
logreg = LogisticRegression()
logreg.fit(X_train_sc, y_train)
Y_pred_log = logreg.predict(X_test_sc)
accu_reg = accuracy_score(y_test, Y_pred_log)
print("Accuracy score using Logistic Regression with feature scaling:", accu_reg*100)
Accuracy score using Logistic Regression with feature scaling: 99.12280701754386

In [34]:

#support vector machine
from sklearn.svm import SVC
svc = SVC()
svc.fit(X_train, y_train)
Y_pred_svm = svc.predict(X_test)
accu_svc = accuracy_score(y_test, Y_pred_svm)
print("Accuracy score using Support Vector Machine:", accu_svc*100)
Accuracy score using Support Vector Machine: 92.10526315789474

In [35]:

#support vector machine with feature scaling
from sklearn.svm import SVC
svc = SVC()
svc.fit(X_train_sc, y_train)
Y_pred_svm = svc.predict(X_test_sc)
accu_svc = accuracy_score(y_test, Y_pred_svm)
print("Accuracy score using Support Vector Machine with feature scaling:", accu_svc*100)
Accuracy score using Support Vector Machine with feature scaling: 96.49122807017544

In [36]:

#knn
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors = 3)
knn.fit(X_train, y_train)
Y_pred_knn = svc.predict(X_test)
accu_knn = accuracy_score(y_test, Y_pred_knn)
print("Accuracy score using K nearest neighbours", accu_knn*100)
Accuracy score using K nearest neighbours 37.719298245614034

In [37]:

#knn with feature scaling
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors = 3)
knn.fit(X_train_sc, y_train)
Y_pred_knn = svc.predict(X_test_sc)
accu_knn = accuracy_score(y_test, Y_pred_knn)
print("Accuracy score using K nearest neighbours with feature scaling:", accu_knn*100)
Accuracy score using K nearest neighbours with feature scaling: 96.49122807017544

In [38]:

# Gaussian Naive Bayes
from sklearn.naive_bayes import GaussianNB
gaussian = GaussianNB()
gaussian.fit(X_train, y_train)
Y_pred_nb = gaussian.predict(X_test)
acc_gaussian = accuracy_score(y_test, Y_pred_nb)
print("Accuracy score using Gaussian Naive Bayes:", acc_gaussian*100)
Accuracy score using Gaussian Naive Bayes: 95.6140350877193

In [39]:

# Gaussian Naive Bayes with feature scaling
from sklearn.naive_bayes import GaussianNB
gaussian = GaussianNB()
gaussian.fit(X_train_sc, y_train)
Y_pred_nb = gaussian.predict(X_test_sc)
acc_gaussian = accuracy_score(y_test, Y_pred_nb)
print("Accuracy score using Gausian Naive Bayes with feature scaling:", acc_gaussian*100)
Accuracy score using Gausian Naive Bayes with feature scaling: 95.6140350877193

In [40]:

# Decision Tree
from sklearn.tree import DecisionTreeClassifier
decision_tree = DecisionTreeClassifier()
decision_tree.fit(X_train, y_train)
Y_pred_dt = decision_tree.predict(X_test)
acc_decision_tree = accuracy_score(y_test, Y_pred_dt)
print("Accuracy score using Decision Tree:", acc_decision_tree*100)
Accuracy score using Decision Tree: 91.22807017543859

In [41]:

# Decision Tree with feature scaling
from sklearn.tree import DecisionTreeClassifier
decision_tree = DecisionTreeClassifier()
decision_tree.fit(X_train_sc, y_train)
Y_pred_dt = decision_tree.predict(X_test_sc)
acc_decision_tree = accuracy_score(y_test, Y_pred_dt)
print("Accuracy score using Decision Tree with feature scaling:", acc_decision_tree*100)
Accuracy score using Decision Tree with feature scaling: 91.22807017543859

In [42]:

# Random Forest
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
random_forest = RandomForestClassifier(n_estimators=100)
random_forest.fit(X_train, y_train)
Y_pred_rf = random_forest.predict(X_test)
random_forest.score(X_train, y_train)
acc_random_forest = accuracy_score(y_test, Y_pred_rf)
print("Accuracy score using Random Forest:", acc_random_forest*100)
Accuracy score using Random Forest: 96.49122807017544

In [43]:

# Random Forest with feature scaling
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
random_forest = RandomForestClassifier(n_estimators=100)
random_forest.fit(X_train_sc, y_train)
Y_pred_rf = random_forest.predict(X_test_sc)
random_forest.score(X_train, y_train)
acc_random_forest = accuracy_score(y_test, Y_pred_rf)
print("Accuracy score using Random Forest with feature scaling:", acc_random_forest*100)
Accuracy score using Random Forest with feature scaling: 95.6140350877193

In [44]:

# XGBoost Classifier
from xgboost import XGBClassifier
xgb_classifier = XGBClassifier()
xgb_classifier.fit(X_train, y_train)
y_pred_xgb = xgb_classifier.predict(X_test)
acc_xgb = accuracy_score(y_test, y_pred_xgb)
print("Accuracy score using XG Boost Classifier:", acc_xgb*100)
Accuracy score using XG Boost Classifier: 96.49122807017544

In [46]:

# XGBoost Classifier
from xgboost import XGBClassifier
xgb_classifier = XGBClassifier()
xgb_classifier.fit(X_train_sc, y_train)
y_pred_xgb = xgb_classifier.predict(X_test_sc)
acc_xgb = accuracy_score(y_test, y_pred_xgb)
print("Accuracy score using XG Boost Classifier with feature scaling:", acc_xgb*100)
Accuracy score using XG Boost Classifier with feature scaling: 96.49122807017544

In [47]:

models = pd.DataFrame({
    'Model': ['Support Vector Machines', 'KNN', 'Logistic Regression', 'Decision Tree',
              'Random Forest', 'Naive Bayes', 'XG Boost'],
    'Score': [accu_svc, accu_knn, accu_reg, acc_decision_tree,
              acc_random_forest, acc_gaussian, acc_xgb]})
models.sort_values(by='Score', ascending=False)

Вышел[47]:

Логистическая регрессия показывает самую высокую точность 99,12%. Поэтому мы будем использовать его в качестве нашей модели машинного обучения.

Матрица путаницы

Оценка матрицы путаницы имеет ошибку типа I как 0 и ошибку типа II как 1, что указывает на хорошую производительность модели.

In [48]:

from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, Y_pred_log)
plt.title('Heatmap of Confusion Matrix', fontsize = 15)
sns.heatmap(cm, annot = True)
plt.show()

In [49]:

from sklearn.metrics import classification_report
print(classification_report(y_test, Y_pred_log))
precision    recall  f1-score   support
           0       0.99      1.00      0.99        71
           1       1.00      0.98      0.99        43
    accuracy                           0.99       114
   macro avg       0.99      0.99      0.99       114
weighted avg       0.99      0.99      0.99       114

Перекрестная проверка модели ML

Перекрестная проверка — это метод, используемый для проверки эффективности модели машинного обучения, а также процедура повторной выборки, используемая для оценки модели, если у нас есть ограниченные данные. Здесь используется 10-кратная перекрестная проверка, которая дала меньшую точность, чем точность, полученная из модели логистической регрессии. Это указывает на то, что в модели есть переобучение, которое можно преодолеть, используя больший набор данных.

In [57]:

# Cross validation
from sklearn.model_selection import cross_val_score
cross_validation = cross_val_score(estimator = logreg, X = X_train_sc, y = y_train, cv = 20)
print("Cross validation of Logistic Regression model = ",cross_validation)
print("Cross validation of Logistic Regression model (in mean) = ",cross_validation.mean())
Cross validation of Logistic Regression model =  [1.         0.95652174 1.         0.95652174 1.         0.95652174
 0.95652174 0.91304348 0.95652174 1.         1.         1.
 1.         1.         1.         0.90909091 1.         0.95454545
 0.90909091 0.95454545]
Cross validation of Logistic Regression model (in mean) =  0.9711462450592885

Среднее значение точности перекрестной проверки составляет 97,11 %, а точность модели логистической регрессии — 99,12 %. Это показывает, что логистическая регрессия немного переобучена, но когда обучающих данных будет больше, это будет обобщенная модель.

Следовательно, модель может служить нашей цели, поскольку она имеет показатель точности более 95% для прогнозирования рака молочной железы у пациентов.

Спасибо, что дочитали до конца.

Ссылка на репозиторий github — https://github.com/priya-nath/Breast_Cancer_Prediction_Using_ML_Classification