В задании вам будет предложено ознакомиться с основными техниками предобработки данных, а так же применить их для обучения модели логистической регрессии. Ответ потребуется загрузить в соответствующую форму в виде 6 текстовых файлов.
In [1]:
import pandas as pd
import numpy as np
import matplotlib
from matplotlib import pyplot as plt
matplotlib.style.use('ggplot')
%matplotlib inline
Задача: по 38 признакам, связанных с заявкой на грант (область исследований учёных, информация по их академическому бэкграунду, размер гранта, область, в которой он выдаётся) предсказать, будет ли заявка принята. Датасет включает в себя информацию по 6000 заявкам на гранты, которые были поданы в университете Мельбурна в период с 2004 по 2008 год.
Полную версию данных с большим количеством признаков можно найти на https://www.kaggle.com/c/unimelb.
In [2]:
data = pd.read_csv('data.csv')
data.shape
Out[2]:
In [3]:
X = data.drop('Grant.Status', 1)
y = data['Grant.Status']
Базовым этапом в предобработке любого датасета для логистической регрессии будет кодирование категориальных признаков, а так же удаление или интерпретация пропущенных значений (при наличии того или другого).
In [4]:
data.head()
Out[4]:
Видно, что в датасете есть как числовые, так и категориальные признаки. Получим списки их названий:
In [5]:
numeric_cols = ['RFCD.Percentage.1', 'RFCD.Percentage.2', 'RFCD.Percentage.3',
'RFCD.Percentage.4', 'RFCD.Percentage.5',
'SEO.Percentage.1', 'SEO.Percentage.2', 'SEO.Percentage.3',
'SEO.Percentage.4', 'SEO.Percentage.5',
'Year.of.Birth.1', 'Number.of.Successful.Grant.1', 'Number.of.Unsuccessful.Grant.1']
categorical_cols = list(set(X.columns.values.tolist()) - set(numeric_cols))
Также в нём присутствуют пропущенные значения. Очевидны решением будет исключение всех данных, у которых пропущено хотя бы одно значение. Сделаем это:
In [6]:
data.dropna().shape
Out[6]:
Видно, что тогда мы выбросим почти все данные, и такой метод решения в данном случае не сработает.
Пропущенные значения можно так же интерпретировать, для этого существует несколько способов, они различаются для категориальных и вещественных признаков.
Для вещественных признаков:
Для категориальных:
In [1]:
def calculate_means(numeric_data):
means = np.zeros(numeric_data.shape[1])
for j in range(numeric_data.shape[1]):
to_sum = numeric_data.iloc[:,j]
indices = np.nonzero(~numeric_data.iloc[:,j].isnull())[0]
correction = np.amax(to_sum[indices])
to_sum /= correction
for i in indices:
means[j] += to_sum[i]
means[j] /= indices.size
means[j] *= correction
return pd.Series(means, numeric_data.columns)
In [10]:
means = calculate_means(X[numeric_cols])
In [11]:
means['RFCD.Percentage.1']
Out[11]:
In [12]:
def NanChZero(datafr):
datawork = datafr
for item in datawork.columns:
datawork[item].fillna(0, inplace=True)
return datawork
def NanChMeans(datafr):
datawork = datafr
means = calculate_means(X[numeric_cols])
for item in datawork.columns:
datawork[item].fillna(means[item], inplace=True)
return datawork
X_real_zeros=X[numeric_cols].fillna(0)
X_real_mean=NanChMeans(X[numeric_cols])
In [14]:
def NanChNA(datafr):
datawork = datafr
for item in datawork.columns:
datawork[item].fillna('NA', inplace=True)
for item in datawork.columns:
datawork[item]=datawork[item].astype(str)
return datawork
X_cat = X[categorical_cols].applymap(str).fillna('NA')
В предыдущей ячейке мы разделили наш датасет ещё на две части: в одной присутствуют только вещественные признаки, в другой только категориальные. Это понадобится нам для раздельной последующей обработке этих данных, а так же для сравнения качества работы тех или иных методов.
Для использования модели регрессии требуется преобразовать категориальные признаки в вещественные. Основной способ преоборазования категориальных признаков в вещественные: one-hot encoding. Его идея заключается в том, что мы преобразуем категориальный признак при помощи бинарного кода: каждой категории ставим в соответствие набор из нулей и единиц.
In [16]:
encoder = DV(sparse = False)
X_cat_oh = encoder.fit_transform(X_cat.T.to_dict().values())
Для построения метрики качества по результату обучения требуется разделить исходный датасет на обучающую и тестовую выборки.
In [17]:
from sklearn.cross_validation import train_test_split
(X_train_real_zeros,
X_test_real_zeros,
y_train, y_test) = train_test_split(X_real_zeros, y,
test_size=0.3,
random_state=0)
(X_train_real_mean,
X_test_real_mean) = train_test_split(X_real_mean,
test_size=0.3,
random_state=0)
(X_train_cat_oh,
X_test_cat_oh) = train_test_split(X_cat_oh,
test_size=0.3,
random_state=0)
Вообще говоря, не вполне логично оптимизировать на кросс-валидации заданный по умолчанию в классе логистической регрессии функционал accuracy, а измерять на тесте AUC ROC, но это, как и ограничение размера выборки, сделано для ускорения работы процесса кросс-валидации.
In [20]:
from sklearn.linear_model import LogisticRegression
from sklearn.grid_search import GridSearchCV
from sklearn.metrics import roc_auc_score
def plot_scores(optimizer):
scores = [[item[0]['C'],
item[1],
(np.sum((item[2]-item[1])**2)/(item[2].size-1))**0.5] for item in optimizer.grid_scores_]
scores = np.array(scores)
plt.semilogx(scores[:,0], scores[:,1])
plt.fill_between(scores[:,0], scores[:,1]-scores[:,2],
scores[:,1]+scores[:,2], alpha=0.3)
plt.show()
def write_answer_1(auc_1, auc_2):
auc = (auc_1 + auc_2)/2
with open("preprocessing_lr_answer1.txt", "w") as fout:
fout.write(str(auc))
param_grid = {'C': [0.01, 0.05, 0.1, 0.5, 1, 5, 10]}
cv = 3
In [21]:
dataZeros_train = np.hstack((X_train_real_zeros,X_train_cat_oh))
dataZeros_test = np.hstack((X_test_real_zeros,X_test_cat_oh))
dataMean_train =np.hstack((X_train_real_mean,X_train_cat_oh))
dataMean_test =np.hstack((X_test_real_mean,X_test_cat_oh))
In [22]:
estimator=LogisticRegression(penalty='l2', random_state = 0, class_weight='balanced', n_jobs=4)
optimizer = GridSearchCV(estimator, param_grid, scoring = 'accuracy', cv=cv)
optimizer.fit(dataZeros_train,y_train)
print 'Метки функции предсказаний:\n'
print y_test[:10]
print optimizer.predict(dataZeros_test)[:10]
print 'Вероятности(т.к. функция логистическая):\n'
print optimizer.predict_proba(dataZeros_test)[:10]
print 'Лучшая функция:\n'
print optimizer.best_estimator_
print 'Коэффициенты лучшей функции:\n'
print optimizer.best_estimator_.coef_
print 'Лучший параметр функции:\n'
print optimizer.best_params_
plot_scores(optimizer)
auc_zeros=roc_auc_score(y_test, optimizer.predict_proba(dataZeros_test)[:,1])
print auc_zeros
In [23]:
estimator=LogisticRegression(penalty='l2', random_state = 0, class_weight='balanced', n_jobs=4)
optimizer = GridSearchCV(estimator, param_grid, scoring = 'accuracy', cv=cv)
optimizer.fit(dataMean_train,y_train)
print 'Метки функции предсказаний:\n'
print y_test[:10]
print optimizer.predict(dataMean_test)[:10]
print 'Вероятности(т.к. функция логистическая):\n'
print optimizer.predict_proba(dataMean_test)[:10]
print optimizer.predict_proba(dataMean_test)[:,1]
print 'Лучшая функция:\n'
print optimizer.best_estimator_
print 'Коэффициенты лучшей функции:\n'
print optimizer.best_estimator_.coef_
print 'Лучший параметр функции:\n'
print optimizer.best_params_
plot_scores(optimizer)
auc_mean=roc_auc_score(y_test, optimizer.predict_proba(dataMean_test)[:,1])
print auc_mean
In [24]:
estimator=LogisticRegression(penalty='l2', random_state = 0, class_weight='balanced', n_jobs=4)
optimizer = GridSearchCV(estimator, param_grid, scoring = 'accuracy', cv=cv)
optimizer.fit(X_train_cat_oh,y_train)
print 'Метки функции предсказаний:\n'
print y_test[:10]
print optimizer.predict(X_test_cat_oh)[:10]
print 'Вероятности(т.к. функция логистическая):\n'
print optimizer.predict_proba(X_test_cat_oh)[:10]
print 'Лучшая функция:\n'
print optimizer.best_estimator_
print 'Коэффициенты лучшей функции:\n'
print optimizer.best_estimator_.coef_
print 'Лучший параметр функции:\n'
print optimizer.best_params_
plot_scores(optimizer)
roc_auc_score(y_test, optimizer.predict_proba(X_test_cat_oh)[:,1])
Out[24]:
In [26]:
auc_zeros
Out[26]:
In [27]:
auc_mean
Out[27]:
In [28]:
write_answer_1(auc_zeros, auc_mean)
Попробуем улучшить качество классификации.
In [30]:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_real_scaled=scaler.fit_transform(X_train_real_mean)
X_train_real_scaled=scaler.transform(X_train_real_scaled)
X_test_real_scaled=scaler.fit_transform(X_test_real_mean)
X_test_real_scaled=scaler.transform(X_test_real_scaled)
In [31]:
X_test_real_scaled
Out[31]:
In [32]:
data_numeric_scaled = pd.DataFrame(X_train_real_scaled, columns=numeric_cols)
list_cols = ['Number.of.Successful.Grant.1', 'SEO.Percentage.2', 'Year.of.Birth.1']
scatter_matrix(data_numeric_scaled[list_cols], alpha=0.5, figsize=(10, 10))
plt.show()
Как видно из графиков, мы не поменяли свойства признакового пространства: гистограммы распределений значений признаков, как и их scatter-plots, выглядят так же, как и до нормировки, но при этом все значения теперь находятся примерно в одном диапазоне, тем самым повышая интерпретабельность результатов, а также лучше сочетаясь с идеологией регуляризации.
In [33]:
dataMean_train =np.hstack((X_train_real_scaled,X_train_cat_oh))
dataMean_test =np.hstack((X_test_real_scaled,X_test_cat_oh))
In [34]:
estimator=LogisticRegression(penalty='l2', random_state = 0, n_jobs=4)
optimizer = GridSearchCV(estimator, param_grid, scoring = 'accuracy', cv=cv)
optimizer.fit(dataMean_train,y_train)
print 'Метки функции предсказаний:\n'
print y_test[:10]
print optimizer.predict(dataMean_test)[:10]
print 'Вероятности(т.к. функция логистическая):\n'
print optimizer.predict_proba(dataMean_test)[:10]
print optimizer.predict_proba(dataMean_test)[:,1]
print 'Лучшая функция:\n'
print optimizer.best_estimator_
print 'Коэффициенты лучшей функции:\n'
print optimizer.best_estimator_.coef_
print 'Лучший параметр функции:\n'
print optimizer.best_params_
plot_scores(optimizer)
auc_mean=roc_auc_score(y_test, optimizer.predict_proba(dataMean_test)[:,1])
print auc_mean
In [35]:
def write_answer_2(auc):
with open("preprocessing_lr_answer2.txt", "w") as fout:
fout.write(str(auc))
write_answer_2(auc_mean)
np.random.seed(0)
indices_to_add = np.random.randint(...)
X_train_to_add = X_train[y_train.as_matrix() == 1,:][indices_to_add,:]
После этого добавьте эти объекты в начало или конец обучающей выборки. Дополните соответствующим образом вектор ответов.
In [38]:
dataMean_train =np.hstack((X_train_real_scaled,X_train_cat_oh))
dataMean_test =np.hstack((X_test_real_scaled,X_test_cat_oh))
estimator=LogisticRegression(penalty='l2', random_state = 0, class_weight='balanced', n_jobs=4)
optimizer = GridSearchCV(estimator, param_grid, scoring = 'accuracy', cv=cv)
optimizer.fit(dataMean_train,y_train)
print 'Метки функции предсказаний:\n'
print y_test[:10]
print optimizer.predict(dataMean_test)[:10]
print 'Вероятности(т.к. функция логистическая):\n'
print optimizer.predict_proba(dataMean_test)[:10]
print optimizer.predict_proba(dataMean_test)[:,1]
print 'Лучшая функция:\n'
print optimizer.best_estimator_
print 'Коэффициенты лучшей функции:\n'
print optimizer.best_estimator_.coef_
print 'Лучший параметр функции:\n'
print optimizer.best_params_
plot_scores(optimizer)
auc_mean_2=roc_auc_score(y_test, optimizer.predict_proba(dataMean_test)[:,1])
print auc_mean_2
In [39]:
np.random.seed(0)
number_to_add = np.sum(y_train==0)-np.sum(y_train==1)
indices_to_add = np.random.randint(np.sum(y_train==1), size = number_to_add)
X_train_to_add = dataMean_train[y_train.as_matrix() == 1,:][indices_to_add,:]
X_train_enhanced=np.append(dataMean_train,X_train_to_add, axis=0)
y_train_enhanced=np.append(y_train,(np.ones((number_to_add,1))))
print X_train_enhanced.shape
print y_train_enhanced.shape
In [40]:
estimator=LogisticRegression(penalty='l2', random_state = 0, class_weight='balanced', n_jobs=4)
optimizer = GridSearchCV(estimator, param_grid, scoring = 'accuracy', cv=cv)
optimizer.fit(X_train_enhanced,y_train_enhanced)
print 'Метки функции предсказаний:\n'
print y_test[:10]
print optimizer.predict(dataMean_test)[:10]
print 'Лучшая функция:\n'
print optimizer.best_estimator_
print 'Коэффициенты лучшей функции:\n'
print optimizer.best_estimator_.coef_
print 'Лучший параметр функции:\n'
print optimizer.best_params_
plot_scores(optimizer)
auc_mean_enhanced=roc_auc_score(y_test, optimizer.predict_proba(dataMean_test)[:,1])
print auc_mean_enhanced
In [41]:
def write_answer_3(auc_1, auc_2):
auc = (auc_1 + auc_2) / 2
with open("preprocessing_lr_answer3.txt", "w") as fout:
fout.write(str(auc))
write_answer_3(auc_mean_2, auc_mean_enhanced)
In [44]:
from sklearn.linear_model import LogisticRegression
from sklearn.grid_search import GridSearchCV
from sklearn.metrics import roc_auc_score
In [45]:
from sklearn.cross_validation import train_test_split
(X_train_real_zeros_str,
X_test_real_zeros_str,
y_train_str, y_test_str) = train_test_split(X_real_zeros, y,
stratify=y,
test_size=0.3,
random_state=0)
(X_train_cat_oh_str,
X_test_cat_oh_str) = train_test_split(X_cat_oh,stratify=y,
test_size=0.3,
random_state=0)
In [46]:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_real_scaled_str=scaler.fit_transform(X_train_real_zeros_str)
X_test_real_scaled_str=scaler.transform(X_test_real_zeros_str)
In [48]:
dataZeros_train_str = np.hstack((X_train_real_scaled_str,X_train_cat_oh_str))
dataZeros_test_str = np.hstack((X_test_real_scaled_str,X_test_cat_oh_str))
In [50]:
estimator=LogisticRegression(penalty='l2', random_state = 0, class_weight='balanced', n_jobs=4)
optimizer = GridSearchCV(estimator, param_grid, scoring = 'accuracy', cv=cv)
optimizer.fit(dataZeros_train_str,y_train_str)
print 'Метки функции предсказаний:\n'
print y_test_str[:10]
print optimizer.predict(dataZeros_test_str)[:10]
print 'Лучшая функция:\n'
print optimizer.best_estimator_
print 'Коэффициенты лучшей функции:\n'
print optimizer.best_estimator_.coef_
print 'Лучший параметр функции:\n'
print optimizer.best_params_
print 'параметр accuracy - ',optimizer.best_score_
plot_scores(optimizer)
auc_mean_str=roc_auc_score(y_test_str, optimizer.predict_proba(dataZeros_test_str)[:,1])
print auc_mean_str
In [51]:
def write_answer_4(auc):
with open("preprocessing_lr_answer4.txt", "w") as fout:
fout.write(str(auc))
write_answer_4(auc_mean_str)
In [56]:
(X_train_poly,
X_test_poly,
y_train_poly, y_test_poly) = train_test_split(X_real_zeros, y,
stratify=y,
test_size=0.3,
random_state=0)
(X_train_cat_oh_poly,
X_test_cat_oh_poly) = train_test_split(X_cat_oh, stratify=y,
test_size=0.3,
random_state=0)
In [58]:
from sklearn.preprocessing import PolynomialFeatures
transform_str = PolynomialFeatures(2)
Data_train_poly = transform_str.fit_transform(X_train_poly)
Data_test_poly = transform_str.transform(X_test_poly)
In [59]:
scaler2 = StandardScaler()
X_train_poly_2 = scaler2.fit_transform(Data_train_poly)
X_test_poly_2=scaler2.transform(Data_test_poly)
In [60]:
dataZeros_train_poly = np.hstack((X_train_poly_2,X_train_cat_oh_poly))
dataZeros_test_poly = np.hstack((X_test_poly_2,X_test_cat_oh_poly))
In [61]:
estimator=LogisticRegression(penalty='l2', random_state = 0, class_weight='balanced', n_jobs=-1, fit_intercept=False)
optimizer = GridSearchCV(estimator, param_grid, scoring = 'accuracy', cv=cv)
optimizer.fit(dataZeros_train_poly,y_train_poly)
print 'Метки функции предсказаний:\n'
print y_test_poly[:10]
print optimizer.predict(dataZeros_test_poly)[:10]
print 'Лучшая функция:\n'
print optimizer.best_estimator_
print 'Коэффициенты лучшей функции:\n'
print optimizer.best_estimator_.coef_
print 'Лучший параметр функции:\n'
print optimizer.best_params_
plot_scores(optimizer)
auc_zeros_str_poly=roc_auc_score(y_test_poly, optimizer.predict_proba(dataZeros_test_poly)[:,1])
print auc_zeros_str_poly
In [62]:
def write_answer_5(auc):
with open("preprocessing_lr_answer5.txt", "w") as fout:
fout.write(str(auc))
write_answer_5(auc_zeros_str_poly)
In [63]:
(X_train_real_zeros_lasso,
X_test_real_zeros_lasso,
y_train_lasso, y_test_lasso) = train_test_split(X_real_zeros, y,
stratify=y,
test_size=0.3,
random_state=0)
(X_train_cat_oh_lasso,
X_test_cat_oh_lasso) = train_test_split(X_cat_oh, stratify=y,
test_size=0.3,
random_state=0)
In [64]:
scaler = StandardScaler()
X_train_real_scaled_lasso=scaler.fit_transform(X_train_real_zeros_lasso)
X_test_real_scaled_lasso=scaler.transform(X_test_real_zeros_lasso)
In [65]:
dataZeros_train_lasso = np.hstack((X_train_real_scaled_lasso,X_train_cat_oh_str))
dataZeros_test_lasso = np.hstack((X_test_real_scaled_lasso,X_test_cat_oh_str))
In [66]:
estimator=LogisticRegression(penalty='l1', random_state = 0, class_weight='balanced', n_jobs=4)
optimizer = GridSearchCV(estimator, param_grid, scoring = 'accuracy', cv=cv)
optimizer.fit(dataZeros_train_lasso,y_train_str)
print 'Метки функции предсказаний:\n'
print y_test_str[:10]
print optimizer.predict(dataZeros_test_lasso)[:10]
print 'Лучшая функция:\n'
print optimizer.best_estimator_
print 'Коэффициенты лучшей функции:\n'
print optimizer.best_estimator_.coef_[0][:13]
print 'Лучший параметр функции:\n'
print optimizer.best_params_
plot_scores(optimizer)
auc_zero_lasso=roc_auc_score(y_test_str, optimizer.predict_proba(dataZeros_test_lasso)[:,1])
print auc_zero_lasso
In [67]:
optimizer.best_estimator_.coef_[0,:,]
Out[67]:
In [68]:
def write_answer_6(features):
with open("preprocessing_lr_answer6.txt", "w") as fout:
fout.write(" ".join([str(num) for num in features]))
write_answer_6(optimizer.best_estimator_.coef_[0][:13])