In [216]:
import matplotlib
import matplotlib.pyplot as plt

%matplotlib inline
matplotlib.rcParams.update({'font.size': 12})

# увеличим дефолтный размер графиков
from pylab import rcParams
rcParams['figure.figsize'] = 18, 6
rcParams['font.size'] = 16
rcParams['axes.labelsize'] = 14
rcParams['xtick.labelsize'] = 13
rcParams['ytick.labelsize'] = 13

In [217]:
import pandas as pd
import numpy as np

Данные

Возьмите данные с https://www.kaggle.com/c/shelter-animal-outcomes .

Обратите внимание, что в этот раз у нас много классов, почитайте в разделе Evaluation то, как вычисляется итоговый счет (score).

Визуализация

Задание 1.

Выясните, построив необходимые графики, влияет ли возраст, пол или фертильность животного на его шансы быть взятыми из приюта.

Подготовим данные


In [218]:
visual = pd.read_csv('data/CatsAndDogs/TRAIN2.csv')

#Сделаем числовой столбец Outcome, показывающий, взяли животное из приюта или нет
#Сначала заполним единицами, типа во всех случах хорошо
visual['Outcome'] = 'true'
#Неудачные случаи занулим
visual.loc[visual.OutcomeType == 'Euthanasia', 'Outcome'] = 'false'
visual.loc[visual.OutcomeType == 'Died', 'Outcome'] = 'false'

#Заменим строки, где в SexuponOutcome NaN, на что-нибудь осмысленное
visual.loc[visual.SexuponOutcome.isnull(), 'SexuponOutcome'] = 'Unknown Unknown'

#Сделаем два отдельных столбца для пола и фертильности
visual['Gender'] = visual.SexuponOutcome.apply(lambda s: s.split(' ')[-1])
visual['Fertility'] = visual.SexuponOutcome.apply(lambda s: s.split(' ')[0])

Сравним по возрасту


In [219]:
mergedByAges = visual.groupby('AgeuponOutcome')['Outcome'].value_counts().to_dict()

results = pd.DataFrame(data = mergedByAges, index=[0]).stack().fillna(0).transpose()
results.columns = pd.Index(['true', 'false'])
results['total'] = results.true + results.false
results.sort_values(by='true', ascending=False, inplace=True)
results[['true', 'false']].plot(kind='bar', stacked=False, rot=45);


Сравним по полу


In [220]:
mergedByGender = visual.groupby('Gender')['Outcome'].value_counts().to_dict()

results = pd.DataFrame(data = mergedByGender, index=[0]).stack().fillna(0).transpose()
results.columns = pd.Index(['true', 'false'])
results['total'] = results.true + results.false
results.sort_values(by='true', ascending=False, inplace=True)
results[['true', 'false']].plot(kind='bar', stacked=True, rot=45);


Сравним по фертильности


In [221]:
mergedByFert = visual.groupby('Fertility')['Outcome'].value_counts().to_dict()

results = pd.DataFrame(data = mergedByFert, index=[0]).stack().fillna(0).transpose()
results.columns = pd.Index(['true', 'false'])
results['total'] = results.true + results.false
results.sort_values(by='true', ascending=False, inplace=True)
results[['true', 'false']].plot(kind='bar', stacked=True, rot=45);


Вывод по возрасту: лучше берут не самых старых, но и не самых молодых
Вывод по полу: по большому счёту не имеет значения
Вывод по фертильности: лучше берут животных с ненарушенными репродуктивными способностями. Однако две следующие группы не сильно различаются по сути и, если их сложить, то разница не столь велика.

Построение моделей

Задание 2.

Посмотрите тетрадку с генерацией новых признаков. Сделайте как можно больше релевантных признаков из всех имеющихся.

Не забудьте параллельно обрабатывать отложенную выборку (test), чтобы в ней были те же самые признаки, что и в обучающей.

Возьмем исходные данные


In [222]:
train, test = pd.read_csv(
    'data/CatsAndDogs/TRAIN2.csv' #наши данные
    #'data/CatsAndDogs/train.csv' #исходные данные
), pd.read_csv(
    'data/CatsAndDogs/TEST2.csv'  #наши данные
    #'data/CatsAndDogs/test.csv'  #исходные данные
)

train.head()


Out[222]:
AnimalID Name DateTime OutcomeType AnimalType SexuponOutcome AgeuponOutcome Breed Color
0 A671945 Hambone 2014-02-12 18:22:00 Return_to_owner Dog Neutered Male 1 year Shetland Sheepdog Mix Brown/White
1 A656520 Emily 2013-10-13 12:44:00 Euthanasia Cat Spayed Female 1 year Domestic Shorthair Mix Cream Tabby
2 A686464 Pearce 2015-01-31 12:28:00 Adoption Dog Neutered Male 2 years Pit Bull Mix Blue/White
3 A677334 Elsa 2014-04-25 13:04:00 Transfer Dog Intact Female 1 month Cairn Terrier/Chihuahua Shorthair Black/Tan
4 A699218 Jimmy 2015-03-28 13:11:00 Transfer Cat Intact Male 3 weeks Domestic Shorthair Mix Blue Tabby

In [223]:
test.shape


Out[223]:
(5346, 8)

Добавим новые признаки в train


In [224]:
#Сначала по-аналогии с визуализацией

#Заменим строки, где в SexuponOutcome, Breed, Color NaN
train.loc[train.SexuponOutcome.isnull(), 'SexuponOutcome'] = 'Unknown Unknown'
train.loc[train.AgeuponOutcome.isnull(), 'AgeuponOutcome'] = '0 0'
train.loc[train.Breed.isnull(), 'Breed'] = 'Unknown'
train.loc[train.Color.isnull(), 'Color'] = 'Unknown'

#Сделаем два отдельных столбца для пола и фертильности
train['Gender'] = train.SexuponOutcome.apply(lambda s: s.split(' ')[-1])
train['Fertility'] = train.SexuponOutcome.apply(lambda s: s.split(' ')[0])

#Теперь что-то новое

#Столбец, в котором отмечено, есть имя у животного или нет
train['hasName'] = 1
train.loc[train.Name.isnull(), 'hasName'] = 0

#Столбец, в котором объединены порода и цвет
train['breedColor'] = train.apply(lambda row: row['Breed'] + ' ' + str(row['Color']), axis=1)

#Декомпозируем DateTime
#Во-первых, конвертируем столбец в тип DateTime из строкового
train['DateTime'] = pd.to_datetime(train['DateTime'])
#А теперь декомпозируем
train['dayOfWeek'] = train.DateTime.apply(lambda dt: dt.dayofweek)
train['month'] = train.DateTime.apply(lambda dt: dt.month)
train['day'] = train.DateTime.apply(lambda dt: dt.day)
train['quarter'] = train.DateTime.apply(lambda dt: dt.quarter)
train['hour'] = train.DateTime.apply(lambda dt: dt.hour)
train['minute'] = train.DateTime.apply(lambda dt: dt.hour)
train['year'] = train.DateTime.apply(lambda dt: dt.year)

#Разбиение возраста
#Сделаем два отдельных столбца для обозначения года/месяца и их количества
train['AgeuponFirstPart'] = train.AgeuponOutcome.apply(lambda s: s.split(' ')[0])
train['AgeuponSecondPart'] = train.AgeuponOutcome.apply(lambda s: s.split(' ')[-1])
#Переведем примерно в среднем месяцы, годы и недели в дни с учетом окончаний s
train['AgeuponSecondPartInDays'] = 0
train.loc[train.AgeuponSecondPart == 'year', 'AgeuponSecondPartInDays'] = 365
train.loc[train.AgeuponSecondPart == 'years', 'AgeuponSecondPartInDays'] = 365
train.loc[train.AgeuponSecondPart == 'month', 'AgeuponSecondPartInDays'] = 30
train.loc[train.AgeuponSecondPart == 'months', 'AgeuponSecondPartInDays'] = 30
train.loc[train.AgeuponSecondPart == 'week', 'AgeuponSecondPartInDays'] = 7
train.loc[train.AgeuponSecondPart == 'weeks', 'AgeuponSecondPartInDays'] = 7
#Во-первых, конвертируем столбец в числовой тип из строкового
train['AgeuponFirstPart'] = pd.to_numeric(train['AgeuponFirstPart'])
train['AgeuponSecondPartInDays'] = pd.to_numeric(train['AgeuponSecondPartInDays'])

#А теперь получим нормальное время жизни в днях
train['LifetimeInDays'] = train['AgeuponFirstPart'] * train['AgeuponSecondPartInDays']

#Удалим уж совсем бессмысленные промежуточные столбцы
train = train.drop(['AgeuponSecondPartInDays', 'AgeuponSecondPart', 'AgeuponFirstPart'], axis=1)
train.head()


Out[224]:
AnimalID Name DateTime OutcomeType AnimalType SexuponOutcome AgeuponOutcome Breed Color Gender ... hasName breedColor dayOfWeek month day quarter hour minute year LifetimeInDays
0 A671945 Hambone 2014-02-12 18:22:00 Return_to_owner Dog Neutered Male 1 year Shetland Sheepdog Mix Brown/White Male ... 1 Shetland Sheepdog Mix Brown/White 2 2 12 1 18 18 2014 365
1 A656520 Emily 2013-10-13 12:44:00 Euthanasia Cat Spayed Female 1 year Domestic Shorthair Mix Cream Tabby Female ... 1 Domestic Shorthair Mix Cream Tabby 6 10 13 4 12 12 2013 365
2 A686464 Pearce 2015-01-31 12:28:00 Adoption Dog Neutered Male 2 years Pit Bull Mix Blue/White Male ... 1 Pit Bull Mix Blue/White 5 1 31 1 12 12 2015 730
3 A677334 Elsa 2014-04-25 13:04:00 Transfer Dog Intact Female 1 month Cairn Terrier/Chihuahua Shorthair Black/Tan Female ... 1 Cairn Terrier/Chihuahua Shorthair Black/Tan 4 4 25 2 13 13 2014 30
4 A699218 Jimmy 2015-03-28 13:11:00 Transfer Cat Intact Male 3 weeks Domestic Shorthair Mix Blue Tabby Male ... 1 Domestic Shorthair Mix Blue Tabby 5 3 28 1 13 13 2015 21

5 rows × 21 columns

Добавим новые признаки в test по-аналогии


In [225]:
#Сначала по-аналогии с визуализацией

#Заменим строки, где в SexuponOutcome, Breed, Color NaN
test.loc[test.SexuponOutcome.isnull(), 'SexuponOutcome'] = 'Unknown Unknown'
test.loc[test.AgeuponOutcome.isnull(), 'AgeuponOutcome'] = '0 0'
test.loc[test.Breed.isnull(), 'Breed'] = 'Unknown'
test.loc[test.Color.isnull(), 'Color'] = 'Unknown'

#Сделаем два отдельных столбца для пола и фертильности
test['Gender'] = test.SexuponOutcome.apply(lambda s: s.split(' ')[-1])
test['Fertility'] = test.SexuponOutcome.apply(lambda s: s.split(' ')[0])

#Теперь что-то новое

#Столбец, в котором отмечено, есть имя у животного или нет
test['hasName'] = 1
test.loc[test.Name.isnull(), 'hasName'] = 0

#Столбец, в котором объединены порода и цвет
test['breedColor'] = test.apply(lambda row: row['Breed'] + ' ' + str(row['Color']), axis=1)

#Декомпозируем DateTime
#Во-первых, конвертируем столбец в тип DateTime из строкового
test['DateTime'] = pd.to_datetime(test['DateTime'])
#А теперь декомпозируем
test['dayOfWeek'] = test.DateTime.apply(lambda dt: dt.dayofweek)
test['month'] = test.DateTime.apply(lambda dt: dt.month)
test['day'] = test.DateTime.apply(lambda dt: dt.day)
test['quarter'] = test.DateTime.apply(lambda dt: dt.quarter)
test['hour'] = test.DateTime.apply(lambda dt: dt.hour)
test['minute'] = test.DateTime.apply(lambda dt: dt.hour)
test['year'] = test.DateTime.apply(lambda dt: dt.year)

#Разбиение возраста
#Сделаем два отдельных столбца для обозначения года/месяца и их количества
test['AgeuponFirstPart'] = test.AgeuponOutcome.apply(lambda s: s.split(' ')[0])
test['AgeuponSecondPart'] = test.AgeuponOutcome.apply(lambda s: s.split(' ')[-1])
#Переведем примерно в среднем месяцы, годы и недели в дни с учетом окончаний s
test['AgeuponSecondPartInDays'] = 0
test.loc[test.AgeuponSecondPart == 'year', 'AgeuponSecondPartInDays'] = 365
test.loc[test.AgeuponSecondPart == 'years', 'AgeuponSecondPartInDays'] = 365
test.loc[test.AgeuponSecondPart == 'month', 'AgeuponSecondPartInDays'] = 30
test.loc[test.AgeuponSecondPart == 'months', 'AgeuponSecondPartInDays'] = 30
test.loc[test.AgeuponSecondPart == 'week', 'AgeuponSecondPartInDays'] = 7
test.loc[test.AgeuponSecondPart == 'weeks', 'AgeuponSecondPartInDays'] = 7
#Во-первых, конвертируем столбец в числовой тип из строкового
test['AgeuponFirstPart'] = pd.to_numeric(test['AgeuponFirstPart'])
test['AgeuponSecondPartInDays'] = pd.to_numeric(test['AgeuponSecondPartInDays'])

#А теперь получим нормальное время жизни в днях
test['LifetimeInDays'] = test['AgeuponFirstPart'] * test['AgeuponSecondPartInDays']

#Удалим уж совсем бессмысленные промежуточные столбцы
test = test.drop(['AgeuponSecondPartInDays', 'AgeuponSecondPart', 'AgeuponFirstPart'], axis=1)

test.head()


Out[225]:
AnimalID Name DateTime AnimalType SexuponOutcome AgeuponOutcome Breed Color Gender Fertility hasName breedColor dayOfWeek month day quarter hour minute year LifetimeInDays
0 A683430 NaN 2014-07-11 19:09:00 Cat Intact Male 3 weeks Domestic Shorthair Mix Blue Cream Male Intact 0 Domestic Shorthair Mix Blue Cream 4 7 11 3 19 19 2014 21
1 A667013 NaN 2013-11-15 12:52:00 Dog Neutered Male 2 years Lhasa Apso/Miniature Poodle Tan Male Neutered 0 Lhasa Apso/Miniature Poodle Tan 4 11 15 4 12 12 2013 730
2 A688584 Preston 2015-11-25 15:00:00 Dog Neutered Male 1 year Great Pyrenees Mix White/Cream Male Neutered 1 Great Pyrenees Mix White/Cream 2 11 25 4 15 15 2015 365
3 A708812 Munchkin 2015-09-18 15:19:00 Cat Spayed Female 1 year Domestic Shorthair Mix White Female Spayed 1 Domestic Shorthair Mix White 4 9 18 3 15 15 2015 365
4 A705262 Jamaica 2015-08-15 14:22:00 Dog Spayed Female 2 years Plott Hound/Boxer Brown Brindle/White Female Spayed 1 Plott Hound/Boxer Brown Brindle/White 5 8 15 3 14 14 2015 730

Задание 3.

Выполните отбор признаков, попробуйте различные методы. Проверьте качество на кросс-валидации.

Выведите топ самых важных и самых незначащих признаков.

Предобработка данных


In [226]:
np.random.seed = 1234
from sklearn.preprocessing import LabelEncoder
from sklearn import preprocessing

#####################Заменим NaN значения на слово Unknown##################
#Уберем Nan значения из train
train.loc[train.AnimalID.isnull(), 'AnimalID'] = 'Unknown'
train.loc[train.Name.isnull(), 'Name'] = 'Unknown'
train.loc[train.OutcomeType.isnull(), 'OutcomeType'] = 'Unknown'
train.loc[train.AnimalType.isnull(), 'AnimalType'] = 'Unknown'
train.loc[train.AgeuponOutcome.isnull(), 'AgeuponOutcome'] = 'Unknown'
train.loc[train.LifetimeInDays.isnull(), 'LifetimeInDays'] = 'Unknown'

#Уберем Nan значения из test
test.loc[test.AnimalID.isnull(), 'AnimalID'] = 'Unknown'
test.loc[test.Name.isnull(), 'Name'] = 'Unknown'
test.loc[test.AnimalType.isnull(), 'AnimalType'] = 'Unknown'
test.loc[test.AgeuponOutcome.isnull(), 'AgeuponOutcome'] = 'Unknown'
test.loc[test.LifetimeInDays.isnull(), 'LifetimeInDays'] = 'Unknown'

#####################Закодируем слова числами################################

#Закодировали AnimalID цифрами вместо названий в test & train
#encAnimalID = preprocessing.LabelEncoder()
#encAnimalID.fit(pd.concat((test['AnimalID'], train['AnimalID'])))
#test['AnimalID'] = encAnimalID.transform(test['AnimalID'])
#train['AnimalID'] = encAnimalID.transform(train['AnimalID'])

#Закодировали имя цифрами вместо названий в test & train
encName = preprocessing.LabelEncoder()
encName.fit(pd.concat((test['Name'], train['Name'])))
test['Name'] = encName.transform(test['Name'])
train['Name'] = encName.transform(train['Name'])

#Закодировали DateTime цифрами вместо названий в test & train
encDateTime = preprocessing.LabelEncoder()
encDateTime.fit(pd.concat((test['DateTime'], train['DateTime'])))
test['DateTime'] = encDateTime.transform(test['DateTime'])
train['DateTime'] = encDateTime.transform(train['DateTime'])

#Закодировали OutcomeType цифрами вместо названий в train, т.к. в test их нет
encOutcomeType = preprocessing.LabelEncoder()
encOutcomeType.fit(train['OutcomeType'])
train['OutcomeType'] = encOutcomeType.transform(train['OutcomeType'])

#Закодировали AnimalType цифрами вместо названий в test & train
encAnimalType = preprocessing.LabelEncoder()
encAnimalType.fit(pd.concat((test['AnimalType'], train['AnimalType'])))
test['AnimalType'] = encAnimalType.transform(test['AnimalType'])
train['AnimalType'] = encAnimalType.transform(train['AnimalType'])

#Закодировали SexuponOutcome цифрами вместо названий в test & train
encSexuponOutcome = preprocessing.LabelEncoder()
encSexuponOutcome.fit(pd.concat((test['SexuponOutcome'], train['SexuponOutcome'])))
test['SexuponOutcome'] = encSexuponOutcome.transform(test['SexuponOutcome'])
train['SexuponOutcome'] = encSexuponOutcome.transform(train['SexuponOutcome'])

#Закодировали AgeuponOutcome цифрами вместо названий в test & train
encAgeuponOutcome = preprocessing.LabelEncoder()
encAgeuponOutcome.fit(pd.concat((test['AgeuponOutcome'], train['AgeuponOutcome'])))
test['AgeuponOutcome'] = encAgeuponOutcome.transform(test['AgeuponOutcome'])
train['AgeuponOutcome'] = encAgeuponOutcome.transform(train['AgeuponOutcome'])

#Закодировали Breed цифрами вместо названий в test & train
encBreed = preprocessing.LabelEncoder()
encBreed.fit(pd.concat((test['Breed'], train['Breed'])))
test['Breed'] = encBreed.transform(test['Breed'])
train['Breed'] = encBreed.transform(train['Breed'])

#Закодировали Color цифрами вместо названий в test & train
encColor = preprocessing.LabelEncoder()
encColor.fit(pd.concat((test['Color'], train['Color'])))
test['Color'] = encColor.transform(test['Color'])
train['Color'] = encColor.transform(train['Color'])

#Закодировали Gender цифрами вместо названий в test & train
encGender = preprocessing.LabelEncoder()
encGender.fit(pd.concat((test['Gender'], train['Gender'])))
test['Gender'] = encGender.transform(test['Gender'])
train['Gender'] = encGender.transform(train['Gender'])

#Закодировали Fertility цифрами вместо названий в test & train
encFertility = preprocessing.LabelEncoder()
encFertility.fit(pd.concat((test['Fertility'], train['Fertility'])))
test['Fertility'] = encFertility.transform(test['Fertility'])
train['Fertility'] = encFertility.transform(train['Fertility'])

#Закодировали breedColor цифрами вместо названий в test & train
encbreedColor = preprocessing.LabelEncoder()
encbreedColor.fit(pd.concat((test['breedColor'], train['breedColor'])))
test['breedColor'] = encbreedColor.transform(test['breedColor'])
train['breedColor'] = encbreedColor.transform(train['breedColor'])

####################################Предобработка#################################
from sklearn.model_selection import cross_val_score
#poly_features = preprocessing.PolynomialFeatures(3)

#Подготовили данные так, что X_tr - таблица без AnimalID и OutcomeType, а в y_tr сохранены OutcomeType
X_tr, y_tr = train.drop(['AnimalID', 'OutcomeType'], axis=1), train['OutcomeType']

#Типа перевели dataFrame в array и сдалали над ним предварительную обработку
#X_tr = poly_features.fit_transform(X_tr)
X_tr.head()


Out[226]:
Name DateTime AnimalType SexuponOutcome AgeuponOutcome Breed Color Gender Fertility hasName breedColor dayOfWeek month day quarter hour minute year LifetimeInDays
0 2351 3361 1 2 6 1221 130 1 1 1 4675 2 2 12 1 18 18 2014 365
1 1847 350 0 3 6 640 167 0 2 1 2517 6 10 13 4 12 12 2013 365
2 4440 12681 1 2 22 1066 86 1 1 1 4100 5 1 31 1 12 12 2015 730
3 1835 5021 1 0 3 369 36 0 0 1 1252 4 4 25 2 13 13 2014 30
4 2761 13872 0 1 26 640 63 1 0 1 2481 5 3 28 1 13 13 2015 21

Статистические тесты


In [227]:
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2, f_classif, mutual_info_classif

skb = SelectKBest(mutual_info_classif, k=15)
x_new = skb.fit_transform(X_tr, y_tr)

In [228]:
x_new


Out[228]:
array([[ 2351,  3361,     1, ...,    18,    18,   365],
       [ 1847,   350,     0, ...,    12,    12,   365],
       [ 4440, 12681,     1, ...,    12,    12,   730],
       ..., 
       [ 6340, 13463,     1, ...,    13,    13,  1460],
       [ 6072,  5074,     0, ...,    12,    12,    28],
       [ 6072, 16611,     0, ...,     9,     9,   365]], dtype=int64)

Методы обертки


In [229]:
from sklearn.feature_selection import RFE
from sklearn.linear_model import LinearRegression

names = X_tr.columns.values
lr = LinearRegression()
rfe = RFE(lr, n_features_to_select=1)
rfe.fit(X_tr,y_tr);
print("Features sorted by their rank:")
print(sorted(zip(map(lambda x: round(x, 4), rfe.ranking_), names)))


Features sorted by their rank:
[(1, 'minute'), (2, 'hour'), (3, 'hasName'), (4, 'SexuponOutcome'), (5, 'Fertility'), (6, 'Gender'), (7, 'AnimalType'), (8, 'dayOfWeek'), (9, 'year'), (10, 'quarter'), (11, 'AgeuponOutcome'), (12, 'month'), (13, 'day'), (14, 'DateTime'), (15, 'Breed'), (16, 'breedColor'), (17, 'LifetimeInDays'), (18, 'Color'), (19, 'Name')]

Отбор при помощи модели Lasso


In [230]:
from sklearn.linear_model import Lasso
clf = Lasso()
clf.fit(X_tr, y_tr);
clf.coef_


Out[230]:
array([  1.65684297e-04,  -7.61330987e-06,  -0.00000000e+00,
        -0.00000000e+00,  -0.00000000e+00,  -0.00000000e+00,
        -1.89024737e-04,   0.00000000e+00,  -0.00000000e+00,
        -0.00000000e+00,   2.83818819e-05,  -0.00000000e+00,
        -0.00000000e+00,  -0.00000000e+00,  -0.00000000e+00,
        -3.99526402e-02,  -0.00000000e+00,   0.00000000e+00,
         1.42732428e-04])

In [231]:
features = X_tr.columns.values
print('Всего Lasso выкинуло %s переменных' % (clf.coef_ == 0).sum())
print('Это признаки:')
for s in features[np.where(clf.coef_ == 0)[0]]:
    print(' * ', s)


Всего Lasso выкинуло 13 переменных
Это признаки:
 *  AnimalType
 *  SexuponOutcome
 *  AgeuponOutcome
 *  Breed
 *  Gender
 *  Fertility
 *  hasName
 *  dayOfWeek
 *  month
 *  day
 *  quarter
 *  minute
 *  year

Отбор при помощи модели RandomForest


In [232]:
from sklearn.ensemble import RandomForestRegressor
clf = RandomForestRegressor()
clf.fit(X_tr, y_tr);
clf.feature_importances_


Out[232]:
array([ 0.0823636 ,  0.09543804,  0.01342814,  0.16183847,  0.02524361,
        0.03052785,  0.05723444,  0.01099755,  0.09225437,  0.01168482,
        0.05926595,  0.04825568,  0.03368415,  0.0648128 ,  0.0073472 ,
        0.03646261,  0.04744203,  0.00416581,  0.11755288])

In [233]:
imp_feature_idx = clf.feature_importances_.argsort()
imp_feature_idx


Out[233]:
array([17, 14,  7,  9,  2,  4,  5, 12, 15, 16, 11,  6, 10, 13,  0,  8,  1,
       18,  3], dtype=int64)

In [234]:
features = X_tr.columns.values

k = 0

while k < len(features):
    print(features[k], imp_feature_idx[k])
    k += 1


Name 17
DateTime 14
AnimalType 7
SexuponOutcome 9
AgeuponOutcome 2
Breed 4
Color 5
Gender 12
Fertility 15
hasName 16
breedColor 11
dayOfWeek 6
month 10
day 13
quarter 0
hour 8
minute 1
year 18
LifetimeInDays 3

Вывод по признакам:
Не нужны: Name, DateTime, month, day, Breed, breedColor. Всё остальное менее однозначно, можно и оставить.

Задание 4.

Попробуйте смешать разные модели с помощью sklearn.ensemble.VotingClassifier. Увеличилась ли точность? Изменилась ли дисперсия?


In [235]:
#Для начала выкинем ненужные признаки, выявленные на прошлом этапе
X_tr = X_tr.drop(['Name', 'DateTime', 'month', 'day', 'Breed', 'breedColor'], axis=1)
test = test.drop(['Name', 'DateTime', 'month', 'day', 'Breed', 'breedColor'], axis=1)
X_tr.head()


Out[235]:
AnimalType SexuponOutcome AgeuponOutcome Color Gender Fertility hasName dayOfWeek quarter hour minute year LifetimeInDays
0 1 2 6 130 1 1 1 2 1 18 18 2014 365
1 0 3 6 167 0 2 1 6 4 12 12 2013 365
2 1 2 22 86 1 1 1 5 1 12 12 2015 730
3 1 0 3 36 0 0 1 4 2 13 13 2014 30
4 0 1 26 63 1 0 1 5 1 13 13 2015 21

In [236]:
from sklearn.ensemble import VotingClassifier

from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier

clf1 = LogisticRegression(random_state=1234)
clf3 = GaussianNB()
clf5 = KNeighborsClassifier()

eclf = VotingClassifier(estimators=[
    ('lr', clf1), ('gnb', clf3), ('knn', clf5)],
                         voting='soft', weights=[1,1,10])

scores = cross_val_score(eclf, X_tr, y_tr)

eclf = eclf.fit(X_tr, y_tr)

In [237]:
print('Best score:', scores.min())


Best score: 0.576038159371

In [238]:
#delete AnimalID from test
X_te = test.drop(['AnimalID'], axis=1)
X_te.head()


Out[238]:
AnimalType SexuponOutcome AgeuponOutcome Color Gender Fertility hasName dayOfWeek quarter hour minute year LifetimeInDays
0 0 1 26 42 1 0 0 4 3 19 19 2014 21
1 1 2 22 274 1 1 0 4 4 12 12 2013 730
2 1 2 6 338 1 1 1 2 4 15 15 2015 365
3 0 3 6 318 0 2 1 4 3 15 15 2015 365
4 1 3 22 98 0 2 1 5 3 14 14 2015 730

In [239]:
y_te = eclf.predict(X_te)
y_te


Out[239]:
array([4, 4, 0, ..., 4, 4, 3], dtype=int64)

In [240]:
ans_nn = pd.DataFrame({'AnimalID': test['AnimalID'], 'type': encOutcomeType.inverse_transform(y_te)})
ans_nn.head()


Out[240]:
AnimalID type
0 A683430 Transfer
1 A667013 Transfer
2 A688584 Adoption
3 A708812 Adoption
4 A705262 Adoption

In [241]:
#Зададим функцию для трансформации
def onehot_encode(df_train, column):
    from sklearn.preprocessing import LabelBinarizer
    
    cs = df_train.select_dtypes(include=['O']).columns.values
    if column not in cs:
        return (df_train, None)

    rest = [x for x in df_train.columns.values if x != column]

    lb = LabelBinarizer()
    train_data = lb.fit_transform(df_train[column])
  
    new_col_names = ['%s' % x for x in lb.classes_]

    if len(new_col_names) != train_data.shape[1]:
        new_col_names = new_col_names[::-1][:train_data.shape[1]]

    new_train = pd.concat((df_train.drop([column], axis=1), pd.DataFrame(data=train_data, columns=new_col_names)), axis=1)
    return (new_train, lb)

In [242]:
ans_nn, lb = onehot_encode(ans_nn, 'type')

In [243]:
ans_nn
ans_nn.head()


Out[243]:
AnimalID Adoption Died Euthanasia Return_to_owner Transfer
0 A683430 0 0 0 0 1
1 A667013 0 0 0 0 1
2 A688584 1 0 0 0 0
3 A708812 1 0 0 0 0
4 A705262 1 0 0 0 0

Проверим, что никакие строчки при манипуляции с NaN не потерялись


In [244]:
test.shape[0] == ans_nn.shape[0]


Out[244]:
True

In [245]:
#Сделаем нумерацию индексов не с 0, а с 1
ans_nn.index += 1 
#Воткнем столбец с индексами как столбец в конкретное место
ans_nn.insert(0, 'ID', ans_nn.index)
#delete AnimalID from test
ans_nn = ans_nn.drop(['AnimalID'], axis=1)
ans_nn.head()


Out[245]:
ID Adoption Died Euthanasia Return_to_owner Transfer
1 1 0 0 0 0 1
2 2 0 0 0 0 1
3 3 1 0 0 0 0
4 4 1 0 0 0 0
5 5 1 0 0 0 0

In [246]:
#Сохраним
ans_nn.to_csv('ans_catdog.csv', index=False)

In [ ]: