<jupyter_start><jupyter_text>Для выполнения этого задания вам понадобятся данные о кредитных историях клиентов одного из банков. Поля в предоставляемых данных имеют следующий смысл:* LIMIT_BAL: размер кредитного лимита (в том числе и на семью клиента)* SEX: пол клиента (1 = мужской, 2 = женский )* EDUCATION: образование (0 = доктор, 1 = магистр; 2 = бакалавр; 3 = выпускник школы; 4 = начальное образование; 5= прочее; 6 = нет данных ).* MARRIAGE: (0 = отказываюсь отвечать; 1 = замужем/женат; 2 = холост; 3 = нет данных).* AGE: возраст в годах* PAY_0 - PAY_6 : История прошлых платежей по кредиту. PAY_6 - платеж в апреле, ... Pay_0 - платеж в сентябре. Платеж = (0 = исправный платеж, 1=задержка в один месяц, 2=задержка в 2 месяца ...)* BILL_AMT1 - BILL_AMT6: задолженность, BILL_AMT6 - на апрель, BILL_AMT1 - на сентябрь* PAY_AMT1 - PAY_AMT6: сумма уплаченная в PAY_AMT6 - апреле, ..., PAY_AMT1 - сентябре* default - индикатор невозврата денежных средств  Задание 1 Размер кредитного лимита (LIMIT_BAL). В двух группах, тех людей, кто вернул кредит (default = 0) и тех, кто его не вернул (default = 1) проверьте гипотезы:* a) о равенстве медианных значений кредитного лимита с помощью подходящей интервальной оценки * b) о равенстве распределений с помощью одного из подходящих непараметрических критериев проверки равенства средних. Значимы ли полученные результаты с практической точки зрения ?<jupyter_code>%matplotlib inline
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use('ggplot')

import scipy
from scipy import stats

raw_data = pd.read_csv('credit_card_default_analysis.csv')
raw_data.head()
print 'Размер датасета: {}'.format(raw_data.shape)
d0_group = raw_data[raw_data['default']==0]
d1_group = raw_data[raw_data['default']==1]
fig, ax = plt.subplots(1, 2, figsize = (15, 5), sharey = True)
data = [d0_group, d1_group]
title = [u'Вернувшие кредит (default=0)',u'Невернувшие кредит (default=1)']
for i in range(2):
    ax[i].hist(data[i].LIMIT_BAL.values, bins = 20,ec = 'black');
    ax[i].axis([0, 1e6, 0, 6000])
    ax[i].set_xlabel(u'Размер кредитного лимита')
    ax[i].set_ylabel(u'Число людей')
    ax[i].set_title(title[i])<jupyter_output><empty_output><jupyter_text>**а) Найдем медианные значения распределений:** * Гипотеза H0 - медианы равны* Гипотеза Н1 - медианы различны<jupyter_code>print 'Медианное значение кредитного лимита для тех, кто вернул кредит: {}'.format(d0_group.LIMIT_BAL.median())
print 'Медианное значение кредитного лимита для тех, кто не вернул кредит: {}'.format(d1_group.LIMIT_BAL.median())<jupyter_output>Медианное значение кредитного лимита для тех, кто вернул кредит: 150000.0
Медианное значение кредитного лимита для тех, кто не вернул кредит: 90000.0<jupyter_text>Видно, что медианы различаются. Проверим доверительные интервалы распределений с помощью бутстрепа<jupyter_code>def get_bootstrap_samples(data, n_samples):
    indicies = np.random.randint(0, len(data), (n_samples, len(data)))
    samples = data[indicies]
    return samples
def get_stat_intervals(stat, alpha):
    boundaries = np.percentile(stat, [100*alpha/2., 100*(1-alpha/2.)])
    return boundaries
np.random.seed(0)
d0_median_scores = np.median(get_bootstrap_samples(d0_group.LIMIT_BAL.values, 1000), axis=0)
d1_median_scores =  np.median(get_bootstrap_samples(d1_group.LIMIT_BAL.values, 1000), axis=0)
delta_median_scores = map(lambda x: x[1] - x[0], zip(d0_median_scores, d1_median_scores))
print "95% доверительный интервал для группы вернувших кредит: {}".format(get_stat_intervals(d0_median_scores, 0.05))
print "95% доверительный интервал для группы не вернувших кредит: {}".format(get_stat_intervals(d1_median_scores, 0.05))
print '95% доверительный интервал для разности групп: {}'.format(get_stat_intervals(delta_median_scores, 0.05))<jupyter_output>95% доверительный интервал для группы вернувших кредит: [145000. 160000.]
95% доверительный интервал для группы не вернувших кредит: [ 80000. 100000.]
95% доверительный интервал для разности групп: [-80000. -50000.]<jupyter_text>Интервалы не пересекаются, интрервал разности находится левее нуля. Различие статистически значимо. Гипотеза Н0 отвергается Оценим практическую значимость<jupyter_code>Fc = d0_group.LIMIT_BAL.median()/d1_group.LIMIT_BAL.median()
print 'Fold change: ', np.round(Fc, 3)<jupyter_output>Fold change:  1.667<jupyter_text>Разница практически значима **б) Проверим равенство распределений с помощью критерия Манна - Уитни** * Гипотеза H0 - распределения одинаковы* Гипотеза Н1 - распределения отличаются на величину сдвига<jupyter_code>stats.mannwhitneyu(d0_group.LIMIT_BAL.values, d1_group.LIMIT_BAL.values)<jupyter_output><empty_output><jupyter_text>На уровне значимости 0.05 гипотеза H0 уверенно отвергается  Задание 2 Пол (SEX): Проверьте гипотезу о том, что гендерный состав группы людей вернувших и не вернувших кредит отличается. Хорошо, если вы предоставите несколько различных решений этой задачи (с помощью доверительного интервала и подходящего статистического критерия)<jupyter_code>fig, ax = plt.subplots(1, 2, figsize = (15, 5), sharey = True)
data = [d0_group, d1_group]
title = [u'Вернувшие кредит (default=0)',u'Невернувшие кредит (default=1)']
for i in range(2):
    ax[i].hist(data[i].SEX.values, bins = 20,ec = 'black');
    #ax[i].axis([0, 1e6, 0, 6000])
    ax[i].set_xlabel(u'Пол респодентов')
    ax[i].set_ylabel(u'Число людей')
    ax[i].set_title(title[i])<jupyter_output><empty_output><jupyter_text>* Гипотеза Н0 - гендерный состав в выборках не отличается* Гипотеза Н1 - гендерный состав различается Построим доверительный интервал и проверим гипотезу с помощью Z-критерия для доли двух независимых выборок<jupyter_code>def proportions_diff_confint_ind(sample1, sample2, alpha = 0.05):       
    z = scipy.stats.norm.ppf(1 - alpha / 2.)
    
    p1 = float(sum(sample1)) / len(sample1)
    p2 = float(sum(sample2)) / len(sample2)
    
    left_boundary = (p1 - p2) - z * np.sqrt(p1 * (1 - p1)/ len(sample1) + p2 * (1 - p2)/ len(sample2))
    right_boundary = (p1 - p2) + z * np.sqrt(p1 * (1 - p1)/ len(sample1) + p2 * (1 - p2)/ len(sample2))
    
    return (left_boundary, right_boundary)
def proportions_diff_z_stat_ind(sample1, sample2):
    
    n1 = len(sample1)
    n2 = len(sample2)
    
    p1 = float(sum(sample1)) / n1
    p2 = float(sum(sample2)) / n2 
    P = float(p1*n1 + p2*n2) / (n1 + n2)
    
    return (p1 - p2) / np.sqrt(P * (1 - P) * (1. / n1 + 1. / n2))
def proportions_diff_z_test(z_stat, alternative = 'two-sided'):
    
    if alternative not in ('two-sided', 'less', 'greater'):
        raise ValueError("alternative not recognized\n"
                         "should be 'two-sided', 'less' or 'greater'")
    
    if alternative == 'two-sided':
        return 2 * (1 - scipy.stats.norm.cdf(np.abs(z_stat)))
    
    if alternative == 'less':
        return scipy.stats.norm.cdf(z_stat)

    if alternative == 'greater':
        return 1 - scipy.stats.norm.cdf(z_stat)<jupyter_output><empty_output><jupyter_text>Закодируем доли для использования в функциях<jupyter_code>d0_zeros = np.zeros(len(d0_group[d0_group['SEX']==1].SEX.values))
d0_ones = np.ones(len(d0_group[d0_group['SEX']==2].SEX.values))

d1_zeros = np.zeros(len(d1_group[d1_group['SEX']==1].SEX.values))
d1_ones = np.ones(len(d1_group[d1_group['SEX']==2].SEX.values))

d0_group_sex_binary = np.concatenate([d0_zeros,d0_ones])
d1_group_sex_binary = np.concatenate([d1_zeros,d1_ones])
print len(d0_group_sex_binary), sum(d0_group_sex_binary)
print "95%% доверительный интервал: [%f, %f]" %\
      proportions_diff_confint_ind(d0_group_sex_binary, d1_group_sex_binary )<jupyter_output>95% доверительный интервал: [0.033635, 0.060548]<jupyter_text>Доверительный интервал не содержит нуля, гендерный состав отличается<jupyter_code>print "p-value: %f" % proportions_diff_z_test(proportions_diff_z_stat_ind(d0_group_sex_binary, d1_group_sex_binary))<jupyter_output>p-value: 0.000000<jupyter_text>Гипотеза Н0 уверенно отвергается  Задание 3 Образование (EDUCATION): Проверьте гипотезу о том, что образование не влияет на то, вернет ли человек долг. Предложите способ наглядного представления разницы в ожидаемых и наблюдаемых значениях количества человек вернувших и не вернувших долг. Например, составьте таблицу сопряженности "образование" на "возврат долга", где значением ячейки была бы разность между наблюдаемым и ожидаемым количеством человек. Как бы вы предложили модифицировать таблицу так, чтобы привести значения ячеек к одному масштабу не потеряв в интерпретируемости ? Наличие какого образования является наилучшим индикатором того, что человек отдаст долг ? наоборт, не отдаст долг ?<jupyter_code>fig, ax = plt.subplots(1, 2, figsize = (15, 5), sharey = True)
data = [d0_group, d1_group]
title = [u'Вернувшие кредит (default=0)',u'Невернувшие кредит (default=1)']
for i in range(2):
    ax[i].hist(data[i].EDUCATION.values, bins = 20,ec = 'black');
    #ax[i].axis([0, 1e6, 0, 6000])
    ax[i].set_xlabel(u'Уровень образования')
    ax[i].set_ylabel(u'Число людей')
    ax[i].set_title(title[i])<jupyter_output><empty_output><jupyter_text>Проверим взаимосвзяь данных с помощью критерия хи квадрат для критериальных признаков * Гипотеза Н0 - уровень образование не влияет на вероятность возврата долга* Гипотеза Н1 - уровень образования влияет на это<jupyter_code>table_edu = raw_data.pivot_table(index='default', 
     values="LIMIT_BAL", columns='EDUCATION', aggfunc = len, fill_value=0)
table_edu.head()
# stats.chi2_contingency(table_edu.values)
print 'Значение уровня значимости: ', stats.chi2_contingency(table_edu.values)[1]<jupyter_output>Значение уровня значимости:  8.825862457577375e-08<jupyter_text>Гипотеза H0 отвергается, влияние есть Отобразим диаграмму  ожидания/реальности при возврате долга<jupyter_code>table_delta = table_edu.values - stats.chi2_contingency(table_edu.values)[3]
fig, ax = plt.subplots(1, 2, figsize = (15, 5), sharey = True)
data = [table_delta[0], table_delta[1]]
label = ['0', '1', '2', '3', '4', '5', '6']
title = [u'Вернувшие кредит (default=0)',u'Невернувшие кредит (default=1)']
for i in range(2):
    ax[i].bar(label, data[i], ec = 'black');
    #ax[i].axis([0, 1e6, 0, 6000])
    ax[i].set_xlabel(u'Уровень образования')
    ax[i].set_ylabel(u'Величина отклонения')
    ax[i].set_title(title[i])<jupyter_output><empty_output><jupyter_text>Масштабируем признаки<jupyter_code>data_edu_scale = (table_edu.loc[0] - table_edu.loc[1])/(table_edu.loc[0]+table_edu.loc[1])
data_edu_scale.plot.bar(figsize = (15, 5))
plt.title(u'Соотношение кредитных выплат');<jupyter_output><empty_output><jupyter_text>Видно, что * хуже всего кредиты возвращают группы 2 и 3: выпускник и начальное образование* лучше всего кредиты возвращают респонденты из группы 0 -  доктора наук  Задание 4 Семейное положение (MARRIAGE): Проверьте, как связан семейный статус с индикатором дефолта: нужно предложить меру, по которой можно измерить возможную связь этих переменных и посчитать ее значение.<jupyter_code>fig, ax = plt.subplots(1, 2, figsize = (15, 5), sharey = True)
data = [d0_group, d1_group]
title = [u'Вернувшие кредит (default=0)',u'Невернувшие кредит (default=1)']
for i in range(2):
    ax[i].hist(data[i].MARRIAGE.values, bins = 20,ec = 'black');
    #ax[i].axis([0, 1e6, 0, 6000])
    ax[i].set_xlabel(u'Семейный статус')
    ax[i].set_ylabel(u'Число людей')
    ax[i].set_title(title[i])<jupyter_output><empty_output><jupyter_text>* гипотеза Н0 - данные связаны между собой* гипотеза Н1 - данные не связаны Оценим значимость взаимосвязи с помощью критерия  хи-квадрат обобщенного на случай критериальных признаков Подготовка матрицы сопряженности:<jupyter_code>table_mar = raw_data.pivot_table(index='default', 
     values="LIMIT_BAL", columns='MARRIAGE', aggfunc = len, fill_value=0)
table_mar.head()<jupyter_output><empty_output><jupyter_text>Вычислим V коэфициент Крамера<jupyter_code>def cramers_stat(confusion_matrix):  
    chi2 = stats.chi2_contingency(confusion_matrix)[0]
    n = confusion_matrix.sum()
    return np.sqrt(chi2 / (n*(min(confusion_matrix.shape)-1)))
print 'Значение V коэффициента Крамера: ', cramers_stat(table_mar.values)<jupyter_output>Значение V коэффициента Крамера:  0.034478203662766466<jupyter_text>Коэффициент близок к нулю, данные слабо коррелируют друг с другом<jupyter_code>print 'Значение уровня значимости: ', stats.chi2_contingency(table_mar)[1]<jupyter_output>Значение уровня значимости:  8.825862457577375e-08<jupyter_text>Гипотеза H0 отвергается, данные не связаны  Задание 5 Возраст (AGE): Относительно двух групп людей вернувших и не вернувших кредит проверьте следующие гипотезы: a) о равенстве медианных значений возрастов людей b) о равенстве распределений с помощью одного из подходящих непараметрических критериев проверки равенства средних. Значимы ли полученные результаты с практической точки зрения ?<jupyter_code>fig, ax = plt.subplots(1, 2, figsize = (15, 5), sharey = True)
data = [d0_group, d1_group]
title = [u'Вернувшие кредит (default=0)',u'Невернувшие кредит (default=1)']
for i in range(2):
    ax[i].hist(data[i].AGE.values, bins = 20,ec = 'black');
    #ax[i].axis([0, 1e6, 0, 6000])
    ax[i].set_xlabel(u'Возраст')
    ax[i].set_ylabel(u'Число людей')
    ax[i].set_title(title[i])<jupyter_output><empty_output><jupyter_text>**а) Найдем медианные значения распределений:** * Гипотеза H0 - медианы распределений  равны* Гипотеза Н1 - медианы распределений различны<jupyter_code>print 'Медианное значение возраста тех, кто вернул кредит: {}'.format(d0_group.AGE.median())
print 'Медианное значение возраста тех, кто не вернул кредит: {}'.format(d1_group.AGE.median())<jupyter_output>Медианное значение возраста тех, кто вернул кредит: 34.0
Медианное значение возраста тех, кто не вернул кредит: 34.0<jupyter_text>Медианы равны. Построим доверительные интревалы с помощью бутстрепа:<jupyter_code>np.random.seed(0)
d0_median_scores = np.median(get_bootstrap_samples(d0_group.AGE.values, 1000), axis=0)
d1_median_scores =  np.median(get_bootstrap_samples(d1_group.AGE.values, 1000), axis=0)
delta_median_scores = map(lambda x: x[1] - x[0], zip(d0_median_scores, d1_median_scores))
print "95% доверительный интервал для группы вернувших кредит: {}".format(get_stat_intervals(d0_median_scores, 0.05))
print "95% доверительный интервал для группы не вернувших кредит: {}".format(get_stat_intervals(d1_median_scores, 0.05))
print '95% доверительный интервал для разности групп: {}'.format(get_stat_intervals(delta_median_scores, 0.05))<jupyter_output>95% доверительный интервал для группы вернувших кредит: [33. 35.]
95% доверительный интервал для группы не вернувших кредит: [33. 35.]
95% доверительный интервал для разности групп: [-1.  2.]<jupyter_text>0 попадает в доверительный интревал разности, отвергунть гипотезу Н0 нельзя **б) Проверим равенство распределений с помощью критерия Манна - Уитни** * Гипотеза H0 - распределения одинаковы* Гипотеза Н1 - распределения отличаются на величину сдвига<jupyter_code>stats.mannwhitneyu(d0_group.AGE.values, d1_group.AGE.values)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11591993637327677, 'fraction_numerical': 0.03665164369034995, 'mean_word_length': 5.849296413980935, 'pattern_counts': {'":': 0, '<': 75, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '21', 'dir': 'jupyter-structured-clean-dedup', 'id': '344815', 'license': 'Apache-2.0', 'n_tokens_mistral': 6592, 'n_tokens_neox': 7097, 'n_words': 1342, 'path': 'coursera/ml_yandex/course4/course4week4/check/first.ipynb', 'repo_name': 'VadimKirilchuk/education', 'size': '15088'}