<jupyter_start><jupyter_text>Задание 1<jupyter_code>a = data['LIMIT_BAL'][data['default'] == 0]
b = data['LIMIT_BAL'][data['default'] == 1]
plt.hist(a, label = 'default = 0')
plt.hist(b, label = 'default = 1')
plt.legend()
# делаем бустрэп

def get_bootstrap_samples(sample1, sample2, n_samples):
    
    a = []
    b = []
    
    for i in range(n_samples):
    
        indices1 = np.random.randint(0, len(sample1), len(sample1))
        indices2 = np.random.randint(0, len(sample2), len(sample2))
    
        a.append(np.median(np.array(sample1)[(indices1)]))
        b.append(np.median(np.array(sample2)[(indices2)]))
    
    return a, b

def stat_intervals(stat, alpha):
    boundaries = np.percentile(stat, [100 * alpha / 2., 100 * (1 - alpha / 2.)])
    return boundaries
a1, b1 = get_bootstrap_samples(a, b, 500)
a1 = np.array(a1)
b1 = np.array(b1)
# считаем доверительный интервал разности медиан

stat_intervals(a1 - b1, 0.05)
# используем критерий Манна-Уитни, чтобы определить p-value гипотезы равенства средних

stats.mannwhitneyu(a, b)<jupyter_output><empty_output><jupyter_text>Как видно, доверительный интервал разности медиан не содержит ноль, значит медианы не равны. Также критерий Манна-Уитни отвергает гипотезу о равенстве средних (в смысле сдвига отсутствия сдвига функций распределения). Результат практически значим: у людей, возвращающих кредиты, кредитный лимит выше. Это адекватно даже с точки зрения здравого смысла.  Задание 2<jupyter_code>a = data['SEX'][data['default'] == 0]-1
b = data['SEX'][data['default'] == 1]-1
plt.hist(a, label = 'default = 0')
plt.hist(b, label = 'default = 1')
plt.legend()
# считаем доверительный интервал для разности долей

def proportions_confint_diff_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)
proportions_confint_diff_ind(a, b)
# считаем p-value

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))
2 * (1 - stats.norm.cdf(np.abs(proportions_diff_z_stat_ind(a, b))))<jupyter_output><empty_output><jupyter_text>Доверительный интервал для разности долей не содержит ноль,  а p-value очень мало, значит гендерный состав групп отличается  Задание 3<jupyter_code>a = data['EDUCATION'][data['default'] == 0]
b = data['EDUCATION'][data['default'] == 1]
plt.hist(a, label = 'default = 0')
plt.hist(b, label = 'default = 1')
plt.legend()
# считаем долю тех, кто не вернул кредит для каждой образовательной группы

shares1 = []
shares2 = []

for j in list(data['EDUCATION'].value_counts().sort_index().axes[0]):
    
    shares1.append(data[(data['EDUCATION']==j)&(data['default']==0)].shape[0])
    shares2.append(data[(data['EDUCATION']==j)&(data['default']==1)].shape[0])
    
shares1 = np.array(shares1)
shares2 = np.array(shares2)
shares = shares2/(shares1 + shares2)
plt.plot([0,1,2,3,4,5,6], shares)
# сделаем contigency table и проверим с момощью chi2

k = np.array([shares1, shares2]).T
stat = stats.chi2_contingency(k)
stat
# построим графики предсказанных разностей между числом вернувших и не вернувших

plt.plot([0,1,2,3,4,5,6], stat[3][:, 0] - stat[3][:,1], label = 'Предсказание')
plt.plot([0,1,2,3,4,5,6], shares1 - shares2, label = 'Данные')
plt.legend()
# а теперь графики долей числа не вернувших

plt.plot([0,1,2,3,4,5,6], stat[3][:,1]/(stat[3][:, 0] + stat[3][:,1]), label = 'Предсказание')
plt.plot([0,1,2,3,4,5,6], shares, label = 'Данные')
plt.legend()
# считаем коэффициент Крамера

np.sqrt(stat[0]/np.sum(k))<jupyter_output><empty_output><jupyter_text>Видно, что хи квадрат предсказывает, что примерно 22 процента не вернут кредит, если возврат не зависит от образования. Однако, судя по p-value, это не так. Даже если взять только 1, 2 и 3 уровни образования, то p-value все еще пренебрежимо мал, хотя на последнем графике появляется ощущение, что там просто 22 процента независимо от образования не возвращают (плюс-минус). Возможно, это неверно, но я считаю, что 22 процента могут являться ОЧЕНЬ грубым прогнозом для невозврата, если учитывать ТОЛЬКО уровень образования, так как коэффициент Крамера достаточно мал.  Задание 4<jupyter_code>a = data['MARRIAGE'][data['default'] == 0]
b = data['MARRIAGE'][data['default'] == 1]

plt.hist(a, label = 'default = 0')
plt.hist(b, label = 'default = 1')
plt.legend()
shares1 = []
shares2 = []

for j in list(data['MARRIAGE'].value_counts().sort_index().axes[0]):
    
    shares1.append(data[(data['MARRIAGE']==j)&(data['default']==0)].shape[0])
    shares2.append(data[(data['MARRIAGE']==j)&(data['default']==1)].shape[0])
    
shares1 = np.array(shares1)
shares2 = np.array(shares2)
shares = shares2/(shares1 + shares2)
# делаем опять contigency

k = np.array([shares1, shares2]).T
stat = stats.chi2_contingency(k)
stat
np.sqrt(stat[0]/np.sum(k))<jupyter_output><empty_output><jupyter_text>Здесь ситуация полностью аналогичная предыдущей. Вроде как распределение и не равномерное, но зависимость возврата от признака слабая  Задание 5<jupyter_code>a = data['AGE'][data['default'] == 0]
b = data['AGE'][data['default'] == 1]

plt.hist(a, label = 'default = 0')
plt.hist(b, label = 'default = 1')
plt.legend()
np.median(a) - np.median(b)
# строим интервальную оценку разности медиан, используя бутсрэп (копипаст с 1 задания)
a1, b1 = get_bootstrap_samples(a, b, 500)
a1 = np.array(a1)
b1 = np.array(b1)

stat_intervals(a1 - b1, 0.05)
stats.mannwhitneyu(a, b)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15956192080876158, 'fraction_numerical': 0.039764111204717775, 'mean_word_length': 4.77431906614786, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, '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': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '108820', 'license': 'MIT', 'n_tokens_mistral': 2608, 'n_tokens_neox': 2714, 'n_words': 530, 'path': 'Yandex data science/4/Week 4/Credit_scoring.ipynb', 'repo_name': 'PupochekRus/Courses', 'size': '5935'}