데이터분석

캐클 - 타이타닉 + 데이터 분석 실습

주니빙 2023. 11. 25. 01:15

 

https://www.kaggle.com/code/ash316/eda-to-prediction-dietanic/notebook

(참고) "타이타닉 - 재난으로부터 기계 학습"

 

EDA To Prediction(DieTanic)

Explore and run machine learning code with Kaggle Notebooks | Using data from Titanic - Machine Learning from Disaster

www.kaggle.com

 

 

실습하기에 앞서 데이터를 먼저 불러와준다.

 

생존자와 사망자 비율 원 그래프(맷플롯립), 카운트 플롯(시본)생성

f,ax=plt.subplots(1,2,figsize=(18,8))

data['Survived'].value_counts().plot.pie(explode=[0,0.1],autopct='%1.1f%%',ax=ax[0],shadow=True)
ax[0].set_title('Survived')
ax[0].set_ylabel('')

sns.countplot('Survived',data=data,ax=ax[1])
ax[1].set_title('Survived')

plt.show()

 

TypeError: countplot() got multiple values for argument 'data' #출력

중복된 값을 전달한다는 오류가 발생하는데, 이때 x='Survived'라고 수정해주면 해결된다.

아래 문제 모두 x 값을 정확히 부여해주면 오류 해결

 

f, ax = plt.subplots(1, 2, figsize=(18, 8))

# 첫 번째 그래프: 파이 차트
data['Survived'].value_counts().plot.pie(explode=[0, 0.1], autopct='%1.1f%%', ax=ax[0], shadow=True)
ax[0].set_title('Survived')
ax[0].set_ylabel('')

# 두 번째 그래프: Countplot
sns.countplot(x='Survived', data=data, ax=ax[1])
ax[1].set_title('Survived')

plt.show()

(파란색 : 사망자, 빨간색 : 생존자)

이는 사고에서 많은 승객이 생존하지 못했다는 것을 보여준다.

훈련 세트에는 891명의 승객이 있으며, 약 350명만이 사고에서 생존하였다. 즉, 총 훈련 세트 중에 생존율은 약 38.4%이다.

 

데이터셋의 다양한 특징을 사용하여 생존율을 확인해 본다. 일부 특징은 성별, 탑승 항구, 나이 등이다.

범주형 특징 : 범주형 변수는 두 개 이상의 범주가 있는 변수로, 해당 특징의 각 값은 그들에 의해 범주화될 수 있다. ex) 성별, 탑승 항구

순서형 특징 : 순서형 변수는 범주형 값과 유사하지만 그들 간의 차이점은 값 사이에 상대적인 정렬이나 순위를 갖을 수 있다는 것이다. ex)Pclass(승객이 속한 등급)

연속적인 특징 : 특징이 연속적이라면 해당 특징 열의 최솟값 또는 최댓값 사이의 어떤 두 점 또는 해당 특징 열의 최솟값 또는 최댓값 사이의 값들을 취할 수 있다. ex) 나이

1. 성별을 기준으로 생존율 분석 (범주형 특징)

 

f,ax=plt.subplots(1,2,figsize=(18,8))

#첫 번째 그래프 : 막대 그래프
data[['Sex','Survived']].groupby(['Sex']).mean().plot.bar(ax=ax[0])
ax[0].set_title('Survived vs Sex')

#두 번째 그래프 : 카운트 플롯
sns.countplot(x='Sex',hue='Survived',data=data,ax=ax[1])
ax[1].set_title('Sex:Survived vs Dead')

plt.show()

 

 

배에 탑승한 여성의 생존율은 약 75%이고, 남성의 생존율은 18-19% 정도이다.

배에 있는 남자의 수가 여자의 수보다 훨씬 많다. 그럼에도 불구하고, 생존한 여성의 수는 거의 남성의 두 배이다.

(오른쪽 막대그래프 - 파란색(0) : 사망자, 빨간색(1) : 생존자)

 

2. Pclass(승객이 속한 등급)에 따라 생존율 분석(순서형 특징)

#교차표 생성 후 히트맵 생성(색상 : summer_r)
pd.crosstab(data.Pclass,data.Survived,margins=True).style.background_gradient(cmap='summer_r')

 

f,ax=plt.subplots(1,2,figsize=(18,8))

#첫 번째 그래프 : 막대 그래프
data['Pclass'].value_counts().plot.bar(color=['#CD7F32','#FFDF00','#D3D3D3'],ax=ax[0])
ax[0].set_title('Number Of Passengers By Pclass')
ax[0].set_ylabel('Count')

#두 번째 그래프 : 카운트 플롯
sns.countplot(x='Pclass',hue='Survived',data=data,ax=ax[1])
ax[1].set_title('Pclass:Survived vs Dead')

plt.show()

Pclass 3의 승객 수가 훨씬 많았지만 그들 중에서 생존한 인원은 매우 적다, 대략 25% 정도

Pclass 1의 승객이 구조 중에 매우 높은 우선순위를 가진다는 것을 볼 수 있다.

Pclass 1에서의 생존율은 약 63%이고, Pclass 2에서의 생존율은 약 48%이다. 따라서 돈과 지위가 중요한 역할을 함을 알 수 있다.

(오른쪽 막대그래프 - 파랑색(0) : 사망자, 빨강색(1) : 생존자)

 

3. 성별과 Pclass와의 생존율 분석

#교차표 생성 후 히트맵 생성(색상 : summer_r)
pd.crosstab([data.Sex,data.Survived],data.Pclass,margins=True).style.background_gradient(cmap='summer_r')

 

 

sns.factorplot(x='Pclass',y='Survived',hue='Sex',data=data)
plt.show()
AttributeError: module 'seaborn' has no attribute 'factorplot' #출력

 

이 경우에 FactorPlot을 사용하는 이유는 범주형 값을 쉽게 분리할 수 있기 때문이다.

다만 'factorplot'이 'seaborn' 라이브러리에 존재하지 않는다는 오류가 뜬다.

이는 Seaborn 버전 0.9.0부터는 factorplot catplot으로 대체되었다. 따라서 최신 버전에서는 sns.catplot으로 바꿔서 사용해준다.

sns.catplot(x='Pclass',y='Survived',hue='Sex',data=data, kind="point")
plt.show()

kind = "point"라고 지정해주어야 원하는 그래프가 제대로 출력된다.

crosstab과 catplot을 살펴보면 Pclass1의 여성 생존율이 약 95-96%이다. 왜냐하면 Pclass1의 여성 중 94명 중 3명만이 사망했기 때문이다. 하지만 Pclass1의 남성 생존율은 매우 낮은 걸로 보아, Pclass와 관계없이 여성이 구조 중에 첫 번째로 우선순위를 받았다는 것이 분명하다. 

 

4. 나이에 따른 생존율 분석(연속적인 특징)

print('Oldest Passenger was of:',data['Age'].max(),'Years')
print('Youngest Passenger was of:',data['Age'].min(),'Years')
print('Average Age on the ship:',data['Age'].mean(),'Years')

#출력
Oldest Passenger was of: 80.0 Years
Youngest Passenger was of: 0.42 Years
Average Age on the ship: 29.69911764705882 Years
f,ax=plt.subplots(1,2,figsize=(18,8))

#첫 번째 그래프 : 바이올린 플롯
sns.violinplot(x="Pclass",y="Age", hue="Survived", data=data,split=True,ax=ax[0])
ax[0].set_title('Pclass and Age vs Survived')
ax[0].set_yticks(range(0,110,10))

#두 번째 그래프 : 바이올린 플롯
sns.violinplot(x="Sex",y="Age", hue="Survived", data=data,split=True,ax=ax[1])
ax[1].set_title('Sex and Age vs Survived')
ax[1].set_yticks(range(0,110,10))

plt.show()

시본 라이브러리에 있는 바이올린 플롯

 

(파란색(0) : 사망자, 빨간색(1) : 생존자)

  1. 어린이의 수는 Pclass와 함께 증가하며, 10세 미만의 승객(즉, 어린이)의 생존율은 Pclass와 관계없이 좋아 보인다.
  2. Pclass1에서 20-50세의 승객의 생존 가능성은 높으며 여성은 더욱 높다.
  3. 남성의 경우 나이가 증가함에 따라 생존 가능성이 감소한다.

이전에 확인했듯이 나이 특징에는 177개의 널 값이 있다. 이러한 NaN 값을 대체하기 위해 데이터 집합의 평균 나이를 할당할 수 있다.

그러나 문제는 다양한 나이대의 많은 사람들이 있으므로 4세 어린이에게 29세의 평균 나이를 할당할 수는 없는 상황이다.

따라서 승객이 어떤 연령대에 속하는지 확인할 방법은 'Name' 특징이 있다. 이 특징을 살펴보면 이름에 'Mr' 또는 'Mrs'와 같은 칭호가 있는데, 이를 이용하여 해당 그룹에 대한 'Mr'와 'Mrs'의 평균 값을 할당할 수 있다.

 

이니셜을 추출한다.

data['Initial']=0
for i in data:
    data['Initial']=data.Name.str.extract('([A-Za-z]+)\.') #lets extract the Salutations
#교차표 생성 후 히트맵 생성(색상 : summer_r)
pd.crosstab(data.Initial,data.Sex).T.style.background_gradient(cmap='summer_r') #Checking the Initials with the Sex

 

 

'Mlle' 또는 'Mme'와 같이 철자가 틀린 이니셜을 'Miss'로 대체한다.

data['Initial'].replace(['Mlle','Mme','Ms','Dr','Major','Lady','Countess','Jonkheer','Col','Rev','Capt','Sir','Don'],['Miss','Miss','Miss','Mr','Mr','Mrs','Mrs','Other','Other','Other','Mr','Mr','Mr'],inplace=True)
data.groupby('Initial')['Age'].mean() #Initials별 평균 나이를 확인

# NaN 값에 평균 나이의 올림 값 할당하기
data.loc[(data.Age.isnull())&(data.Initial=='Mr'),'Age']=33
data.loc[(data.Age.isnull())&(data.Initial=='Mrs'),'Age']=36
data.loc[(data.Age.isnull())&(data.Initial=='Master'),'Age']=5
data.loc[(data.Age.isnull())&(data.Initial=='Miss'),'Age']=22
data.loc[(data.Age.isnull())&(data.Initial=='Other'),'Age']=46
data.Age.isnull().any() #널 값이 더이상 없음

#출력
False

남은 null 값을 모두 없애주었다.

 

f,ax=plt.subplots(1,2,figsize=(20,10))

#첫 번째 그래프 : 히스토그램
data[data['Survived']==0].Age.plot.hist(ax=ax[0],bins=20,edgecolor='black',color='red')
ax[0].set_title('Survived= 0')
x1=list(range(0,85,5))
ax[0].set_xticks(x1)

#두 번째 그래프 : 히스토그램
data[data['Survived']==1].Age.plot.hist(ax=ax[1],color='green',bins=20,edgecolor='black')
ax[1].set_title('Survived= 1')
x2=list(range(0,85,5))
ax[1].set_xticks(x2)

plt.show()

(빨간색(0) : 사망자, 초록색(1) : 생존자)

  1. 5세 미만의 유아들은 대부분 구조되었다. (여성과 어린이를 먼저 구조하는 정책).
  2. 가장 나이가 많은 승객도(80세) 생존했다.
  3. 가장 많은 사망자는 30-40세 연령 그룹에서 발생했다.

 

#factorplot을 catplot으로 바꾸어주고 kind="point" 추가
sns.catplot(x='Pclass',y='Survived',col='Initial',data=data, kind="point")
plt.show()

계급에 관계없이 "여성과 어린이를 먼저"하는 정책

 

5. C(Cherbourg), Q(Queenstown), S(Southampton) - 승객들이 탑승한 지역에 따른 생존율(범주형 특징)

#교차표 생성 후 히트맵 생성(색상 : summer_r)
pd.crosstab([data.Embarked,data.Pclass],[data.Sex,data.Survived],margins=True).style.background_gradient(cmap='summer_r')

 

#factorplot을 catplot으로 바꾸어주고 kind="point" 추가
sns.catplot(x='Embarked',y='Survived',data=data, kind="point")
fig=plt.gcf()
fig.set_size_inches(5,3)
plt.show()

생존 가능성은 C 항구(Cherbourg)에서 가장 높으며 약 0.55이다. 반면 S 항구(Southampton)에서는 가장 낮다.

이를 통해 탑승한 항구에 따라 생존율이 다를 수 있다는 걸 알 수 있다.

f,ax=plt.subplots(2,2,figsize=(20,15))

#첫 번째 그래프 : 카운트 플롯
sns.countplot(x='Embarked',data=data,ax=ax[0,0])
ax[0,0].set_title('No. Of Passengers Boarded')

#두 번째 그래프 : 카운트 플롯
sns.countplot(x='Embarked',hue='Sex',data=data,ax=ax[0,1])
ax[0,1].set_title('Male-Female Split for Embarked')

#세 번째 그래프 : 카운트 플롯
sns.countplot(x='Embarked',hue='Survived',data=data,ax=ax[1,0])
ax[1,0].set_title('Embarked vs Survived')

#네 번째 그래프 : 카운트 플롯
sns.countplot(x='Embarked',hue='Pclass',data=data,ax=ax[1,1])
ax[1,1].set_title('Embarked vs Pclass')

plt.subplots_adjust(wspace=0.2,hspace=0.5)
plt.show()

 

(오른쪽 아래 그래프 - 파랑색(0) : 생존자, 빨강색(1) : 사망자)

  1. 가장 많은 승객이 S에서 탑승했으며 그들 중 대부분은 Pclass3 출신입니다.
  2. C에서 온 승객들은 상당한 비율로 생존한 것으로 보인다. 이는 Pclass1 및 Pclass2 승객 모두를 구조했을 가능성이 있기 때문이다.
  3. S 항구는 주로 부자들이 탑승한 항구로 보인다. 그럼에도 불구하고 여기에서의 생존 가능성은 낮은 이유는 Pclass3 승객 중 많은 사람이 약 81%가 생존하지 못했기 때문이다.
  4. Q 항구의 승객 중 거의 95%가 Pclass3 출신이다.

 

#factorplot을 catplot으로 바꾸어주고 kind="point" 추가
sns.catplot('Pclass','Survived',hue='Sex',col='Embarked',data=data, kind="point")
plt.show()
  1. Pclass와 관계없이 Pclass1 및 Pclass2의 여성들에 대한 생존 가능성은 거의 1에 가깝다.
  2. Pclass3 승객에 대해 남녀 모두 생존율이 매우 낮다. 특히 S 항구는 매우 낮다. 
  3. Pclass3 탑승자 대부분이던 Q 항구는 남성들의 생존율이 매우 낮다.

다음은 캐글에서 이산형 특징로 구분하여 분석하고 있다. 

 

< 기온과 강수량에 따른 지하철 이용 인원 실습 (서울 기준) >

1. 지하철 호선마다 이용 인원 수 비교해보기

2. 기온, 강수량과 지하철 이용 인원간의 상관관계 파악

주 교통 수단인 지하철 이용 인원이 줄어든다는 것은 곧 밖으로 이동하는 사람이 줄어든다는 의미이므로 기온이 매우 높거나 낮을 때 혹은 강수량이 매우 높을 때 지하철 이용 인원이 줄어들거라고 예상

 

먼저 서울 열린 데이터 광장에서 지하철 이용객 수 파일을 읽기 (서울 2022 지하철 이용객 수)

지하철 이용 승객 수를 가져와준 후 NULL 값이 없음을 확인해준다.

컬럼명인 수송일자를 날짜로 바꾸어 주었고 승차/하차 모두 고려할 필요 없이 승차한 인원으로만 지하철 총 이용 승객을 파악해준다.

필요없는 열들은삭제해주고 시간대별로 나누어져 있는 승객의 수를 행마다 모두 더해준 뒤 그 값을 하나의 열로 추가하여 나타내준다.

총 이용 승객의 수를 하나의 열로 추가하여 나타내 주었기 때문에 더 이상 필요없는 시간대별 승객을 모두 지워주고

호선별 이용 승객의 수를 파악하기 위해 호선을 기준으로 총 이용 승객을 합쳐준다.

그래프를 나타내기에 앞서 한글 폰트를 먼저 설정해준다.

시본 라이브러리를 이용하여 호선에 따른 총 이용 승객을 바그래프로 나타내 보았다. 보다싶이 한글 폰트가 깨지지 않은 채 나타나진다.

이를 통해 2호선이 앞도적으로 이용 승객이 많은 것으로 보여지며 그 뒤론 5, 7, 3, 4, 6, 8, 1 호선 순으로 점차 줄어드는 것을 볼 수 있다.

 

이제 호선이 아닌 날짜를 기준으로 총 이용 승객 수를 합쳐준다.

또한 기온과 강수량에 따른 총 이용 승객 수를 알아보기 위하여 기상청에서 방재기상관측 자료를 날씨 데이터로 가져와 읽어준다.

 

날씨 데이터에서 필요없는 컬럼을 지워주고 두 데이터를 합치기 위하여 날씨 데이터에서의 컬렴명 또한 '일시'를 '날짜'로 바꿔준다.

 

두 데이터 모두 '날짜'의 컬럼명을 가지고 있으므로 이제 '날짜'를 기준으로 두 데이터를 병합해준다. 

 

다만 아까 s_date는 날짜를 기준으로 총 이용 승객을 합친 데이터지만 weather와 데이터를 병합해주는 과정에서 다시 '날짜'가 중복된 값으로 나타나므로 중복된 날짜를 제거해준다. 이때 총 이용 승객은  합쳐진 값 그대로 나타나므로 중복된 날짜를 제거해줘도 괜찮다.

 

y축을 총 이용 승객으로 두고 하나는 평균 기온, 하나는 평균 강수량에 대한 산점도 그래프를 그려보았다.

기온과 강수량이 지하철 총 이용 승객 수에 영향을 미칠 것이라고 예상한 것과 달리 영향을 거의 미치지 않는다.

매우 덥거나 매우 추운 날씨에도 지하철 이용 승객이 많은 날이 꽤 존재하며 강수량이 매우 많은 날에도 지하철 이용 승객이 많다.

 

더 정확한 상관관계를 파악하기 위해여 시본 라이브러리를 이용한 히트맵을 그려보았다. 

여기서 총 이용 승객과 일 강수량의 상관 관계는 0.02, 총 이용 승객과 평균 기온의 상관 관계는 0.11으로 둘 다 연관이 거의 없다.

여기서 평균 기온과 일 강수량의 상관 관계는 0.21으로 그나마 가장 높다.

 

이를 보면 평균 기온과 일 강수량의 관계가 비례/반비례 관계는 아니지만 일 강수량이 많은 날에는 평균 기온이 높다는 사실은 알 수 있다.

이는 추운 겨울이 아니라 장마철인 여름에 비가 많이 내려, 일 강수량이 높은 사실을 반증해준다.