import pandas as pd
pd.set_option('display.max_columns', 50)
import numpy as np
import os
os.chdir('D:\Data\Projects\Classification\Heart Disease')
import matplotlib.pyplot as plt
plt.style.use('Solarize_Light2')
plt.rcParams['font.size'] = 15
import seaborn as sns
from warnings import filterwarnings
filterwarnings('ignore')
from IPython.core.pylabtools import figsize
figsize(10, 10)
import plotly.offline as py
import plotly.graph_objs as go
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import f1_score, confusion_matrix, roc_auc_score, roc_curve, classification_report, accuracy_score
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import RandomizedSearchCV
from sklearn import model_selection
from sklearn.dummy import DummyClassifier
from sklearn.linear_model import LogisticRegression
df = pd.read_csv('heart.csv')
df.shape
df.head(5)
x = df.drop('target', axis=1)
y = df.target
x.shape, y.shape
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
X_train.shape, X_test.shape, y_train.shape, y_test.shape
Mittelwert bei 0, Standardabweichung 1
Für einige der Algorithmen, wie Logistic Regression und Support Vector Machines, ist das Standardisieren wichtig, um optimale Ergebnisse zu erzielen.
Das Fitten geschieht ausschließlich auf X_train, transformiert werden dann X_train und X_test.
sc = StandardScaler()
sc.fit(X_train)
X_train =sc.transform(X_train);
X_test =sc.transform(X_test);
Das Dummy Model sagt immer den Mittelwert der Zielvariablen voraus
# Create dummy classifer
dummy = DummyClassifier(strategy='uniform', random_state=1)
# "Train" model
dummy.fit(X_train, y_train)
# Get accuracy score
dummy.score(X_test, y_test)
lr = LogisticRegression()
lr.fit(X_train, y_train)
y_pred = lr.predict(X_test)
accuracy_score(y_pred, y_test)
c: je höher, desto weniger ist das Model regularized (default:1.0)
param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100, 1000] }
clf = GridSearchCV(LogisticRegression(penalty='l2'), param_grid)
clf.fit(X_train, y_train)
clf.best_params_
# Logistic Regression it c= 0.01
lr_reg = LogisticRegression(C=0.01)
lr_reg.fit(X_train, y_train)
y_pred_reg = lr_reg.predict(X_test)
y_proba = lr_reg.predict_proba(X_test)
accuracy_score(y_test, y_pred_reg)
Für die Roc Kurve brauche ich Thresholds, sonst gibt es nur einen Punkt und sie gibt Accuracy aus.
roc_auc_score(y_test, y_pred_reg)
print(classification_report(y_test, y_pred_reg))
cm = confusion_matrix(y_test, y_pred_reg)
cm
plt.rcParams['font.size'] = 20
ax= plt.subplot()
sns.heatmap(cm, annot=True, ax = ax, cmap='Set2', fmt=".1f"); #annot=True to annotate cells
# labels, title and ticks
ax.set_xlabel('Predicted labels', fontsize=18);
ax.set_ylabel('True labels', fontsize=18);
ax.set_title('Confusion Matrix');
ax.xaxis.set_ticklabels(['0', '1']);
ax.yaxis.set_ticklabels(['0', '1']);
plt.tight_layout()
results = pd.DataFrame({'y_test': y_test, 'y_pred': y_pred_reg, 'y_proba': y_proba[:,1]})
results = results.sort_index()
# alle falsch klassifizierten Patienten
results[(y_test == 1) == (y_pred_reg == 0)]
results[(y_test == 1) & (y_pred_reg == 0)]
df.iloc[[42, 101, 139], :]
# Median der Werte über 0,5
results.loc[results.y_proba > 0.5].median()
results.loc[results.y_proba > 0.5].min()
# Es gibt keine Werte bei 0.5, daher ist das kde Plot unten irgendwie irreführend.
figsize(10, 8)
sns.kdeplot(results.y_proba, shade = True)
plt.axvline(0.5, 0, 1, color='red')
figsize(10, 8)
plt.hist(results.y_proba, bins = 35)
plt.axvline(0.5, 0, 1, color='red')
# Recall berechnen
tpr = cm[1,1]/(cm[1,1]+cm[1,0])
tpr
fpr= cm[0,1]/(cm[0,1]+cm[0,0])
fpr
y_pred_prob = lr_reg.predict_proba(X_test)[:,1]
fpr, tpr, thresholds = roc_curve(y_test, y_pred_prob, drop_intermediate=False)
thresholds
Es scheint verwunderlich, dass der erste Werte von Thresholds über 1 liegt. Dies ist kein Bug, sondern soll so sein, damit der Wert 0 für TPR und FPR angezeigt werden kann.
figsize(10, 7)
plt.plot(fpr, tpr)
plt.xlim([-0.05, 1.05])
plt.ylim([-0.05, 1.05])
plt.title('ROC Curve Heart Disease')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.grid(True)
fpr
plt.subplots(figsize=(15, 8))
plt.plot(fpr, tpr, 'o-', label="ROC curve")
plt.plot(np.linspace(0,1,10), np.linspace(0,1,10), label="diagonal")
for x, y, txt in zip(fpr[::5], tpr[::5], thresholds[::5]):
plt.annotate(np.round(txt,2), (x, y-0.04))
rnd_idx = 27
plt.annotate( 'this point refers to the tpr and the fpr\n at a probability threshold of {}'.format(np.round(thresholds[rnd_idx], 2)),
xy=(fpr[rnd_idx], tpr[rnd_idx]), xytext=(fpr[rnd_idx]+0.2, tpr[rnd_idx]-0.25),
arrowprops=dict(facecolor='black', lw=2, arrowstyle='->'),)
plt.legend(loc="upper left")
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
print(tuple(zip(fpr[::5], tpr[::5], thresholds[::5])))
trace1 = go.Scatter(x=fpr, y=tpr,
mode='lines',
line=dict(color='darkorange'),
name='ROC curve'
)
trace2 = go.Scatter(x=[-0.05, 1.05], y=[-0.05, 1.05],
mode='lines',
line=dict(color='navy', dash='dash'),
showlegend=False)
layout = go.Layout(title='Receiver operating characteristic Heart Disease',
xaxis=dict(title='False Positive Rate'),
yaxis=dict(title='True Positive Rate'))
fig = go.Figure(data=[trace1, trace2], layout=layout)
py.iplot(fig)
lr_bal = LogisticRegression(C=0.01, class_weight='balanced')
lr_bal.fit(X_train, y_train)
y_pred_bal = lr_bal.predict(X_test)
accuracy_score(y_pred_bal, y_test)
df_poly = pd.read_csv('df_poly.csv')
df_poly.head()
x_p = df_poly.drop('target', axis=1)
y = df_poly.target
x_p.shape, y.shape
X_train_p, X_test_p, y_train, y_test = train_test_split(x_p, y, test_size=0.2, random_state=42)
X_train_p.shape, X_test_p.shape, y_train.shape, y_test.shape
Standardisieren des Polynomial Datensatzes
sc.fit(X_train_p)
X_train_p =sc.transform(X_train_p);
X_test_p =sc.transform(X_test_p);
lr_reg_p = LogisticRegression(C=0.01)
lr_reg_p.fit(X_train_p, y_train)
y_p_pred = lr_reg_p.predict(X_test_p)
accuracy_score(y_p_pred, y_test)
Mit Polynomial Features performt das Model auf dem Test-Set gleich.
Bei der Auswahl einer Metrik für die Güte eines Models ist die Problemstellung von großer Bedeutung. Soll vorhergesagt werden, ob ein Patient krank oder gesund ist, ist die Metrik Recall wichtiger als der Accuracy-Score. Der Grund hierfür ist, dass lieber einige gesunde Patienten weiter getestet werden, als das ein kranker Patient als gesund eingestuft wird.
Zudem sollen nun nicht die Klassen direkt vorhergesagt werden, sondern die Wahrscheinlichkeit für die Zugehörigkeit zu einer Klasse. So können Risikogruppen identifiziert werden.
# Dataframe aus den Vorhersagen in Wahrscheinlichkeiten
pred_proba_df = pd.DataFrame(lr_reg.predict_proba(X_test))
# Liste von Entscheidungsgrenzen
threshold_list = [0.05,0.1,0.15,0.2,0.25,0.3,0.35,0.4,0.45,0.5,0.55,0.6,0.65,.7,.75,.8,.85,.9,.95,.99]
tpr_list = []
fpr_list = []
for i in threshold_list:
print ('\n****** For threshold = {} ******'.format(i))
y_test_pred = pred_proba_df.applymap(lambda x: 1 if x > i else 0)
# y_test und Spalte für 1 aus y_pred umwandeln, Accuracy Score aller Werte i berechnen
test_accuracy = accuracy_score(y_test.as_matrix().reshape(y_test.as_matrix().size, 1),
y_test_pred.iloc[:,1].as_matrix().reshape(y_test_pred.iloc[:,1].as_matrix().size, 1))
print('Testing Accuracy: {}'.format(test_accuracy))
# Confusion Matrix für alle Werte i
con = confusion_matrix(y_test.as_matrix().reshape(y_test.as_matrix().size, 1),
y_test_pred.iloc[:,1].as_matrix().reshape(y_test_pred.iloc[:,1].as_matrix().size, 1))
tpr = con[1,1]/(con[1,1]+con[1,0])
fpr = con[0,1]/(con[0,1]+con[0,0])
tpr_list.append(tpr)
fpr_list.append(fpr)
print('Confusion Matrix: ')
print(con)
print('True Positve Rate: ', tpr)
print('False Positive Rate: ', fpr)
rev = [i for i in threshold_list[::-1]]
rev
[i for i in reversed(threshold_list)]
rates = pd.DataFrame({'Threshold' : threshold_list,
'True Positive Rate': tpr_list,
'False Positive Rate': fpr_list})
rates
rate = rates.drop([0, 1, 6, 7, 17, 18, 19])
rate = rate.reset_index(drop=True)
rate
tpr = rate['True Positive Rate']
fpr = rate['False Positive Rate']
th = rate['Threshold']
figsize(15, 15)
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("ROC Curve")
plt.scatter(fpr, tpr)
for i, txt in enumerate(th):
plt.annotate(txt, (fpr[i]+0.01, tpr[i]))