<jupyter_start><jupyter_text>SkillFactory Введение в ML, введение в sklearn В этом задании мы с вами рассмотрим данные с конкурса [Задача предсказания отклика клиентов ОТП Банка](http://www.machinelearning.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D0%BA%D0%B0%D0%B7%D0%B0%D0%BD%D0%B8%D1%8F_%D0%BE%D1%82%D0%BA%D0%BB%D0%B8%D0%BA%D0%B0_%D0%BA%D0%BB%D0%B8%D0%B5%D0%BD%D1%82%D0%BE%D0%B2_%D0%9E%D0%A2%D0%9F_%D0%91%D0%B0%D0%BD%D0%BA%D0%B0_%28%D0%BA%D0%BE%D0%BD%D0%BA%D1%83%D1%80%D1%81%29)<jupyter_code># Думаю, так удобнее :-)
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:95% !important; }</style>"))
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

%matplotlib inline

plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = (12,5)<jupyter_output><empty_output><jupyter_text>Грузим данные Считаем описание данных<jupyter_code>df_descr = pd.read_csv('data/otp_description.csv', sep='\t', encoding='utf8')
df_descr<jupyter_output><empty_output><jupyter_text>Считаем обучающую выборки и тестовую (которую мы как бы не видим)<jupyter_code>df_train = pd.read_csv('data/otp_train.csv', sep='\t', encoding='utf8')
df_train.shape
df_test = pd.read_csv('data/otp_test.csv', sep='\t', encoding='utf8')
df_test.shape
df_train.head()<jupyter_output><empty_output><jupyter_text>Объединим две выборкиТак как пока мы пока не умеем работать sklearn  Pipeline, то для того, чтобы после предобработки столбцы в двух выборках находились на своих местах.Для того, чтобы в дальнейшем отделить их введем новый столбец "sample"<jupyter_code>df_train.loc[:, 'sample'] = 'train'
df_test.loc[:, 'sample'] = 'test'
df = df_test.append(df_train).reset_index(drop=True)
df.shape<jupyter_output><empty_output><jupyter_text>Чуть-чуть посмотрим на данные Посмотрим типы данных и их заполняемость<jupyter_code>df.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 30133 entries, 0 to 30132
Data columns (total 53 columns):
AGREEMENT_RK                  30133 non-null int64
TARGET                        30133 non-null int64
AGE                           30133 non-null int64
SOCSTATUS_WORK_FL             30133 non-null int64
SOCSTATUS_PENS_FL             30133 non-null int64
GENDER                        30133 non-null int64
CHILD_TOTAL                   30133 non-null int64
DEPENDANTS                    30133 non-null int64
EDUCATION                     30133 non-null object
MARITAL_STATUS                30133 non-null object
GEN_INDUSTRY                  27420 non-null object
GEN_TITLE                     27420 non-null object
ORG_TP_STATE                  27420 non-null object
ORG_TP_FCAPITAL               27425 non-null object
JOB_DIR                       27420 non-null object
FAMILY_INCOME                 30133 non-null object
PERSONAL_INCOME               30133 non-null object
REG_ADDRESS_PRO[...]<jupyter_text>Видим, что часть данных - object, скорее всего стоки.Давайте выведем эти значения для каждого столбца<jupyter_code>for i in df_train.columns: # перебираем все столбцы
    if str(df_train[i].dtype) == 'object': # если тип столбца - object
        print('='*10)
        print(i) # выводим название столбца
        print(set(df_train[i])) # выводим все его значения (но делаем set - чтоб значения не повторялись)
        print('\n') # выводим пустую строку<jupyter_output>==========
EDUCATION
{'Высшее', 'Ученая степень', 'Среднее специальное', 'Неоконченное высшее', 'Неполное среднее', 'Среднее', 'Два и более высших образования'}


==========
MARITAL_STATUS
{'Разведен(а)', 'Не состоял в браке', 'Гражданский брак', 'Состою в браке', 'Вдовец/Вдова'}


==========
GEN_INDUSTRY
{nan, 'Транспорт', 'Туризм', 'Строительство', 'Ресторанный бизнес/Общественное питание', 'Банк/Финансы', 'Сборочные производства', 'Подбор персонала', 'Информационные услуги', 'Нефтегазовая промышленность', 'Маркетинг', 'ЧОП/Детективная д-ть', 'Торговля', 'Государственная служба', 'Энергетика', 'Металлургия/Промышленность/Машиностроение', 'Сельское хозяйство', 'Образование', 'Недвижимость', 'Управляющая компания', 'Страхование', 'Логистика', 'Развлечения/Искусство', 'СМИ/Реклама/PR-агенства', 'Наука', 'Информационные технологии', 'Здравоохранение', 'Химия/Парфюмерия/Фармацевтика', 'Салоны красоты и здоровья', 'Коммунальное хоз-во/Дорожные службы', 'Юридические услуги/нотариальные услу[...]<jupyter_text>Mожно заметить что некоторые переменные, которые обозначены как строки (например PERSONAL_INCOME) на самом деле числа, но по какой-то причине были распознаны как строкиПричина же что использовалась запятая для разделения не целой части числа.. Перекодировать их можно например так:<jupyter_code>df['PERSONAL_INCOME'].map(lambda x: x.replace(',', '.')).astype('float')<jupyter_output><empty_output><jupyter_text>Такой эффект наблюдается в столбцах `PERSONAL_INCOME`, `CREDIT`, `FST_PAYMENT`, `LOAN_AVG_DLQ_AMT`, `LOAN_MAX_DLQ_AMT`  Теперь ваше небольшое исследование  Задание 1. Есть ли пропуски в данных? Что с ними сделать?(единственного верного ответа нет - аргументируйте)  Ответ:Из результатов выше, мы знаем, что есть пропущенные значения. Посчитаем число пропусков в данных.<jupyter_code>nan_vals_count = df.isnull().sum()
nan_vals_count.iloc[nan_vals_count.nonzero()[0]]
def show_data(dataframe, columns=None):
    for i in df_train.columns if columns is None else columns: # перебираем столбцы
        print('='*10)
        print(i) # выводим название столбца
        print(set(df_train[i])) # выводим все его значения (но делаем set - чтоб значения не повторялись)
        print('\n') # выводим пустую строку
        
columns_with_na = ['GEN_INDUSTRY', 'GEN_TITLE', 'ORG_TP_STATE', 'ORG_TP_FCAPITAL', 'JOB_DIR', 'TP_PROVINCE', 'REGION_NM', 'WORK_TIME']
show_data(df, columns_with_na)<jupyter_output>==========
GEN_INDUSTRY
{nan, 'Транспорт', 'Туризм', 'Строительство', 'Ресторанный бизнес/Общественное питание', 'Банк/Финансы', 'Сборочные производства', 'Подбор персонала', 'Информационные услуги', 'Нефтегазовая промышленность', 'Маркетинг', 'ЧОП/Детективная д-ть', 'Торговля', 'Государственная служба', 'Энергетика', 'Металлургия/Промышленность/Машиностроение', 'Сельское хозяйство', 'Образование', 'Недвижимость', 'Управляющая компания', 'Страхование', 'Логистика', 'Развлечения/Искусство', 'СМИ/Реклама/PR-агенства', 'Наука', 'Информационные технологии', 'Здравоохранение', 'Химия/Парфюмерия/Фармацевтика', 'Салоны красоты и здоровья', 'Коммунальное хоз-во/Дорожные службы', 'Юридические услуги/нотариальные услуги', 'Другие сферы'}


==========
GEN_TITLE
{'Рабочий', 'Руководитель среднего звена', 'Индивидуальный предприниматель', nan, 'Военнослужащий по контракту', 'Служащий', 'Другое', 'Партнер', 'Работник сферы услуг', 'Высококвалифиц. специалист', 'Руководитель высшего звена', 'Руководи[...]<jupyter_text>Задание 2. Есть ли категориальные признаки? Что с ними делать? Есть и их нужно закодировать.  Задание 3. Фунция предобработки Напишите функцию, которая бы* Удаляло идентификатор `AGREEMENT_RK`* Избавлялась от проблем с '.' и ',' в стобцах PERSONAL_INCOME, CREDIT, FST_PAYMENT, LOAN_AVG_DLQ_AMT, LOAN_MAX_DLQ_AMT* Что-то делала с пропусками* Кодировала категориальные признакиВ результате, ваш датафрейм должен содержать только числа и не содержать пропусков!<jupyter_code>def preproc_data(df_input):
    df_output = df_input.copy()    
    
    ## Your Code Here
    df_output = df_output.drop(['AGREEMENT_RK'], axis=1)
    
    columns_to_fix = ['PERSONAL_INCOME', 'CREDIT', 'FST_PAYMENT', 'LOAN_AVG_DLQ_AMT', 'LOAN_MAX_DLQ_AMT']
    
    for column in columns_to_fix:
        df_output[column] = df_output[column].map(lambda x: x.replace(',', '.')).astype('float')
    
    family_income_list = ['до 5000 руб.', 'от 5000 до 10000 руб.', 'от 10000 до 20000 руб.', 'от 20000 до 50000 руб.', 'свыше 50000 руб.']
     
    for idx, val in enumerate(family_income_list):
        df_output['FAMILY_INCOME'].replace(to_replace = val, value="{}".format(idx), inplace=True)
    
    df_output['FAMILY_INCOME'] = df_output.FAMILY_INCOME.astype('int64')
    
    df_output.WORK_TIME[df_output.WORK_TIME.isnull()] = df_output.WORK_TIME.mean()
    
    df_output = pd.get_dummies(df_output, columns=['EDUCATION', 'MARITAL_STATUS'])
    
    df_output = df_output.drop(['GEN_INDUSTRY', 'GEN_TITLE', 'ORG_TP_STATE', 'ORG_TP_FCAPITAL', 'JOB_DIR', 'TP_PROVINCE', 'REGION_NM',
                                'REG_ADDRESS_PROVINCE', 'FACT_ADDRESS_PROVINCE', 'POSTAL_ADDRESS_PROVINCE', 'PREVIOUS_CARD_NUM_UTILIZED'], axis=1)
    
    return df_output
df_preproc = df.pipe(preproc_data)

df_train_preproc = df_preproc.query('sample == "train"').drop(['sample'], axis=1)
df_test_preproc = df_preproc.query('sample == "test"').drop(['sample'], axis=1)<jupyter_output>/home/am0z/miniconda3/envs/sfml/lib/python3.6/site-packages/ipykernel_launcher.py:19: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy<jupyter_text>Задание 4. Отделите целевую переменную и остальные признакиДолжно получится:* 2 матрицы: X и X_test* 2 вектора: y и y_test<jupyter_code>y = df_train_preproc['TARGET']
X = df_train_preproc.drop('TARGET', axis=1)

y_test = df_test_preproc['TARGET']
X_test = df_test_preproc.drop('TARGET', axis=1)<jupyter_output><empty_output><jupyter_text>Задание 5. Обучение и оценка качества разных моделей<jupyter_code>from sklearn.model_selection import train_test_split
# test_size=0.3, random_state=42

## Your Code Here
target = df_preproc['TARGET']
X = df_preproc.drop(['sample', 'TARGET'], axis=1)

X_train, X_test, y_train, y_test = train_test_split(X, target, test_size=0.3, random_state=42)

# Попробовать следующие "черные ящики": интерфейс одинаковый 
#     fit, 
#     predict, 
#     predict_proba

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression

## Your Code Here
dtc = DecisionTreeClassifier()
dtc.fit(X_train, y_train)
predict_dtc = dtc.predict(X_test)
predict_proba_dtc  = dtc.predict_proba(X_test)

rfc = RandomForestClassifier()
rfc.fit(X_train, y_train)
predict_rfc = rfc.predict(X_test)
predict_proba_rfc = rfc.predict(X_test)

lr = LogisticRegression()
lr.fit(X_train, y_train)
predict_lr = lr.predict(X_test)
predict_proba_lr = lr.predict_proba(X_test)

# Посчитать метрики стандартные
# accuracy, precision, recall

from sklearn.metrics import accuracy_score, precision_score, recall_score

## Your Code Here
print('DecisionTreeClassifier:')
print('precision', precision_score(y_test, predict_dtc))
print('recall', recall_score(y_test, predict_dtc))
print('accuracy', accuracy_score(y_test, predict_dtc))
print('='*10)

print('RandomForestClassifier')
print('precision: {}'.format(precision_score(y_test, predict_rfc)))
print('recall: {}'.format(recall_score(y_test, predict_rfc)))
print('accuracy: {}'.format(accuracy_score(y_test, predict_rfc)))
print('='*10)

print('LogisticRegression')
print('precision: {}'.format(precision_score(y_test, predict_lr)))
print('recall: {}'.format(recall_score(y_test, predict_lr)))
print('accuracy: {}'.format(accuracy_score(y_test, predict_lr)))
print('='*10)

# Визуалищировать эти метрики всех моделей на одном графике (чтоб визуально посмотреть)

## Your Code Here
from matplotlib import pyplot as plt
%matplotlib inline

fig, ax = plt.subplots(figsize=(15,10))

precision1 = precision_score(y_test, predict_dtc)
precision2 = precision_score(y_test, predict_rfc)
precision3 = precision_score(y_test, predict_lr)

recall1 = recall_score(y_test, predict_dtc)
recall2 = recall_score(y_test, predict_rfc)
recall3 = recall_score(y_test, predict_lr)

accuracy1 = accuracy_score(y_test, predict_dtc)
accuracy2 = accuracy_score(y_test, predict_rfc)
accuracy3 = accuracy_score(y_test, predict_lr)

fd = pd.DataFrame([[precision1, precision2, precision3],[recall1, recall2, recall3], [accuracy1, accuracy2, accuracy3]],
                 index=['precision', 'recall', 'accuracy'], columns=pd.Index(['DecisionTreeClassifier','RandomForestClassifier','LogisticRegression'])).plot(kind='bar', ax=ax)
from sklearn.metrics import roc_curve, auc
plt.figure(figsize=(10, 7))

fpr, tpr, thresholds = roc_curve(y_test, predict_proba_lr[:,1])
roc_auc  = auc(fpr, tpr)
plt.plot(fpr, tpr, label='%s ROC (area = %0.2f)' % ('LR', roc_auc))

fpr2, tpr2, thresholds2 = roc_curve(y_test, predict_proba_dtc[:,1])
roc_auc2  = auc(fpr2, tpr2)
plt.plot(fpr2, tpr2, label='%s ROC (area = %0.2f)' % ('DTC', roc_auc2))

fpr3, tpr3, thresholds3 = roc_curve(y_test, predict_proba_rfc)
roc_auc3  = auc(fpr3, tpr3)
plt.plot(fpr3, tpr3, label='%s ROC (area = %0.2f)' % ('RFC', roc_auc3))

plt.plot([0, 1], [0, 1])
plt.ylabel('tpr')
plt.xlabel('fpr')
plt.grid(True)
plt.title('ROC curve')
plt.xlim((-0.01, 1.01))
plt.ylim((-0.01, 1.01))
plt.legend(loc=0, fontsize='small')
from sklearn.cross_validation import cross_val_score
from sklearn.model_selection import StratifiedKFold
# Сделать k-fold (10 фолдов) кросс-валидацию каждой модели
# И посчитать средний roc_auc
skf = StratifiedKFold(n_splits=10, shuffle=True, random_state=123)

## Your Code Here
print('dtc: ', cross_val_score(dtc, X_train, y_train, scoring='roc_auc', cv=10))
print('rfc: ', cross_val_score(rfc, X_train, y_train, scoring='roc_auc', cv=10))
print('lr: ', cross_val_score(lr, X_train, y_train, scoring='roc_auc', cv=10))

print('dtc- mean: ', np.mean(cross_val_score(dtc, X_train, y_train, scoring='roc_auc', cv=10)))
print('rfc- mean: ', np.mean(cross_val_score(rfc, X_train, y_train, scoring='roc_auc', cv=10)))
print('lr- mean: ', np.mean(cross_val_score(lr, X_train, y_train, scoring='roc_auc', cv=10)))
# Взять лучшую модель и сделать predict (с вероятностями (!!!)) для test выборки


## Your Code Here
predict_lr_test = lr.predict_proba(X_test)
print(predict_lr_test)
# Померить roc_auc на тесте
print('lr: ', cross_val_score(lr, X_test, y_test, scoring='roc_auc', cv=10))<jupyter_output>lr:  [0.57382094 0.61460966 0.64903352 0.62927702 0.58218222 0.6147366
 0.65449195 0.64028619 0.65645375 0.65658048]
{'fraction_non_alphanumeric': 0.13270909602928752, 'fraction_numerical': 0.03323007603491974, 'mean_word_length': 5.79665071770335, 'pattern_counts': {'":': 1, '<': 43, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 1, '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': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '496510', 'license': 'MIT', 'n_tokens_mistral': 6112, 'n_tokens_neox': 6235, 'n_words': 1101, 'path': 'hw_02/ml-intro-hw.ipynb', 'repo_name': 'AndrewCr0w/sfml', 'size': '14204'}