데이터 분석
[머신러닝] 타이타닉 데이터 분석
- -
* [머신러닝] 타이타닉 분석
- kaggle: https://www.kaggle.com/c/titanic
- kaggle에서 제공하는 타이타닉 데이터를 통해 생존자와 사망자를 예측하는 모델 만들기.
- 모델 생성 후 실제 사망자 데이터와 비교해보기
1. 문제정의
- 타이타닉 탑승객의 데이터를 활용해서 생존자 / 사망자를 예측해보자.
- kaggle에서 좋은(높은) 점수를 받는 것을 목표로 잡는다.
2. 데이터 수집
- kaggle 사이트에서 train, test, gender_submission 불러오기
# data analysis and wrangling
import numpy as np
import pandas as pd
# visualization (데이터 시각화 라이브러리)
import matplotlib.pyplot as plt
import seaborn as sns
#data
train = pd.read_csv('./train.csv')
test = pd.read_csv('./test.csv')
train.head()
test.head()
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 |
3. 데이터 전처리
- 결측값, 이상값이 있는지 확인한다.
- 도출하고자 하는 결론과 관계가 없는 컬럼이 있는지 컬럼과 주제의 상관성을 고려한다.
- 데이터 전처리는 행 열의 동일한 전처리가 중요하다. (행, 열 전처리를 한꺼번에 진행한다.)
# train 컬럼 확인
train.columns.unique
<bound method Index.unique of Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',
'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'],
dtype='object')>
결측치 확인
- Age, Cabin, Embarked 컬럼에 결측치가 있음을 확인할 수 있다.
train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PassengerId 891 non-null int64
1 Survived 891 non-null int64
2 Pclass 891 non-null int64
3 Name 891 non-null object
4 Sex 891 non-null object
5 Age 714 non-null float64
6 SibSp 891 non-null int64
7 Parch 891 non-null int64
8 Ticket 891 non-null object
9 Fare 891 non-null float64
10 Cabin 204 non-null object
11 Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
이상치 확인
- Fare 에 비교적 높은 값이 있으나 이상치인지 실제로 높은 금액을 지불한 것인지는 확인되지 않는다.
- 따라서 이상치가 없는 것으로 판단한다.
train.describe()
PassengerId | Survived | Pclass | Age | SibSp | Parch | Fare | |
---|---|---|---|---|---|---|---|
count | 891.000000 | 891.000000 | 891.000000 | 714.000000 | 891.000000 | 891.000000 | 891.000000 |
mean | 446.000000 | 0.383838 | 2.308642 | 29.699118 | 0.523008 | 0.381594 | 32.204208 |
std | 257.353842 | 0.486592 | 0.836071 | 14.526497 | 1.102743 | 0.806057 | 49.693429 |
min | 1.000000 | 0.000000 | 1.000000 | 0.420000 | 0.000000 | 0.000000 | 0.000000 |
25% | 223.500000 | 0.000000 | 2.000000 | 20.125000 | 0.000000 | 0.000000 | 7.910400 |
50% | 446.000000 | 0.000000 | 3.000000 | 28.000000 | 0.000000 | 0.000000 | 14.454200 |
75% | 668.500000 | 1.000000 | 3.000000 | 38.000000 | 1.000000 | 0.000000 | 31.000000 |
max | 891.000000 | 1.000000 | 3.000000 | 80.000000 | 8.000000 | 6.000000 | 512.329200 |
test.describe()
PassengerId | Pclass | Age | SibSp | Parch | Fare | |
---|---|---|---|---|---|---|
count | 418.000000 | 418.000000 | 332.000000 | 418.000000 | 418.000000 | 417.000000 |
mean | 1100.500000 | 2.265550 | 30.272590 | 0.447368 | 0.392344 | 35.627188 |
std | 120.810458 | 0.841838 | 14.181209 | 0.896760 | 0.981429 | 55.907576 |
min | 892.000000 | 1.000000 | 0.170000 | 0.000000 | 0.000000 | 0.000000 |
25% | 996.250000 | 1.000000 | 21.000000 | 0.000000 | 0.000000 | 7.895800 |
50% | 1100.500000 | 3.000000 | 27.000000 | 0.000000 | 0.000000 | 14.454200 |
75% | 1204.750000 | 3.000000 | 39.000000 | 1.000000 | 0.000000 | 31.500000 |
max | 1309.000000 | 3.000000 | 76.000000 | 8.000000 | 9.000000 | 512.329200 |
Passengerid 컬럼 삭제
- Passengerid는 순서를 나타내는 데이터이므로 생존 예측에는 영향을 미치지 않을 것이므로 컬럼을 삭제한다.
- del DataFrame['삭제할 컬럼'] : 열 삭제만 가능 (키워드)
- DataFrame.drop('삭제할 컬럼') : 행 / 열의 삭제가 가능
del train['PassengerId']
train.columns.unique
<bound method Index.unique of Index(['Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket',
'Fare', 'Cabin', 'Embarked'],
dtype='object')>
test.drop('PassengerId', axis=1, inplace=True)
test.columns.unique
<bound method Index.unique of Index(['Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket', 'Fare',
'Cabin', 'Embarked'],
dtype='object')>
정답 컬럼 분리
- train, test 컬럼의 비교를 위해 Survived 컬럼은 삭제한다.
y_train = train['Survived']
train 에서 Survived 컬럼 삭제
train.drop('Survived', axis=1, inplace=True)
train.shape
(891, 11)
test.shape
(418, 10)
결측치 채우기
# 공통 : age, cabin
# train : Embarked
# test : Fare
train : Embarked 데이터 결측치 채우기
- value_counts() : 컬럼 안에 값들의 개수
- S가 가장 많다는 것을 알 수 있음.
train['Embarked'].value_counts(normalize=True)
S 0.724409
C 0.188976
Q 0.086614
Name: Embarked, dtype: float64
- 최빈값 S로 결측치 채우기
- 결측치가 적은 경우에만 추천함.
- fillna() 함수 활용
- fillna('S')
train['Embarked'].fillna('S', inplace = True)
test: Fare 데이터 결측치 채우기
test['Fare'].value_counts()
7.7500 21
26.0000 19
8.0500 17
13.0000 17
7.8958 11
..
9.3250 1
14.4583 1
15.0333 1
25.4667 1
21.0750 1
Name: Fare, Length: 169, dtype: int64
train['Fare'].describe()
count 891.000000
mean 32.204208
std 49.693429
min 0.000000
25% 7.910400
50% 14.454200
75% 31.000000
max 512.329200
Name: Fare, dtype: float64
- 중앙값으로 채우기
test['Fare'].fillna('14', inplace = True)
공통 : Age 데이터 결측치 채우기
- 다른 컬럼과의 상관관계를 통해서 결측치를 채워보자
- corr() 함수로 상관관계 파악
- 정확도는 -1 ~ 1 사이의 값으로 나타낸다.
- 양의 정수는 비례하는 정도를, 음의 정수는 반비례하는 정도를 의미한다.
# - : 음의 상관관계, 반비례 (ex. -0.369 : 반비례 관계로, 36% 정도로 정확하다.)
# 숫자 컬럼만 나옴.
train.corr()
Survived | Pclass | Age | SibSp | Parch | Fare | |
---|---|---|---|---|---|---|
Survived | 1.000000 | -0.338481 | -0.077221 | -0.035322 | 0.081629 | 0.257307 |
Pclass | -0.338481 | 1.000000 | -0.369226 | 0.083081 | 0.018443 | -0.549500 |
Age | -0.077221 | -0.369226 | 1.000000 | -0.308247 | -0.189119 | 0.096067 |
SibSp | -0.035322 | 0.083081 | -0.308247 | 1.000000 | 0.414838 | 0.159651 |
Parch | 0.081629 | 0.018443 | -0.189119 | 0.414838 | 1.000000 | 0.216225 |
Fare | 0.257307 | -0.549500 | 0.096067 | 0.159651 | 0.216225 | 1.000000 |
- Age 컬럼과 Pclass 컬럼의 상관관계가 가장 높다는 것을 확인할 수 있다.
train['Pclass'].value_counts()
3 491
1 216
2 184
Name: Pclass, dtype: int64
DataFrame.groupby() 함수
- 같은 값을 하나로 묶어 통계 또는 집계 결과를 얻기 위해 사용하는 것
- 그룹화 시킬 DataFrame 은 숫자로만 되있어야 한다.
- 전체 groupby 할 경우, 숫자로 된 DataFrame 내 데이터만 분석되어 나온다.
- Aggregation: 뒤에 함수를 지정하여 원하는 값을 도출해 낼 수 있다.
- Parameter
by
: default=None이다.axis
: default=0이다.level
: default=None이다.as_index
: default=True이다.sort
: default=True이다.group_keys
: default=True이다.
# 'A'별로 DataFrame 내 숫자 데이터를 보고 싶을 경우
DataFrame.groupby('A').mean()
DataFrame.groupby('A').sum()
DataFrame.groupby('A').mean()
# 내가 만든 함수를 적용하고 싶을 때 agg()
DataFrame.groupby('A').agg('__')
- train의 Pclass 컬럼 별로 train 전체 컬럼(중 숫자 데이터) 값을 보여줌.
train.groupby(train["Pclass"]).mean()
Survived | Age | SibSp | Parch | Fare | |
---|---|---|---|---|---|
Pclass | |||||
1 | 0.629630 | 38.233441 | 0.416667 | 0.356481 | 84.154687 |
2 | 0.472826 | 29.877630 | 0.402174 | 0.380435 | 20.662183 |
3 | 0.242363 | 25.140620 | 0.615071 | 0.393075 | 13.675550 |
- train의 Embarked 컬럼 별로 train의 Pclass 컬럼의 평균 값을 보여줌.
train['Pclass'].groupby(train["Embarked"]).agg('mean')
Embarked
C 1.886905
Q 2.909091
S 2.346749
Name: Pclass, dtype: float64
train['Pclass'].groupby(train["Embarked"]).mean()
Embarked
C 1.886905
Q 2.909091
S 2.346749
Name: Pclass, dtype: float64
- Pclass, Sex 컬럼 별로 train 내 전체 데이터의 평균값을 보여줌.
train.groupby(["Pclass", "Sex"]).mean()
Survived | Age | SibSp | Parch | Fare | ||
---|---|---|---|---|---|---|
Pclass | Sex | |||||
1 | female | 0.968085 | 34.611765 | 0.553191 | 0.457447 | 106.125798 |
male | 0.368852 | 41.281386 | 0.311475 | 0.278689 | 67.226127 | |
2 | female | 0.921053 | 28.722973 | 0.486842 | 0.605263 | 21.970121 |
male | 0.157407 | 30.740707 | 0.342593 | 0.222222 | 19.741782 | |
3 | female | 0.500000 | 21.750000 | 0.895833 | 0.798611 | 16.118810 |
male | 0.135447 | 26.507589 | 0.498559 | 0.224784 | 12.661633 |
- Pclass, Sex 컬럼 별로 trian의 Pclass, Sex, Age 컬럼의 평균을 보여줌.
train[['Pclass', 'Sex' , 'Age']].groupby(["Pclass", "Sex"]).mean()
Age | ||
---|---|---|
Pclass | Sex | |
1 | female | 34.611765 |
male | 41.281386 | |
2 | female | 28.722973 |
male | 30.740707 | |
3 | female | 21.750000 |
male | 26.507589 |
- 객실과 성별 별로 나이의 중앙값
- 중앙값을 결측치에 채우기 위해 age_table 에 담는다.
age_table = train[['Pclass', 'Sex' , 'Age']].groupby(by=["Pclass", "Sex"]).median()
age_table
Age | ||
---|---|---|
Pclass | Sex | |
1 | female | 35.0 |
male | 40.0 | |
2 | female | 28.0 |
male | 30.0 | |
3 | female | 21.5 |
male | 25.0 |
# Series 형태
age_table.loc[3,'female'][0]
21.5
# 튜플 방식으로 출력 (행, 열)
age_table.loc[(3,'female'), 'Age']
21.5
for i in range(1, 100):
train.iloc[i]
np.isnan() 함수
- 데이터 값이 결측치인지 아닌지 확인해주는 함수
- 결측치를 채우는 함수를 만든다.
- 결측치가 있다면 age_table 데이터 값으로 채워준다.
def fill_age(person):
if np.isnan(person['Age']):
return age_table.loc[person['Pclass'],person['Sex']][0]
else:
return person['Age']
# fill_age 의 parameter
fill_age(train.iloc[1])
38.0
# 5번째 행의 age 는 null 이다.
np.isnan(train.iloc[5]['Age'])
True
### 결측치 확인
train.iloc[5]
Survived 0
Pclass 3
Name Moran, Mr. James
Sex male
Age NaN
SibSp 0
Parch 0
Ticket 330877
Fare 8.4583
Cabin NaN
Embarked Q
Name: 5, dtype: object
# apply : 한 줄씩 입출력하는 것
train['Age'] = train.apply(fill_age, axis=1)
test['Age'] = test.apply(fill_age, axis=1)
공통: cabin 데이터 결측치 채우기
- 결측치 양이 많을 때는 상관관계를 보기가 어렵다.
- 모든 결측치를 하나의 값으로 채우는 방법을 택한다.
- 결측치 의미 : Cabin 값 확인을 못했다. (= 사망을 했거나 cabin 이 없는 3등급의 사람일 수 있다.)
- 원래 순서대로라면 결측치가 의미하는 게 무엇인지 상관관계를 먼저 파악해야 한다.
# unique
train['Cabin'].unique()
array([nan, 'C85', 'C123', 'E46', 'G6', 'C103', 'D56', 'A6',
'C23 C25 C27', 'B78', 'D33', 'B30', 'C52', 'B28', 'C83', 'F33',
'F G73', 'E31', 'A5', 'D10 D12', 'D26', 'C110', 'B58 B60', 'E101',
'F E69', 'D47', 'B86', 'F2', 'C2', 'E33', 'B19', 'A7', 'C49', 'F4',
'A32', 'B4', 'B80', 'A31', 'D36', 'D15', 'C93', 'C78', 'D35',
'C87', 'B77', 'E67', 'B94', 'C125', 'C99', 'C118', 'D7', 'A19',
'B49', 'D', 'C22 C26', 'C106', 'C65', 'E36', 'C54',
'B57 B59 B63 B66', 'C7', 'E34', 'C32', 'B18', 'C124', 'C91', 'E40',
'T', 'C128', 'D37', 'B35', 'E50', 'C82', 'B96 B98', 'E10', 'E44',
'A34', 'C104', 'C111', 'C92', 'E38', 'D21', 'E12', 'E63', 'A14',
'B37', 'C30', 'D20', 'B79', 'E25', 'D46', 'B73', 'C95', 'B38',
'B39', 'B22', 'C86', 'C70', 'A16', 'C101', 'C68', 'A10', 'E68',
'B41', 'A20', 'D19', 'D50', 'D9', 'A23', 'B50', 'A26', 'D48',
'E58', 'C126', 'B71', 'B51 B53 B55', 'D49', 'B5', 'B20', 'F G63',
'C62 C64', 'E24', 'C90', 'C45', 'E8', 'B101', 'D45', 'C46', 'D30',
'E121', 'D11', 'E77', 'F38', 'B3', 'D6', 'B82 B84', 'D17', 'A36',
'B102', 'B69', 'E49', 'C47', 'D28', 'E17', 'A24', 'C50', 'B42',
'C148'], dtype=object)
# unique
test['Cabin'].unique()
array([nan, 'B45', 'E31', 'B57 B59 B63 B66', 'B36', 'A21', 'C78', 'D34',
'D19', 'A9', 'D15', 'C31', 'C23 C25 C27', 'F G63', 'B61', 'C53',
'D43', 'C130', 'C132', 'C101', 'C55 C57', 'B71', 'C46', 'C116',
'F', 'A29', 'G6', 'C6', 'C28', 'C51', 'E46', 'C54', 'C97', 'D22',
'B10', 'F4', 'E45', 'E52', 'D30', 'B58 B60', 'E34', 'C62 C64',
'A11', 'B11', 'C80', 'F33', 'C85', 'D37', 'C86', 'D21', 'C89',
'F E46', 'A34', 'D', 'B26', 'C22 C26', 'B69', 'C32', 'B78',
'F E57', 'F2', 'A18', 'C106', 'B51 B53 B55', 'D10 D12', 'E60',
'E50', 'E39 E41', 'B52 B54 B56', 'C39', 'B24', 'D28', 'B41', 'C7',
'D40', 'D38', 'C105'], dtype=object)
train['Cabin']
0 NaN
1 C85
2 NaN
3 C123
4 NaN
...
886 NaN
887 B42
888 NaN
889 C148
890 NaN
Name: Cabin, Length: 891, dtype: object
# Object 형식은 indexing 할 수 없으므로 str 형식으로 바꿔준다.
# str 형식으로 나온 A,B,C (첫 번째 글자) 를 저장한다.
train['Cabin'] = train['Cabin'].str[0]
test['Cabin'] = test['Cabin'].str[0]
- 결측치를 'M' 값으로 채운다.
train['Cabin'].fillna('M', inplace=True) test['Cabin'].fillna('M', inplace=True)
train['Cabin']
0 M
1 C
2 M
3 C
4 M
..
886 M
887 B
888 M
889 C
890 M
Name: Cabin, Length: 891, dtype: object
- 결측치가 모두 채워진 것을 확인한다.
train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 11 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Survived 891 non-null int64
1 Pclass 891 non-null int64
2 Name 891 non-null object
3 Sex 891 non-null object
4 Age 891 non-null float64
5 SibSp 891 non-null int64
6 Parch 891 non-null int64
7 Ticket 891 non-null object
8 Fare 891 non-null float64
9 Cabin 891 non-null object
10 Embarked 891 non-null object
dtypes: float64(2), int64(4), object(5)
memory usage: 76.7+ KB
test.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Pclass 418 non-null int64
1 Name 418 non-null object
2 Sex 418 non-null object
3 Age 418 non-null float64
4 SibSp 418 non-null int64
5 Parch 418 non-null int64
6 Ticket 418 non-null object
7 Fare 418 non-null object
8 Cabin 418 non-null object
9 Embarked 418 non-null object
dtypes: float64(1), int64(3), object(6)
memory usage: 32.8+ KB
4. EDA 탐색적 데이터 분석
- 특성공학 : 컬럼에 연산을 통해서 의미있는 새로운 정보를 추출하는 행위
Family_size column 분석
- 4-1) 특성 확장
- SibSp, Parch 사이의 연관성을 파악한다.
- Family_size : 형제자매수(SibSp) + 부모자식수 (Parch) + 1
test['Family_size']=test['SibSp'] + test['Parch'] + 1
train['Family_size']=train['SibSp'] + train['Parch'] + 1
sns.countplot
- 그래프를 그려 연관성을 확인한다.
# x 축 하나에 비교값이 여러 개 가능 (hue == 구분자)
sns.countplot(data = train, x='Family_size', hue='Survived')
<AxesSubplot:xlabel='Family_size', ylabel='count'>
결과: 가족이 없는 경우 사망률이 더 높고, 2-4 명의 가족이 있는 경우 생존률이 비교적 높다.
Binning
- 수치형 데이터를 범주형 데이터로 바꾼다.
DataFrame.cut()
- 수치형 데이터를 범주형 데이터로 바꿔주는 것
- Parameter
bins
: 구간(속성 값), int형으로 입력한다.labels
: 구간에 대한 범주 이름(속성에 대한 이름), int형으로 입력한다.
bins=[0,1,4,20]
# 0< x <=1 / 1< x <=4 / 4< x <=20
# 0 < x <=1 == Alone
labels = ['Alone','Small','Large']
train['Family_Group'] = pd.cut(train['Family_size'],bins=bins, labels=labels)
train.columns
Index(['Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket',
'Fare', 'Cabin', 'Embarked', 'Family_size', 'Family_Group'],
dtype='object')
test['Family_Group'] = pd.cut(test['Family_size'],bins=bins, labels=labels)
sns.countplot(data = train, x='Family_Group', hue='Survived')
<AxesSubplot:xlabel='Family_Group', ylabel='count'>
Cabin column 분석
sns.countplot(data = train, x='Cabin', hue='Survived')
<AxesSubplot:xlabel='Cabin', ylabel='count'>
결과: M 에서 상대적으로 많은 사람이 죽었다. (M == null)
- 생존 여부 판단에 사용할 수 있다.
-
Pclass column 분석
sns.countplot(data = train, x='Pclass', hue='Survived')
<AxesSubplot:xlabel='Pclass', ylabel='count'>
결과: 등급이 높아질수록 생존률이 높다.
Cabin과 Pclass 컬럼 확인
sns.countplot(data = train, x='Cabin', hue='Pclass')
<AxesSubplot:xlabel='Cabin', ylabel='count'>
결과: M은 3등급 사람들이 많다. 사망자의 비율이 높음.
- A, B, C 구역에는 1등급만 존재한다. 생존 확률이 더 높다.
Embarked column 분석
sns.countplot(data = train, x='Embarked', hue='Survived')
<AxesSubplot:xlabel='Embarked', ylabel='count'>
결과: S, Q에서 탑승한 경우 사망률이 생존률보다 높다.
Age column 확인
# violinplot > 두 데이터 비교에 용이, 차지하는 크기는 데이터 수와 비례하지 않음. (비율과 비례함.)
sns.violinplot(data=train, x='Sex', y='Age', hue='Survived', split=True)
<AxesSubplot:xlabel='Sex', ylabel='Age'>
결과
- 남자는 산 사람과 죽은 사람의 나이대가 차이가 있다.
- 여자는 산 사람과 죽은 사람의 나이대가 비슷하다.
- 어린 아이들의 경우 상대적으로 남자 아이의 생존률이 더 높다.
Fare column 확인
sns.violinplot(data=train, x='Sex', y='Fare', hue='Survived', split=True)
<AxesSubplot:xlabel='Sex', ylabel='Fare'>
결과: 저렴한 요금을 낸 경우 사망률이 더 높다.
sns.countplot(data = train, x='Sex', hue='Survived')
<AxesSubplot:xlabel='Sex', ylabel='count'>
sns.countplot(data = train, y='Sex', hue='Survived')
<AxesSubplot:xlabel='count', ylabel='Sex'>
Text 데이터 (Name, Ticket column)
- 4-2) 비정형 데이터(문자 데이터) > 정형 데이터(수치형 데이터)
- 텍스트 데이터(비정형 데이터)는 머신러닝이 학습을 할 수 없다.
- 비정형 데이터를 특성공학을 통해 정형데이터로 만들어보자.
Name Column
- 이름 내 호칭을 사용할 수 있음.
- 이름에 대한 특성 파악
- 첫 번째는 '성'과 ','이 들어감.
- 두 번째는 호칭 뒤에 '.(온점)'이 들어감.
train['Name'][0]
'Braund, Mr. Owen Harris'
- 정형화
- split 함수로 (',') 기준으로 나눔
- 나눈 데이터 중 두 번째 데이터 씀.
- 그 데이터를 다시 ('.') 기준으로 나눔.
- 나눈 데이터 중 첫 번째 데이터 씀.
- strip(): 문자 앞 뒤의 띄어쓰기(공백) 제거
train['Name'][0].split(',')[1].split('.')[0].strip()
'Mr'
# 함수 작성
# 테이블의 한 줄이 parameter 로 들어옴.
def split_title(name):
return name.split(',')[1].split('.')[0].strip()
train['Name'].apply(split_title)
0 Mr
1 Mrs
2 Miss
3 Mrs
4 Mr
...
886 Rev
887 Miss
888 Miss
889 Mr
890 Mr
Name: Name, Length: 891, dtype: object
# Name 컬럼을 Title 로 바꾸기
train['Title'] = train['Name'].apply(split_title)
test['Title'] = test['Name'].apply(split_title)
train.drop('Name', axis=1, inplace=True)
test.drop('Name', axis=1, inplace=True)
train['Title'].value_counts()
Mr 517
Miss 182
Mrs 125
Master 40
Dr 7
Rev 6
Col 2
Mlle 2
Major 2
Mme 1
Ms 1
Don 1
Sir 1
the Countess 1
Lady 1
Jonkheer 1
Capt 1
Name: Title, dtype: int64
# def map_title(name):
# if(name == 'Mr' or 'Miss' or 'Mrs' or 'Master' or 'Dr'):
# return name
# else:
# return name.map('Other')
# train['Title2'] = train['Title'].apply(map_title)
# train['Title2'][30]
# train['Title2'].unique()
호칭의 범주를 줄여보자.
- Mr Mrs Miss Master Dr Other
- Map 함수를 활용해서 mapping
convert_title_dic = {
'Mr' : 'Mr' ,
'Mrs' : 'Mrs',
'Miss' : 'Miss',
'Master' : 'Master',
'Don' : 'Other',
'Rev' : 'Rev',
'Dr': 'Other',
'Mme' : 'Other',
'Ms' : 'Other',
'Major' : 'Other',
'Lady' : 'Other',
'Sir' : 'Other',
'Mlle' : 'Other',
'Col' : 'Other',
'Capt' : 'Other',
'the Countess' : 'Other',
'Jonkheer' : 'Other',
'Dona' : 'Other'
}
train['Title'] = train['Title'].map(convert_title_dic)
test['Title'] = test['Title'].map(convert_title_dic)
train['Title'].unique()
array(['Mr', 'Mrs', 'Miss', 'Master', 'Other', 'Rev'], dtype=object)
test['Title'].unique()
array(['Mr', 'Mrs', 'Miss', 'Master', 'Other', 'Rev'], dtype=object)
Ticket data
- 중복되지 않는 값이 681개, 사용하기 어렵다.
- 삭제
train['Ticket'].value_counts()
1601 7
CA. 2343 7
347082 7
3101295 6
347088 6
..
349223 1
349246 1
2697 1
370372 1
36967 1
Name: Ticket, Length: 681, dtype: int64
train['Ticket'].str[:1].value_counts()
3 301
2 183
1 146
P 65
S 65
C 47
A 29
W 13
4 10
7 9
F 7
6 6
L 4
5 3
8 2
9 1
Name: Ticket, dtype: int64
train.drop('Ticket', axis = 1, inplace = True)
test.drop('Ticket', axis = 1, inplace = True)
train.columns.unique()
Index(['Survived', 'Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Cabin',
'Embarked', 'Family_size', 'Family_Group', 'Title'],
dtype='object')
train.shape, test.shape
((891, 12), (418, 11))
글자 데이터를 숫자 데이터로 변경해보자.
- 문자 데이터 > Sex, Cabin, Embarked, Family_group, Title
- 4-3) 원핫 인코딩(OneHotEncoding): 5개 문자 컬럼을 수치화 한다.
- 머신러닝 모델은 수치 데이터만 학습할 수 있기 때문에 문자 데이터를 수치 데이터로 변경해야 함.
# One-hot Encoding 함수
categorical_feature = ['Sex', 'Cabin', 'Embarked', 'Family_Group', 'Title']
# train, test 함수를 합친 상태에서 진행해야 함.
# 합친 후 다시 7:3 비율로 나눠야함.
# 합칠 수 있도록 column 개수를 맞춰줘야 함.
train.shape, test.shape
((891, 12), (418, 11))
# 정답 컬럼 분리
y_train = train['Survived']
# train 에서 Survived 컬럼 삭제
train.drop('Survived', axis=1, inplace=True)
# concat : 행, 열을 기준으로 데이터프레임을 합침.
# merge : 데이터를 기준으로 데이터프레임을 합침.
pd.concat([train, test])
Pclass | Sex | Age | SibSp | Parch | Fare | Cabin | Embarked | Family_size | Family_Group | Title | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3 | male | 22.0 | 1 | 0 | 7.25 | M | S | 2 | Small | Mr |
1 | 1 | female | 38.0 | 1 | 0 | 71.2833 | C | C | 2 | Small | Mrs |
2 | 3 | female | 26.0 | 0 | 0 | 7.925 | M | S | 1 | Alone | Miss |
3 | 1 | female | 35.0 | 1 | 0 | 53.1 | C | S | 2 | Small | Mrs |
4 | 3 | male | 35.0 | 0 | 0 | 8.05 | M | S | 1 | Alone | Mr |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
413 | 3 | male | 25.0 | 0 | 0 | 8.05 | M | S | 1 | Alone | Mr |
414 | 1 | female | 39.0 | 0 | 0 | 108.9 | C | C | 1 | Alone | Other |
415 | 3 | male | 38.5 | 0 | 0 | 7.25 | M | S | 1 | Alone | Mr |
416 | 3 | male | 25.0 | 0 | 0 | 8.05 | M | S | 1 | Alone | Mr |
417 | 3 | male | 25.0 | 1 | 1 | 22.3583 | M | C | 3 | Small | Master |
1309 rows × 11 columns
combine = pd.concat([train, test], ignore_index=True)
combine.head()
Pclass | Sex | Age | SibSp | Parch | Fare | Cabin | Embarked | Family_size | Family_Group | Title | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3 | male | 22.0 | 1 | 0 | 7.25 | M | S | 2 | Small | Mr |
1 | 1 | female | 38.0 | 1 | 0 | 71.2833 | C | C | 2 | Small | Mrs |
2 | 3 | female | 26.0 | 0 | 0 | 7.925 | M | S | 1 | Alone | Miss |
3 | 1 | female | 35.0 | 1 | 0 | 53.1 | C | S | 2 | Small | Mrs |
4 | 3 | male | 35.0 | 0 | 0 | 8.05 | M | S | 1 | Alone | Mr |
# 원핫 인코딩
# get_dummies 함수
one_hot = pd.get_dummies(combine[categorical_feature])
one_hot.head()
Sex_female | Sex_male | Cabin_A | Cabin_B | Cabin_C | Cabin_D | Cabin_E | Cabin_F | Cabin_G | Cabin_M | ... | Embarked_S | Family_Group_Alone | Family_Group_Small | Family_Group_Large | Title_Master | Title_Miss | Title_Mr | Title_Mrs | Title_Other | Title_Rev | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | ... | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
2 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | ... | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
3 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
4 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | ... | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
5 rows × 23 columns
# 기존 문자데이터 삭제
combine.head()
Pclass | Sex | Age | SibSp | Parch | Fare | Cabin | Embarked | Family_size | Family_Group | Title | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3 | male | 22.0 | 1 | 0 | 7.25 | M | S | 2 | Small | Mr |
1 | 1 | female | 38.0 | 1 | 0 | 71.2833 | C | C | 2 | Small | Mrs |
2 | 3 | female | 26.0 | 0 | 0 | 7.925 | M | S | 1 | Alone | Miss |
3 | 1 | female | 35.0 | 1 | 0 | 53.1 | C | S | 2 | Small | Mrs |
4 | 3 | male | 35.0 | 0 | 0 | 8.05 | M | S | 1 | Alone | Mr |
# combine 함수 내 categoricatl_feature(문자 데이터 전부)를 삭제한다.
combine.drop(categorical_feature, axis=1, inplace=True)
combine.head()
Pclass | Age | SibSp | Parch | Fare | Family_size | |
---|---|---|---|---|---|---|
0 | 3 | 22.0 | 1 | 0 | 7.25 | 2 |
1 | 1 | 38.0 | 1 | 0 | 71.2833 | 2 |
2 | 3 | 26.0 | 0 | 0 | 7.925 | 1 |
3 | 1 | 35.0 | 1 | 0 | 53.1 | 2 |
4 | 3 | 35.0 | 0 | 0 | 8.05 | 1 |
# 지운 후, one_hot encoding data 를 합쳐준다. total_combine 함수에 저장
total_combine = pd.concat([combine, one_hot], axis=1)
total_combine.shape
(1309, 29)
total_combine.head()
Pclass | Age | SibSp | Parch | Fare | Family_size | Sex_female | Sex_male | Cabin_A | Cabin_B | ... | Embarked_S | Family_Group_Alone | Family_Group_Small | Family_Group_Large | Title_Master | Title_Miss | Title_Mr | Title_Mrs | Title_Other | Title_Rev | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3 | 22.0 | 1 | 0 | 7.25 | 2 | 0 | 1 | 0 | 0 | ... | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
1 | 1 | 38.0 | 1 | 0 | 71.2833 | 2 | 1 | 0 | 0 | 0 | ... | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
2 | 3 | 26.0 | 0 | 0 | 7.925 | 1 | 1 | 0 | 0 | 0 | ... | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
3 | 1 | 35.0 | 1 | 0 | 53.1 | 2 | 1 | 0 | 0 | 0 | ... | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
4 | 3 | 35.0 | 0 | 0 | 8.05 | 1 | 0 | 1 | 0 | 0 | ... | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
5 rows × 29 columns
5. 모델 선택 및 하이퍼파라미터 조정
from sklearn.tree import DecisionTreeClassifier # 분류
tree_model = DecisionTreeClassifier()
6. 학습
X_train = total_combine.iloc[:891]
X_test = total_combine.iloc[891:]
print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
(891, 29)
(418, 29)
(891,)
tree_model.fit(X_train, y_train)
DecisionTreeClassifier()
pre = tree_model.predict(X_test)
gender = pd.read_csv('./gender_submission.csv')
# gender DataFrame 에 Survived 라는 컬럼으로 pre 값 저장
gender['Survived']= pre
gender.to_csv('mySubmission01.csv', index=False)
'데이터 분석' 카테고리의 다른 글
[머신러닝 데이터 분석] Iris 품종 분류 (0) | 2021.07.18 |
---|
Contents
소중한 공감 감사합니다