Типы отсутствующих данных
1- Отсутствует полностью случайным образом (MCAR):
Случайно пропавшие без вести (MCAR) Полностью случайно пропавшие без вести довольно просто. Это означает то, что говорится: склонность к отсутствию точки данных совершенно случайна. Нет никакой связи между отсутствием точки данных и какими-либо значениями в наборе данных, отсутствующими или наблюдаемыми.
2- Отсутствует не случайно (MNAR):
Также известное как неигнорируемое отсутствие ответа — это данные, которые не являются ни MAR, ни MCAR (т. е. значение отсутствующей переменной связано с причиной ее отсутствия).
3- Отсутствует случайным образом (MAR):
Означает, что склонность к отсутствию точки данных связана не с отсутствием данных, а с некоторыми наблюдаемыми данными. Независимо от того, ответил кто-то на № 13 в вашем опросе, это не имеет ничего общего с отсутствующими значениями, но имеет отношение к значениям какой-либо другой переменной.
import pandas as pd import numpy as np
df = pd.read_csv("train.csv") df
df.isnull().sum() #Tells How many null values are there in every column
PassengerId 0 Survived 0 Pclass 0 Name 0 Sex 0 Age 177 SibSp 0 Parch 0 Ticket 0 Fare 0 Cabin 687 Embarked 2 dtype: int64
df[df['Embarked'].isnull()] #Show the data where there is missing values in "Embarked" column
2- Отсутствующие данные не случайным образом (MNAR): систематические отсутствующие данные
Существует связь между отсутствующими данными и любым другим отсутствующим или наблюдаемым значением в наборе данных.
#Making an other column 'Cabin_null' and it is initialized with values 0,1 when there is a null value in 'Cabin' column df['Cabin_null'] = np.where(df['Cabin'].isnull(),1,0) df['Cabin_null']
0 1 1 0 2 1 3 0 4 1 .. 886 1 887 0 888 1 889 0 890 1 Name: Cabin_null, Length: 891, dtype: int32
#Find the percentage of null values df['Cabin_null'].mean()
0.7710437710437711
df.columns
Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked', 'Cabin_null'], dtype='object')
#It's means that where values in "Cabin_null" are missing. Most of them are not servived(0) that's why there percentage is higher # and where mean is less, so they are survived(1). df.groupby(['Survived'])['Cabin_null'].mean()
Survived 0 0.876138 1 0.602339 Name: Cabin_null, dtype: float64
3- пропавших без вести наугад (март)
Нравится: Мужчинам — — Скрыть зарплату Женщинам — — Скрыть возраст
Все методы обработки пропущенных значений
1- Замена среднего/медианы/моды 2- Импутация случайной выборки 3- Сбор значений NAN с новой функцией 4- Импутация конца распределения 5- Произвольная импутация 6- Импутация частых категорий
Вменение среднего/медианы/моды
Когда это применять? Вменение среднего / медианного значения предполагает, что данные отсутствуют полностью случайным образом (MAR). Мы решаем эту проблему, заменяя NaN на наиболее часто встречающуюся переменную. Чтобы преодолеть выбросы, мы используем Media или режим.
df = pd.read_csv('train.csv', usecols = ['Age', 'Fare', 'Survived'])
df.head()
# Percentage of missing values df.isnull().mean()
Survived 0.000000 Age 0.198653 Fare 0.000000 dtype: float64
# We make a function to impute nan values and give parameters, dataset, column name, median. # in 2nd line we make a new column and fill it with median where there is a nan values in the each column like age,fare,survived def impute_nan(df, variable, median): df[variable+"_median"] = df[variable].fillna(median)
median = df.Age.median() median
28.0
impute_nan(df, 'Age', median) #Function call df.head() #Now we get column "Age_median" and here all null values of Age is convert to median
print(df['Age'].std()) print(df['Age_median'].std()) #Standard Deviatipon of 'Age_median' column is less because we handle missing value
14.526497332334044 13.019696550973194
import matplotlib.pyplot as plt %matplotlib inline
fig = plt.figure() ax = fig.add_subplot(111) df['Age'].plot(kind = 'kde', ax = ax) df['Age_median'].plot(kind = 'kde', ax = ax, color = 'red') lines, labels = ax.get_legend_handles_labels() ax.legend(lines, labels, loc = 'best')
<matplotlib.legend.Legend at 0x187d01af8e0>
Недостатки среднего/медианы
1- влияние корреляции 2- изменение или искажение исходной дисперсии
Недостатки среднего/медианы
1- Простота реализации 2- Более быстрый способ получить полный набор данных
2 Вменение случайной выборки
Он берет случайное наблюдение из набора данных и использует это наблюдение, чтобы заменить им отсутствующие значения.
Когда его следует использовать? Когда данные отсутствуют полностью случайным образом (MCAR).
import pandas as pd import numpy as np
df = pd.read_csv('train.csv', usecols = ['Age', 'Fare', 'Survived']) df.head()
df.isnull().sum()
Survived 0 Age 177 Fare 0 dtype: int64
#Check percentage of missing values df.isnull().mean()
Survived 0.000000 Age 0.198653 Fare 0.000000 dtype: float64
df['Age'].isnull().sum()
177
#First we are dropping nan values from Age column, then we are picking samples of present or real values and replace #them with 177 null values and with random state = 0. Sample values will remain same. it will not change everytime df['Age'].dropna().sample(df['Age'].isnull().sum(), random_state = 0)
423 28.00 177 50.00 305 0.92 292 36.00 889 26.00 ... 539 22.00 267 25.00 352 15.00 99 34.00 689 15.00 Name: Age, Length: 177, dtype: float64
#Getting indexes where there are null values df[df['Age'].isnull()].index
Int64Index([ 5, 17, 19, 26, 28, 29, 31, 32, 36, 42, ... 832, 837, 839, 846, 849, 859, 863, 868, 878, 888], dtype='int64', length=177)
#Create a function to replace tha nan values with random observation def impute_nan(df, variable, median): df[variable+'_median'] = df[variable].fillna(median) df[variable+'_random'] = df[variable] #It will consists of random samples through which we fill nan values random_smpl = df[variable].dropna().sample(df[variable].isnull().sum(), random_state = 0) #Pandas need to have same index in order to merge dataset random_smpl.index = df[df[variable].isnull()].index df.loc[df[variable].isnull(), variable+'_random'] = random_smpl
median = df['Age'].median() median
28.0
impute_nan(df, 'Age', median)
df.head()
import matplotlib.pyplot as plt %matplotlib inline
fig = plt.figure() ax = fig.add_subplot(111) df['Age'].plot(kind = 'kde', ax = ax) df.Age_random.plot(kind = 'kde', ax = ax, color = 'yellow') lines, labels = ax.get_legend_handles_labels() ax.legend(lines, labels, loc = 'best')
<matplotlib.legend.Legend at 0x187dc0dcd30>
Преимущества
1- Меньше искажений в дисперсии
3- Захват значений NaN с новой функцией
Это хорошо работает, когда данные не отсутствуют полностью случайным образом.
df = pd.read_csv('train.csv', usecols = ['Age', 'Survived', 'Fare'])
df.head()
df['Age_NaN'] = np.where(df['Age'].isnull(),1, 0)
df.head()
df.Age.median()
28.0
df['Age'].fillna(df.Age.median(), inplace = True) df.head(50)
Преимущество
1- Простота реализации 2- Учитывает важность отсутствующих значений
Недостатки
1- Создание дополнительных функций (Проклятие размерности)
3- Вменение в конце распределения
Получите данные от 3 стандартных отклонений
import pandas as pd import numpy as np
df = pd.read_csv('train.csv', usecols = ['Age', 'Fare', 'Survived']) df.head()
df.Age.hist(bins = 50)
<AxesSubplot:>
#Pick right end of distribution of data to replace all NaN Values extreme = df.Age.mean()+3*df.Age.std() extreme
73.27860964406095
import seaborn as sns sns.boxplot('Age', data = df) #From this we get outliers
c:\python39\lib\site-packages\seaborn\_decorators.py:36: FutureWarning: Pass the following variable as a keyword arg: x. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation. warnings.warn( <AxesSubplot:xlabel='Age'>
def impute_NaN(df, median, extreme, variable): df[variable+"_end_distribution"] = df[variable].fillna(extreme) df[variable].fillna(median, inplace = True) #Becaue we want to compute 'Age' and 'Age_end_distribution_imputstion'
impute_NaN(df, df.Age.median(), extreme, 'Age')
df.head()
df['Age'].hist(bins = 50) #Because we give median value in nan values in feature 'Age'
<AxesSubplot:>
df['Age_end_distribution'].hist(bins=50)
<AxesSubplot:>
sns.boxplot('Age_end_distribution', data = df) #Now in box plot we see that there is no outlierrs by usinng end of distribution
c:\python39\lib\site-packages\seaborn\_decorators.py:36: FutureWarning: Pass the following variable as a keyword arg: x. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation. warnings.warn( <AxesSubplot:xlabel='Age_end_distribution'>
Преимущества:
1- Выбросы фиксируются с помощью конечного распределения
Вменение произвольного значения
Он состоит из замены значений NaN произвольными значениями. Для каждой функции произвольное значение должно быть другим.
что такое произвольное значение? 1- Здесь мы берем последнее значение выброса, а также можем взять наименьшее значение выброса. 2- Используется, чтобы увидеть важность пропущенных значений 3-
import pandas as pd import numpy as np
df = pd.read_csv('train.csv', usecols= ['Age', 'Survived', 'Fare']) df.head()
def impute_NaN(df, variable): df[variable+'Zeros'] = df[variable].fillna(0) df[variable+'Hundreds'] = df[variable].fillna(100)
impute_NaN(df, 'Age')
df.head()
df['Age'].hist(bins = 50)
<AxesSubplot:>
Как обрабатывать категориальные пропущенные значения
1- Частое вменение категории
import pandas as pd
df.columns
Index(['Survived', 'Age', 'Fare', 'AgeZeros', 'AgeHundreds'], dtype='object')
df = pd.read_csv('house.csv', usecols = ['BsmtQual', 'FireplaceQu', 'GarageType', 'SalePrice']) df.head()
df.isnull().mean()
BsmtQual 0.025342 FireplaceQu 0.472603 GarageType 0.055479 SalePrice 0.000000 dtype: float64
df.isnull().mean().sort_values(ascending = True)
SalePrice 0.000000 BsmtQual 0.025342 GarageType 0.055479 FireplaceQu 0.472603 dtype: float64
df.isnull().sum() #As we seen that BsmtQual abd GarageType has less nan values so we replace it with more frequent tcategories
BsmtQual 37 FireplaceQu 690 GarageType 81 SalePrice 0 dtype: int64
#To find maximum number of frequent features df.groupby(['BsmtQual'])['BsmtQual'].count()
BsmtQual Ex 121 Fa 35 Gd 618 TA 649 Name: BsmtQual, dtype: int64
df.groupby(['BsmtQual'])['BsmtQual'].count().sort_values(ascending = False).plot.bar()
<AxesSubplot:xlabel='BsmtQual'>
df['BsmtQual'].value_counts() #Method to get most frequent category
TA 649 Gd 618 Ex 121 Fa 35 Name: BsmtQual, dtype: int64
df['BsmtQual'].value_counts().sort_values(ascending = False).plot.bar()
<AxesSubplot:>
df.groupby(['GarageType'])['GarageType'].count() #Code to get categories which is most frequenting
GarageType 2Types 6 Attchd 870 Basment 19 BuiltIn 88 CarPort 9 Detchd 387 Name: GarageType, dtype: int64
df.groupby(['GarageType'])['GarageType'].count().sort_values(ascending = False).plot.bar()
<AxesSubplot:xlabel='GarageType'>
df['GarageType'].value_counts().plot.bar()
<AxesSubplot:>
df['FireplaceQu'].mode()[0] #Code to get most frequent category
'Gd'
df['FireplaceQu'].value_counts() # You can also get most frequent category by this code
Gd 380 TA 313 Fa 33 Ex 24 Po 20 Name: FireplaceQu, dtype: int64
df['BsmtQual'].value_counts().index[0] #Another method to get most frequent category
'TA'
df['FireplaceQu'].value_counts().plot.bar()
<AxesSubplot:>
#### Replacing functions def impute_NaN(df, variable): mst_frequent = df[variable].value_counts().index[0] df[variable].fillna(mst_frequent, inplace = True)
for features in ['BsmtQual', 'FireplaceQu', 'GarageType']: impute_NaN(df, features)
df.isnull().mean()
BsmtQual 0.0 FireplaceQu 0.0 GarageType 0.0 SalePrice 0.0 dtype: float64
Недостаток
когда у вас есть высокие пропущенные значения, не следует использовать эту технику. потому что это исказит взаимосвязь наиболее частых категорий с зависимыми переменными
2- Добавление переменной tu для захвата NaN
df = pd.read_csv('house.csv', usecols = ['BsmtQual', 'FireplaceQu', 'GarageType', 'SalePrice'])
df.head()
import numpy as np
#Capturing the importance of null values
df['BsmtQual_var'] = np.where(df['BsmtQual'].isnull(), 1, 0)
df
frequent = df['BsmtQual'].mode()[0] #getting Most frequent category
df['BsmtQual'].fillna(frequent, inplace = True) #replacing most frequent item to null valuees in 'BsmtQual' df.head()
df['FireplaceQu_var'] = np.where(df['FireplaceQu'].isnull(),1, 0) frequent = df['FireplaceQu'].mode()[0] df['FireplaceQu'].fillna(frequent, inplace = True)
df.head()
Если у вас есть более частые категории, мы просто заменим NAN новой категорией.
Преимущества
1- Если у нас много нулевых значений, мы должны использовать эту технику.
Недостатки:
1- Многие функции появятся
df = pd.read_csv('house.csv', usecols = ['BsmtQual', 'FireplaceQu', 'GarageType', 'SalePrice'])
df.head()
def impute_NaN(df, variable): df[variable+'_var2'] = np.where(df[variable].isnull(),'Missing', df[variable])
for feature in ['BsmtQual', 'FireplaceQu', 'GarageType']: impute_NaN(df, feature)
df.head()
#Most use technique to replace nan with new category df = df.drop(['BsmtQual', 'FireplaceQu', 'GarageType'], axis = 1)
df