ТИТАНИК. ПОСТРОЕНИЕ МОДЕЛИ. Часть 1.
=====================================
ФОРМИРОВАНИЕ ПРИЗНАКОВ (FEATURES)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Знакомая картинка из предадущего ролика.
Здесь хорошо видны колонки, содержащие пустоты.
Фильтруем колонки
Исключить уникальные
id — идентификатор
name — ФИО пассажира
ticket — номер билета
home — адрес
Исключить содержащие много пустот
age — возраст
cabin — номер каюты
boat — номер лодки куда попал выживший
body — номер лодки куда было поднято тело погибшего
Включить остальные
pclass — класс купленного билета (1-й, 2-й, или 3-й)
sex — пол пассажира
sibsp — количество братьев или супругов у пассажира на борту
parch — количество родителей или детей у пассажира на борту
fare — сумма денег, которую заплатили за билет
embarked — порт (город), где пассажир сел на Титаник
Целевой признак
survived — выжил ли пассажир: да = 1, нет = 0
Возраст очень важный признак - нужно попытаться
заполнить пустоты и включить его в признаки.
С этого места начинается тяжелая работа по приведению данных
к состоянию пригодному для обучению модели. Осилят не все.
-- Продолжение работы в PostgreSQL --
В таблице tit1 поля age и fare текстовые т.к. в дробных
значениях запятая, а Postgres понимает только точку.
select id, age, fare from tit1 limit 7;
Исправить это: заменить , на .update tit1 set
age = replace(age, ',', '.'),
fare = replace(fare, ',', '.')
where age like '%,%' or fare like '%,%';
Создать таблицу tit2 с типом float (число с плавающей точкой)
для полей age и fare (возраст и цена билета)
create table tit2 (
id serial,
pclass int,
survived int,
name varchar,
sex varchar,
age float,
sibsp int,
parch int,
ticket varchar,
fare float,
cabin varchar,
embarked varchar,
boat varchar,
body varchar,
home varchar
);
create UNIQUE index on tit1 (id);
Перелить исправленные данные из tit1 в tit2
insert into tit2 (
id, pclass, survived, name, sex, age, sibsp,parch,
ticket, fare, cabin, embarked, boat, body, home
)
select
id, pclass, survived, name, sex, age::float, sibsp, parch,
ticket, fare::float, cabin, embarked, boat, body, home
from tit1;
НАЙТИ МЕДИАННЫЕ ЗНАЧЕНИЯ
------------------------
ДЛЯ FARE - ПО КЛАССУ КАЮТЫ
Найти пустые значения цены билета
select id, pclass, age, fare from tit2
where fare is null;
id | pclass | age | fare
------+--------+------+------
1226 | 3 | 60.5 | ¤
Оказалось только одно.
Вычислить медиану цены для 3-го класса
select percentile_cont (0.5) within
group (order by fare)
from tit2 where pclass = 3 and fare is not null;
percentile_cont
-----------------
8.05
Заменить NULL на вычисленное медианное значение цены
для 3-го класса
update tit2 set fare = 8.05 where id = 1226;
ДЛЯ AGE - ПО ТИТУЛУ
Выделить титулы такие как: Miss, Mr, Master,
пользуясь тем, что в начале их всегда есть ', '
а в конце '. '
select distinct
substring(name,
position(', ' in name) + 2,
position('. ' in name) -
position(', ' in name) - 2)
as titul
from tit2 order by titul;
titul
--------------
Capt
Col
Don
Dona
Dr
Jonkheer
Lady
Major
Master
Miss
Mlle
Mme
Mr
Mrs
Ms
Rev
Sir
the Countess
(18 строк)
Заменить NULL на вычисленное медианное значение возраста
для каждого титула в отдельности
Помог ИИ: https://www.phind.com/search/cmfyvgkkp00002v6t6pwbj2v7
НАЧАЛО ЗАПРОСА
``````````````
-- Получаем все возможные титулы
WITH titles AS (
select distinct
substring(name,
position(', ' in name) + 2,
position('. ' in name) -
position(', ' in name) - 2)
as titul
from tit2
),
-- Вычисляем медианы для каждого титула
medians AS (
SELECT
tit2.titul,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY t2.age)
AS median_age
FROM titles tit2
JOIN tit2 t2 ON
substring(t2.name,
position(', ' in t2.name) + 2,
position('. ' in t2.name) - position(', '
in t2.name) - 2) = tit2.titul
WHERE t2.age IS NOT NULL
GROUP BY tit2.titul
)
-- Обновляем NULL значения
UPDATE tit2
SET age = m.median_age
FROM medians m
WHERE tit2.age IS NULL
AND substring(tit2.name,
position(', ' in tit2.name) + 2,
position('. ' in tit2.name) - position(', '
in tit2.name) - 2) = m.titul;
ОКОНЧАНИЕ ЗАПРОСА
`````````````````
Окончательный список признаков (7 штук)
age — возраст пассажира
pclass — класс купленного билета (1-й, 2-й, или 3-й)
sex — пол пассажира
sibsp — количество братьев или супругов на борту
parch — количество родителей или детей на борту
fare — сумма денег, которую заплатили за билет
embarked — порт (город), где пассажир сел на Титаник
Поверить их полноту т.е. нет ли в каком-нибудь из признаков
пустых значений:
select * from tit2 where
age is null or
pclass is null or
sex is null or
sibsp is null or
parch is null or
fare is null or
embarked is null ;
-[ RECORD 1 ]---------------------------------------
id | 170
pclass | 1
survived | 1
name | Icard, Miss. Amelie
sex | female
age | 38
sibsp | 0
parch | 0
ticket | 113572
fare | 80
cabin | B28
embarked | ¤
boat | 6
body | ¤
home | ¤
-[ RECORD 2 ]---------------------------------------
id | 287
pclass | 1
survived | 1
name | Stone, Mrs. George Nelson (Martha Evelyn)
sex | female
age | 62
sibsp | 0
parch | 0
ticket | 113572
fare | 80
cabin | B28
embarked | ¤
boat | 6
body | ¤
home | Cincinatti, OH
Нашлось две записи с пустым портом посадки embarked
Починить embarked - порт в котором пассажир сел на Титаник
Для 1-го класса (ведь обе записи pclass = 1),
при цене близкой к 80 (fare = 80) и
без учета пустых значений (embarked is not null):
select embarked, count(*) from tit2 where
pclass = 1 and embarked is not null and
fare > 79 and fare < 81
group by embarked;
embarked | count
----------+-------
C | 6
S | 3
Принять embarked = 'C' и заполнить пустоты:
update tit2 set embarked = 'C' where id in (170, 287);
Поcледняя проверка на полноту
select * from tit2 where
age is null or
pclass is null or
sex is null or
sibsp is null or
parch is null or
fare is null or
embarked is null ;
0 строк - пустот нет.
Для тех кому все эти процедуры по восстановлению пропущенных
данных покажутся сложными и захочется просто отбросить строки
содержащие пустые значения (а это необходимо!) сравните:
select count(*) from tit2 where
age is not null and
pclass is not null and
sex is not null and
sibsp is not null and
parch is not null and
fare is not null and
embarked is not null ;
count
-------
1309
select count(*) from tit1 where
age is not null and
pclass is not null and
sex is not null and
sibsp is not null and
parch is not null and
fare is not null and
embarked is not null ;
count
-------
1043
Потеря данных, если отбросить пустоты ~20%, это не смертельно,
но качество модели в результате ухудшится, можно посчитать
насколько, но не сегодня.
bzip2-архивы дампа postgres-базы titanic можно скачать
здесь База в начале и база в конце ролика.
Начальный, для тех, кто честно проделает всю работу руками,
а конечный, для самых тупах и ленивых - там уже всё сделано,
если их скачать - распаковываются так:
bzip2 -d ИМЯ_ФАЙЛА.bz2
Конец