In [1]:
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
df= pd.read_csv('c:/1/Stroke_Prediction.csv')
df.head(5)
1. Sprawdzenie kompletności i formatu danych¶
df.isnull().sum()
import seaborn as sns
print('obserwacji zmiennych: ',df.shape)
sns.heatmap(df.isnull(),yticklabels=False,cbar=False,cmap='viridis')
Analiza BMI (Body Mass Index)¶
- BMI<18,5 > nadwaga
- 18,5<=BMI<=24,9 > waga prawidłowa
- 25<=BMI <=29,9 > nadwaga
- BMI>30 > otyłość
a = r'BMI = frac{masa}{{wzrost}^{2}}'
ax = plt.axes([0,0,0.3,0.3]) #left,bottom,width,height
ax.set_xticks([])
ax.set_yticks([])
ax.axis('off')
plt.text(0.4,0.4,'$
Sprawdzam, czy są błędne dane we wskaźniku BMI (Body Mass Index)¶
- Wartość minimalna dla BMI: Zakładam, że ludzie mają minimalnie 100 cm wzrostu i ważą maksymalnie 300 kg
- Wartość maksymalna dla BMI: Zakładam, że ludzie mają maksymalnie 230 cm wzrostu i ważą minimalnie 20 kg
max_BMI=400/(1*1)
min_BMI=30/(2.20*2.20)
print('max_BMI: ', max_BMI)
print('min_BMI: ', min_BMI)
df[(df['BMI']<=10)&(df['BMI']>=300)]
Brak danych zafałszowanych w kolumnie BMI.
Sprawdzam, jaka jest struktura danych.
BMI1 = pd.qcut(df['BMI'],12)
BMI1.value_counts(dropna = False).sort_values(ascending=False).plot(kind='bar')
#df.BMI.value_counts(dropna = False)
import matplotlib.dates as mdates
fig, ax = plt.subplots()
df['BMI'].plot.kde(ax=ax, legend=False, title='Histogram: BMI')
df['BMI'].plot.hist(density=True, ax=ax)
ax.set_ylabel('Probability')
ax.grid(axis='y')
#ax.set_facecolor('#d8dcd6')
Analiza Smoking_Status¶
df['Smoking_Status'].value_counts(dropna = False)
Podobnie nie ma możliwości uzupełnienia brakujących wartości zmienej niezależnej: Smoking_Status na podstawie zachowania pozostałych zmiennych niezależnych.
Zmienna ta musi mieć trzy stany:
- never smoked,
- formerly smoked,
- smokes.
Pozostawienie czwartego stanu NaN byłoby błędem.
df['Smoking_Status'].value_counts(normalize=True,dropna = False)
Jak ważna jest informacja ‘Smoking_Status’ i ‘BMI’ dla zmiennej wynikowej? Sprawdzam to, ponieważ istnieje możliwość eliminacji całych zmiennych. Przy okazji zbadamy korelacje pozostałych zmiennych egzogenicznych ze zmienną endogeniczną.
df['Ss_nowa'] = pd.Categorical(df['Smoking_Status']).codes
CORREL = df.corr().sort_values('Stroke')
print(CORREL['Stroke'])
del df['Ss_nowa']
Kasuję wszystkie rekordy z brakami: ‘Smoking_Status’ i ‘BMI’¶
print('Przed kasowaniem: ',df.shape)
df = df.dropna(how='any')
print('Po kasowaniu: ',df.shape)
df.head(5)
Analiza Gender¶
df['Gender'].value_counts(normalize=True,dropna = False)
Co to znaczy płeć ‘Other’? Przedmiotem badania jest podatność na udar m.in pod kątem konkretnej płci. Płeć mózgu nie ma tu znaczenia. Przyjmuję, że ‘Other’ to błąd danych i go kasuję. Pozostawienie trzeciego stanu ‘Other’ byłoby błędem dla procesu klasyfikacji.
df['Gender'].replace('Other', np.nan, inplace=True)
print('Przed kasowaniem: ',df.shape)
df = df.dropna(how='any')
print('Po kasowaniu: ',df.shape)
Analiza Age_In_Days¶
Wiek człowieka analizujemy w latach. Jednocześnie ludzie starzeją się nierównomiernie. Dlatego wskazane jest analizować pacjentów według grup wiekowych.
df['Age_years']= df['Age_In_Days']/365
Sprawdzam, czy zmienna ‘Age_years’ ma prawidłowe wartości. Okazuje się, że trzech pacjentów ma wiek powyżej 200 lat. Kasujemy te rekordy.
df[df['Age_years']>120]
df['Age_years'] = df['Age_years'].apply(lambda x: np.nan if x > 120 else x)
print('Przed kasowaniem: ',df.shape)
df = df.dropna(how='any')
print('Po kasowaniu: ',df.shape)
df[df['Age_years']>120]
Podzieliłem wiek na 10 grup wiekowych. Kasuję kolumnę ‘Age_In_Days’.
del df['Age_In_Days']
df['Age_years_10']= pd.qcut(df['Age_years'],10)
df['Age_years_10'].value_counts(normalize=True,dropna = False).sort_values(ascending=False).plot(kind='bar')
Analiza Hypertension¶
df['Hypertension'].value_counts(normalize=True,dropna = False)
Nadciśnienie występuje u 11% badanych.Powszechnie uważa się, że nadciśnienie występuje u ludzi mających wysokie BMI (nadwagę). Sprawdźmy, czy tak jest.
df['BMI_5']= pd.qcut(df['BMI'],5)
df.pivot_table(index='BMI_5', columns = 'Hypertension', values='Age_years',aggfunc='count')
df['BMI_5'] = df['BMI_5'].astype(object)
plt.style.use('seaborn')
table=pd.crosstab(df['BMI_5'],df['Hypertension'])
table.div(table.sum(1).astype(float), axis=0).plot(kind='bar', stacked=True, fontsize=14)
plt.title('BMI vs Hypertension', fontsize=20)
plt.xlabel('Grupy_BMI')
plt.ylabel('Proporcja')
del df['BMI_5']
Zmienna egzogeniczna ‘Hypertension’ jest prawidłowa i zachowuje się zgodnie z powszechnym poglądem, że im większe BMI, tym większe nadciśnienie tętnicze.
Analiza Heart_Disease¶
df['Heart_Disease'].value_counts(normalize=True,dropna = False)
Analiza Ever_Married¶
df['Ever_Married'].value_counts(normalize=True,dropna = False)
Analiza Type_Of_Work¶
df['Type_Of_Work'].value_counts(normalize=True,dropna = False)
Analiza Residence¶
df['Residence'].value_counts(normalize=True,dropna = False)
Analiza Avg_Glucose¶
df['Avg_Glucose'].describe()
df['Avg_Glucose'].plot.kde()
Rozkład gęstości prawdopodobieństwa zmiennej: ‘Avg_Glucose’ posiada anomalie, której nie będziemy wyjaśniali na tym etapie badania.
Analiza Stroke¶
df['Stroke'].value_counts(normalize=True,dropna = False)
Zmienna wynikowa ‘Stroke’ jest bardzo niezbilansowana. Z ciekawości zerkniemy, czy pojawia się jakiś wzór zależności zmiennej zależnej i zmiennych niezależnych.
Analiza ogólna zmiennych¶
Wykonuje się ją w ceu sprawdzenia, czy zachowanie zmiennych jest zgodne z ogólnie znaną wiedzą.
df.columns
kot = ["#c0c2ce", "#e40c2b"]
sns.pairplot(data=df[[ 'Avg_Glucose', 'BMI', 'Stroke', 'Age_years']], hue='Stroke', dropna=True, palette=kot)
Wstępna analiza danych ciągłych na powyższym wykresie wykazała, że:
- prawdopodobieństwo udaru rośnie wraz z wiekiem,
- udar najczęściej występuje w przedziale BMI 20-50,
- poziom glukozy wydaje się nie mieć znaczenia.
Zachowanie zmiennych potwierdza ogólnie znaną wiedzę.
Zapisanie oczyszczonego i poprawionego zbioru danych do dalszych analiz¶
df.head(3)
df.isnull().sum()
df.to_csv('c:/1/Stroke_Prediction_CLEAR.csv')
End of Part_1: Stroke_Prediction – Preparation of data for analysis
Part_2 Stroke_Prediction – Preparation of data for the classification process