Типы отсутствующих данных

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