In [48]:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import LabelEncoder
import numpy as np
import math as m
from scipy.stats import boxcox
from scipy.stats import shapiro
%matplotlib inline

In [2]:
train = pd.read_csv('train.csv')
train.head()


Out[2]:
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S

In [3]:
train.shape


Out[3]:
(891, 12)

In [4]:
test = pd.read_csv('test.csv')
test.head()


Out[4]:
PassengerId Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 892 3 Kelly, Mr. James male 34.5 0 0 330911 7.8292 NaN Q
1 893 3 Wilkes, Mrs. James (Ellen Needs) female 47.0 1 0 363272 7.0000 NaN S
2 894 2 Myles, Mr. Thomas Francis male 62.0 0 0 240276 9.6875 NaN Q
3 895 3 Wirz, Mr. Albert male 27.0 0 0 315154 8.6625 NaN S
4 896 3 Hirvonen, Mrs. Alexander (Helga E Lindqvist) female 22.0 1 1 3101298 12.2875 NaN S

In [5]:
test.shape


Out[5]:
(418, 11)

В ходе решения Titanic_2.0 мы получили baseline- 0.76077, проведем глубокое исследование данных и попытаемся улучшить эти значения

Только 2 непрерывных признака, остальные дискретные. Возмодно можно будет понастраивать кодирование признаков


In [14]:
train.info()


<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId    891 non-null int64
Survived       891 non-null int64
Pclass         891 non-null int64
Name           891 non-null object
Sex            891 non-null object
Age            714 non-null float64
SibSp          891 non-null int64
Parch          891 non-null int64
Ticket         891 non-null object
Fare           891 non-null float64
Cabin          204 non-null object
Embarked       889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.6+ KB

In [15]:
test.info()


<class 'pandas.core.frame.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 11 columns):
PassengerId    418 non-null int64
Pclass         418 non-null int64
Name           418 non-null object
Sex            418 non-null object
Age            332 non-null float64
SibSp          418 non-null int64
Parch          418 non-null int64
Ticket         418 non-null object
Fare           417 non-null float64
Cabin          91 non-null object
Embarked       418 non-null object
dtypes: float64(2), int64(4), object(5)
memory usage: 36.0+ KB

В обоих выборках много пропусков занчений признака "Age", практически отсутствуют значения признака "Cabin", пропущено одно значение прзнака Fare в тестовой выборке

Survived


In [5]:
train.Survived.describe()


Out[5]:
count    891.000000
mean       0.383838
std        0.486592
min        0.000000
25%        0.000000
50%        0.000000
75%        1.000000
max        1.000000
Name: Survived, dtype: float64

In [6]:
plt.title(u'Количесто погибших/выжевших на титанике', y= 1.1, size=15)
sns.countplot(x='Survived', data = train)


Out[6]:
<matplotlib.axes._subplots.AxesSubplot at 0xa73aef0>

Классы получились не сбалансированными, учесть это при обучении моделей

Pclass


In [9]:
train.Pclass.describe()


Out[9]:
count    891.000000
mean       2.308642
std        0.836071
min        1.000000
25%        2.000000
50%        3.000000
75%        3.000000
max        3.000000
Name: Pclass, dtype: float64

In [22]:
plt.title(u'Распределение выживших в зависимости от класса', y= 1.1, size = 20 )
sns.barplot(x = 'Pclass', y = 'Survived', data = train)


Out[22]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f3ed5c81550>

сильный признак


In [24]:
plt.title(u'Количество людей путешествубщих в каждоим классе', y= 1.1, size=15)
sns.countplot(x='Pclass', data = train)


Out[24]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f3ed5888b50>

Sex


In [27]:
sex_encoder  = LabelEncoder()
train['Sex_enc'] = sex_encoder.fit_transform(train.Sex)
test['Sex_enc'] = sex_encoder.transform(test.Sex)

In [29]:
plt.title(u'Число мужчин и женщин на борту', y =1.1, size = 20)
sns.countplot(x='Sex', data = train)


Out[29]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f3ed4b48d90>

In [30]:
plt.title(u'Распределение выживших в зависимости от класса и пола', y= 1.1, size = 20 )
sns.barplot(x = 'Pclass', y = 'Survived', data = train, hue = 'Sex')


Out[30]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f3ed57b28d0>

Класс и пол - очень сильные признаки

SibSp and Parch


In [39]:
sns.countplot(x='SibSp', data = train)


Out[39]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f3ed481bb50>

In [44]:
sns.countplot(x='Parch', data = train)


Out[44]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f3ed42e0810>

создадим признак Family Size, чтобы добавить вес правому краю распредления


In [4]:
for df in [train,test]:
    df['Fam_size'] = df.Parch + df.SibSp

In [5]:
sns.countplot(x='Fam_size', data = train)


Out[5]:
<matplotlib.axes._subplots.AxesSubplot at 0x7effe7b67710>

In [48]:
fig = plt.figure(figsize = (10,10))
sns.barplot(x='Fam_size', y = 'Survived', hue = 'Sex',data = train)


Out[48]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f3ed41578d0>

In [49]:
fig = plt.figure(figsize = (10,10))
sns.barplot(x='Fam_size', y = 'Survived', hue = 'Pclass',data = train)


Out[49]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f3ed46b5550>

Очень сильный признак. Бездетные люди из 3 класса практически не имели шансов выжить

Ticket


In [6]:
train.Ticket.describe()


Out[6]:
count          891
unique         681
top       CA. 2343
freq             7
Name: Ticket, dtype: object

In [7]:
for elem in df.Ticket:
    print elem
    #print elem[0]


330911
363272
240276
315154
3101298
7538
330972
248738
2657
A/4 48871
349220
694
21228
24065
W.E.P. 5734
SC/PARIS 2167
233734
2692
STON/O2. 3101270
2696
PC 17603
C 17368
PC 17598
PC 17597
PC 17608
A/5. 3337
113509
2698
113054
2662
SC/AH 3085
C.A. 31029
C.A. 2315
W./C. 6607
13236
2682
342712
315087
345768
1601
349256
113778
SOTON/O.Q. 3101263
237249
11753
STON/O 2. 3101291
PC 17594
370374
11813
C.A. 37671
13695
SC/PARIS 2168
29105
19950
SC/A.3 2861
382652
349230
348122
386525
PC 17608
349232
237216
347090
334914
PC 17608
F.C.C. 13534
330963
113796
2543
19950
382653
349211
3101297
PC 17562
113503
113503
359306
11770
248744
368702
2678
PC 17483
19924
349238
240261
2660
330844
A/4 31416
364856
29103
347072
345498
F.C. 12750
376563
13905
350033
19877
STON/O 2. 3101268
347471
A./5. 3338
11778
228414
365235
347070
2625
C 4001
330920
383162
3410
248734
237734
330968
PC 17531
329944
PC 17483
2680
2681
PP 9549
13050
SC/AH 29037
C.A. 33595
367227
13236
392095
368783
371362
350045
367226
211535
342441
STON/OQ. 369943
113780
4133
2621
349226
350409
2656
248659
SOTON/OQ 392083
CA 2144
CA 2144
113781
PC 17608
244358
17475
345763
17463
SC/A4 23568
113791
250651
11767
349255
3701
350405
347077
S.O./P.P. 752
PC 17483
347469
110489
SOTON/O.Q. 3101315
335432
2650
220844
343271
237393
315153
PC 17591
W./C. 6608
17770
7548
S.O./P.P. 251
2670
347072
2673
347077
29750
C.A. 33112
11778
230136
PC 17756
233478
PC 17756
113773
7935
PC 17558
239059
S.O./P.P. 2
A/4 48873
CA. 2343
28221
226875
111163
A/5. 851
235509
28220
347465
16966
347066
C.A. 31030
65305
36568
347080
PC 17757
26360
C.A. 34050
F.C. 12998
9232
28034
PC 17613
349250
C 4001
SOTON/O.Q. 3101308
S.O.C. 14879
24065
347091
113038
330924
36928
113503
32302
SC/PARIS 2148
342684
W./C. 14266
350053
PC 17606
2661
350054
370368
C.A. 6212
242963
220845
113795
3101266
330971
PC 17599
350416
110813
2679
250650
PC 17761
112377
237789
16966
3470
W./C. 6607
17464
F.C.C. 13534
28220
26707
2660
C.A. 34651
SOTON/O2 3101284
13508
7266
345775
C.A. 42795
AQ/4 3130
363611
28404
345501
345572
350410
29103
350405
C.A. 34644
349235
112051
C.A. 49867
A. 2. 39186
315095
13050
368573
13508
370371
2676
236853
SC 14888
2926
CA 31352
W./C. 14260
315085
SOTON/O.Q. 3101315
364859
2650
370129
A/5 21175
SOTON/O.Q. 3101314
21228
2655
A/5 1478
PC 17607
382650
2652
33638
345771
349202
SC/Paris 2123
2662
113801
347467
347079
237735
S.O./P.P. 2
315092
383123
112901
113781
392091
12749
350026
315091
2658
LP 1588
368364
PC 17760
AQ/3. 30631
PC 17569
28004
350408
C.A. 31029
347075
2654
244368
113790
24160
SOTON/O.Q. 3101309
230136
PC 17585
2003
236854
C.A. 33112
PC 17580
2684
2653
349229
110469
244360
2675
C.A. 31029
2622
C.A. 15185
350403
CA. 2343
PC 17755
A/5. 851
348125
237670
2688
248726
F.C.C. 13528
PC 17759
F.C.C. 13540
S.O.C. 14879
220845
C.A. 2315
113044
11769
1222
368402
349910
CA. 2343
S.C./PARIS 2079
CA 31352
315083
11765
CA. 2343
2689
3101295
112378
SC/PARIS 2147
28133
16966
112058
248746
33638
PC 17608
315152
29107
680
347077
366713
330910
364498
376566
SC/PARIS 2159
220845
349911
244346
364858
349909
12749
PC 17592
C.A. 2673
C.A. 30769
315153
13695
371109
13567
347065
21332
36928
28664
112378
113059
17765
SC/PARIS 2166
28666
113503
334915
SOTON/O.Q. 3101315
365237
19928
347086
A.5. 3236
PC 17758
SOTON/O.Q. 3101262
359309
2668

Первая буква билета может означать серию или еще какую-то информаци о продавце билетов, что возможно могло повлиять на групировку пассажиров на борту


In [8]:
train['letter'] = df.Ticket.apply(lambda x: x[0])

In [9]:
fig = plt.figure(figsize = (10,10))
plt.title(u'Распределение пасажиров по классам в завимимость от первой буквы номер билета', size = 20)
sns.countplot(x='letter',hue='Pclass', data = train)


Out[9]:
<matplotlib.axes._subplots.AxesSubplot at 0x7effe54814d0>

In [10]:
fig = plt.figure(figsize = (10,10))
sns.barplot(x='letter',y = 'Survived', hue='Pclass', data = train)


Out[10]:
<matplotlib.axes._subplots.AxesSubplot at 0x7effe5311690>

Признак слабоват

Некоторые номера билетов повторяются, разделим их на повторяющиеся и нет


In [26]:
ticket = pd.concat((train.Ticket, test.Ticket), ignore_index = True)
ticket_freq = ticket.value_counts()

for df in (train,test):
    fticket_list = []
    for elem in df.Ticket:
        if ticket_freq[str(elem)]>1:
            fticket_list.append(1)
        else:
            fticket_list.append(0)
    df['ticket_freq'] = fticket_list

In [31]:
plt.title(u'Доля выживших в зависимости от пола и наличия у человека повторяющегося билета', size = 20)
sns.barplot(x = 'ticket_freq', y = 'Survived', data = train, hue = 'Sex')


Out[31]:
<matplotlib.axes._subplots.AxesSubplot at 0x7effe4a459d0>

In [32]:
plt.title(u'Доля выживших в зависимости от пола и наличия у человека повторяющегося билета', size = 20)
sns.barplot(x = 'ticket_freq', y = 'Survived', data = train, hue = 'Pclass')


Out[32]:
<matplotlib.axes._subplots.AxesSubplot at 0x7effe4d2c490>

Признак средней силы, так как перекрываются доверительные интервалы

Fare


In [7]:
fig = plt.figure(figsize=(10,10))
plt.title(u'Распределение стоимости билета  в обучающей выборке', y= 1.1, size = 20 )
sns.distplot(train.Fare)


Out[7]:
<matplotlib.axes._subplots.AxesSubplot at 0xa80d668>

In [14]:
fig = plt.figure(figsize=(10,10))
plt.title(u'Распределение стоимости билета  в тестовой выборке', y= 1.1, size = 20 )
sns.distplot(test.Fare.loc[test.Fare.isnull() == False])


Out[14]:
<matplotlib.axes._subplots.AxesSubplot at 0x7ff007bfda50>

На обучении и на тесте распределение признака Fare явно не является нормальным. Объеденим значения и попытаемся привести их к нормальному распределению

В ходе исследования признака оказальсь что есть пасажиры, которые не платили за билет, исследуем их


In [14]:
train.Fare.loc[train.Fare == 0]


Out[14]:
179    0.0
263    0.0
271    0.0
277    0.0
302    0.0
413    0.0
466    0.0
481    0.0
597    0.0
633    0.0
674    0.0
732    0.0
806    0.0
815    0.0
822    0.0
Name: Fare, dtype: float64

In [16]:
train.Survived.loc[train.Fare == 0]


Out[16]:
179    0
263    0
271    1
277    0
302    0
413    0
466    0
481    0
597    0
633    0
674    0
732    0
806    0
815    0
822    0
Name: Survived, dtype: int64

In [15]:
sns.barplot(x =train.Fare.loc[train.Fare == 0] , y = 'Survived', data = train, hue = 'Pclass')


Out[15]:
<matplotlib.axes._subplots.AxesSubplot at 0xbdfa5f8>

In [17]:
sns.barplot(x =train.Fare.loc[train.Fare == 0] , y = 'Survived', data = train, hue = 'Sex')


Out[17]:
<matplotlib.axes._subplots.AxesSubplot at 0xa95bba8>

Пасажиры с бесплатными билетами - мужчины из 3-его класса с практически нулевым шансом на выживание. Созжадим признак free_ticket, 1- бесплтный билет, 0 - платный билет


In [20]:
for df in (train, test):
    df['free_ticket'] = df.Fare.apply(lambda x: 1 if x==0 else 0)

In [41]:
# заменим значения 0 на 0,01 так как дальнейшие преобразования с 0 будут плохо работать
for df in (train, test):
    df.Fare = df.Fare.apply(lambda x:0.01 if x==0 else x)

In [42]:
train['log_fare'] = train.Fare.apply(np.log10)

In [43]:
sns.distplot(train.log_fare)


Out[43]:
<matplotlib.axes._subplots.AxesSubplot at 0xc3e72e8>

In [47]:
sns.distplot(boxcox(train.Fare)[0])


Out[47]:
<matplotlib.axes._subplots.AxesSubplot at 0xc5fc748>

In [49]:
shapiro(boxcox(train.Fare)[0])


Out[49]:
(0.874458372592926, 3.6499318348581054e-26)

In [ ]:
train.Fare.loc[train.Fare <= 0]

Age

возьмемся под конец, так как надо заполнять пробелы


In [37]:
plt.title(u'Распределение людей по возрасту', y= 1.1, size = 20 )
sns.distplot(train.Age.loc[train.Age.isnull()== False])


Out[37]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f3ed4821f10>

In [38]:
train.Age.loc[train.Age.isnull()== False].describe()


Out[38]:
count    714.000000
mean      29.699118
std       14.526497
min        0.420000
25%       20.125000
50%       28.000000
75%       38.000000
max       80.000000
Name: Age, dtype: float64