들어가며
머신러닝 수업이 있는 첫날이다. 첫날인 만큼 깊게 다루지는 않겠지만 뭐든지 기초가 중요한 만큼 배운 내용을 복기하는 시간을 가져보자.
Numpy
Numpy는 대규모 다차원 배열과 행렬 연산에 필요한 다양한 함수와 메소드를 제공하는 라이브러리이다. 간단한 1차원 행렬을 만들어보자. 리스트와는 다르게 comma `,`가 없는 것을 확인할 수 있다. 또한 여러 개의 정수 중 하나라도 실수가 존재한다면 모든 요소의 자료형이 `float`로 바뀐다. 그 이유는 정수형(4byte)이 실수형(8byte)보다 크기가 작기 때문에 모든 요소의 크기를 통일하기 위해서 큰 자료형에 맞추기 때문이다.
a:np.ndarray = np.array(object=[1, 2, 3]) # (:) 파스칼 노테이션
print(a) # [1 2 3]
print(type(a)) # <class 'numpy.ndarray'>
b = np.array([1, 2, 3, 4, 5, 6, 7.0, 8, 9, 10])
print(b) # [ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
print(type(b)) # <class 'numpy.ndarray'>
`zeros()`는 행렬의 모든 요소를 0으로 초기화할 수 있는 메서드이다. `shape`에 초기화하고자 하는 행렬의 크기를 지정해주면 그 크기만큼 모든 요소를 0으로 초기화 해준다. 모두 1로 초기화하는 메서드는 `ones()`이다. 인덱싱을 해서 원하는 요소를 선택하는 방법은 리스트와 거의 동일하다. 차이점이 있다면 numpy배열은 `[0, 0]`와 같이 2차원 배열에서 한 대괄호 안에 `,`를 기준으로 선택할 수도 있다.
c = np.zeros(shape=(3, 4)) # 행렬 초기화
print(f'NP.ZEROS : \n{c}')
# NP.ZEROS :
# [[0. 0. 0. 0.]
# [0. 0. 0. 0.]
# [0. 0. 0. 0.]]
# a = [1 2 3]
print(a[0]) # 1
print(a[1]) # 2
print(c[0][0]) # 0.0
print(c[0, 0]) # 0.0
d = np.ones((4, 4))
print(d)
# [[1. 1. 1. 1.]
# [1. 1. 1. 1.]
# [1. 1. 1. 1.]
# [1. 1. 1. 1.]]
정렬해주는 메서드 `sort()`이다. 리스트의 `sort()` 와는 다르게 결과를 어떤 변수에 할당해주지 않으면 결과 반영이 되지 않는다. 아무래도 데이터를 다루는 과정에서 원본을 훼손하는 행위를 방지하기 위함이지 않나 싶다.
np_array = np.array([2, 1, 5, 3, 7, 4, 6, 8])
print(np_array) # [2 1 5 3 7 4 6 8]
print(np.sort(np_array)) # [1 2 3 4 5 6 7 8]
print(np_array) # [2 1 5 3 7 4 6 8] # 정렬 결과 반영 안됨
np_array_sorting = np.sort(np_array) # 정렬 결과 변수에 할당
print(np_array_sorting) # [1 2 3 4 5 6 7 8] 정렬된 결과
`concatenate()`로 두 행렬을 붙일 수 있다. `axis`를 0으로 지정하면 행방향으로, 1로 지정하면 열방향으로 붙여준다. 교수님께서 Trailing Comma 라는 용어를 사용하셨는데 배열 끝 요소까지 `,`를 붙여주는 것을 말한다. 이러한 방법은 사람의 실수를 방지하기 위함이며, 향후 버전관리에서 변경사항(commit)을 명시적으로 파악하기 위해 사용된다고 한다. 따라서 오류는 아니다.
# 행방향으로 붙이기
x1 = np.array([[1, 2, ], [3, 4, ]]) # Trailing Comma
y1 = np.array([[5, 6, ], [7, 8, ]])
result1 = np.concatenate((x1, y1), axis=0)
print(result1)
# [[1 2]
# [3 4]
# [5 6]
# [7 8]]
# 열방향으로 붙이기
x2 = np.array([[1, 2, ], [3, 4, ]])
y2 = np.array([[5, 6, ], [7, 8, ]])
result2 = np.concatenate((x2, y2), axis=1)
print(result2)
# [[1 2 5 6]
# [3 4 7 8]]
`range()`와 거의 유사한 `arange()`는 해당 범위만큼의 수를 생성한다. 또한 `reshape()`을 통해 매개변수로 원하는 크기로 배열을 재정의 해줄 수도 있다.
array_1 = np.arange(12)
print(array_1) # [0 1 2 3 4 5 6 7 8 9 10 11]
print(array_1.reshape(3, 4))
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print(array_1.reshape(4, 3))
# [[ 0 1 2]
# [ 3 4 5]
# [ 6 7 8]
# [ 9 10 11]]
`newaxis`로 새로운 축을 추가해줄 수 있다. `shape`을 보면 벡터 값에서 1축이 추가된 것을 확인할 수 있다. 여기서 자주 사용되는 `shape`은 numpy계열에서만 사용 가능하다.
# 차원 증가, 차원 축소
array_5 = np.array([1, 2, 3, 4, 5, 6])
print(f'ARRAY_5 : {array_5.shape}') # (6, ) -> 벡터
array_5_1 = array_5[np.newaxis, :] # (:) 반복 구문
print(array_5_1) # [[1 2 3 4 5 6]]
print(array_5_1.shape) # (1, 6) -> shape은 numpy계열만 사용가능
array_1_5 = array_5[:, np.newaxis]
print(array_1_5)
print(array_1_5.shape)
하나의 요소를 선택하면 단일값으로 출력되고, 여러 요소를 선택하면 행렬 형태로 출력된다. 또한 `mean`메서드로 `axis`값에 0을 주면 행방향 평균값을, 1을 주면 열방향 평균값을 계산한다.
ages = np.array([18, 19, 25, 30, 28,])
print(ages[0]) # 18 단일 값
print(ages[:]) # [18 19 25 30 28] 모든 값
print(ages[1:]) # [19 25 30 28] 차원이 줄지 않음
# 복수의 값이 있으면 변수s
scores = np.array([[99, 93, 60, ], [98, 82, 93, ], [93, 65, 81, ], [78, 82, 81, ]])
print(scores.mean(axis=0)) # [92. 80.5 78.75]
print(scores.mean(axis=1)) # [84. 91. 79.66666667 80.33333333]
Matplotlib
matplotlib는 Python 프로그래밍 언어 및 수학적 확장 Numpy 라이브러리를 활용한 플로팅 라이브러리이다. 아래 예제처럼 그래프를 그리는데 많이 사용한다.
x = np.arange(start=0, stop=20, step=1) # 독립변수 : 벡터 x가 가지는 범위(축)
y1 = 2 * np.ones(20)
y2 = x
y3 = np.square(x)
plt.plot(x, y1, x, y2, x, y3)
plt.show()
간단하게 데이터 전처리를 해보자. 활용될 데이터프레임은 유명한 `titanic.csv`이다. seaborn라이브러리에 내장된 `load_dataset()`을 이용해서 `titanic.csv`를 불러온다. 생존여부, 좌석등급, 성별, 나이, 등등 15개의 변수와 891개의 승객 정보가 담긴 행을 확인할 수 있다.
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
titanic = sns.load_dataset(name='titanic')
print(titanic)
print(titanic.shape)
titanic.to_csv(path_or_buf='titanic.csv', index=False) # csv파일로 저장
`fillna()`메서드로 결측치를 다른 값으로 대체해줄 수 있다. 다음은 `age`, `embarked`, `embarked_town`, `deck`의 결측치를 알맞은 값으로 대체해주는 과정이다. `embrked`와 `embarked_town`은 사실상 같은 속성이라고 봐도 무방하다. 마지막 `isnull().sum()`으로 결측치가 모두 대체되었는지 확인할 수 있다.
print(titanic.isnull().sum()) # 각 변수마다 NaN의 개수
# 나이 결측치 값을 전체 나이의 중간 값으로 대체
print(titanic['age']) # 채우기 전
titanic['age'] = titanic['age'].fillna(value=titanic['age'].median())
print(titanic['age']) # 채운 후
# 탑승 위치의 결측치 값을 S(사우샘프턴)으로 대체
print(titanic['embarked'].value_counts())
titanic['embarked'] = titanic['embarked'].fillna(value='S')
print(titanic['embarked'])
# 탑승 위치의 결측치 값을 Southampton으로 대체
print(titanic['embark_town'].value_counts())
titanic['embark_town'] = titanic['embark_town'].fillna(value='Southampton')
print(f"titanic['embark_town'] :\r\n{titanic['embark_town']}")
# 데크번호의 결측치를 C로 대체
print(titanic['deck'].value_counts()) # 최빈값이 C인 것을 확인
print(titanic['deck']) # 교체 전
titanic['deck'] = titanic['deck'].fillna(value='C') # 앞에서 나온 최빈값으로 치환
print(titanic['deck']) # 교체 후
# missing value 다 치환되었는지 확인하는 코드
print(titanic.isnull().sum())
타이타닉의 생존확률을 성별로 나누어 그래프로 그려본 결과이다. 수치상으로는 남자의 생존확률이 조금 더 높은 것을 알 수 있다.
# 타이타닉의 생존자 정보
print(titanic['survived'].value_counts()) # 0 죽음, 1 생존
(f, ax) = plt.subplots(nrows=1, ncols=2, figsize=(10, 5))
titanic['survived'][titanic['sex'] == 'male'].value_counts().plot.pie(explode=[0, 0.1], autopct='%1.1f%%', ax=ax[0], shadow=True)
titanic['survived'][titanic['sex'] == 'female'].value_counts().plot.pie(explode=[0, 0.1], autopct='%1.1f%%', ax=ax[1], shadow=True)
ax[0].set_title('Survived(Male)')
ax[1].set_title('Survived(FeMale)')
plt.show()
이번엔 좌석 등급별 생존자 수를 bar형 그래프로 나타낸 결과이다. 3등석의 희생자 수가 월등히 높은 것을 확인할 수 있다. 낮은 등급에 사람이 많고, 구조 여건이 좋지 못했기 때문에 이런 결과가 나오지 않았나 싶다.
sns.countplot(x='pclass', hue='survived', data=titanic)
plt.title(label='Pclass vs Survived')
plt.show()
첫번째는 생존여부와 성인남성인지의 여부 간의 pearson 상관관계를 출력한다. 중간 정도 음의 상관관계를 갖는다.
두번째는 생존여부와 운임요금 간의 pearson 상관관계를 출력한다. 0에 가까우므로 상관관계가 거의 없다고 할 수 있다.
참고로 pearson 상관계수는 두 변수 간의 선형 관계의 강도와 방향을 나타내는 값으로 -1에서 1 사이의 값을 가진다.
- 1에 가까울수록 강한 양의 상관관계를 의미
- -1에 가까울수록 강한 음의 상관관계를 의미
- 0에 가까울수록 상관관계가 거의 없음을 의미
print(titanic['survived'].corr(other=titanic['adult_male'], method='pearson'))
# -0.5570800422053259
print(titanic['survived'].corr(other=titanic['fare'], method='pearson'))
# 0.2573065223849622
`pairplot`은 주어진 데이터의 각 feature들 사이의 모든 관계를 표시하는 메서드이다. `survied`를 기준으로 여러 변수와의 상관관계를 나타내는 매우 다양한 그래프를 도출해낸다.
sns.pairplot(data=titanic, hue='survived')
plt.show()
마무리
머신러닝을 시작하지는 않고 라이브러리의 기초를 숙지한 시간이었다. 또한 교수님께서 중간중간 머신러닝에 활용되는 수학적인 부분을 설명해주셨는데 단순히 코드를 작성하는 것 뿐만 아니라 코드에 적용되는 수학적인 원리까지 놓쳐서는 안될 것 같다.
'ABC부트캠프 테크노트' 카테고리의 다른 글
[20일차] ABC부트캠프 : 머신러닝2 (0) | 2024.07.31 |
---|---|
[19일차] ABC부트캠프 : 머신러닝1 (0) | 2024.07.30 |
[17일차] ABC부트캠프 : 건양대 메디컬 캠퍼스 견학 (0) | 2024.07.26 |
[16일차] ABC부트캠프 : 데이터 분석 팀 프로젝트(2/2) (0) | 2024.07.25 |
[15일차] ABC부트캠프 : 구글 이미지 크롤링 및 데이터 분석 팀 프로젝트(1/2) (0) | 2024.07.24 |