AnnSEo.log

[파이썬 머신러닝 완벽가이드] CH01 본문

머신러닝

[파이썬 머신러닝 완벽가이드] CH01

AnnSEo2105 2021. 9. 24. 09:54

머신러닝 : 애플리케이션을 수정하지 않고도 데이터 기반으로 패턴을 학습하고 결과를 예측하는 알고리즘 기법

 

예측 분석(Predictive Analysis)으로 재편중

 

머신러닝

- 지도학습(Supervised Learning)

분류, 회귀, 추천 시스템, 시각/음성 감지/인지, 텍스트 분석, NLP

- 비지도학습(Un-supervised Learning)

클러스터링, 차원 축소, 강화학습

- 강화학습(Reinforment Learning)

 

머신러닝의 가장 큰 단점은 데이터에 매우 의존적이라는 것(Garbage In, Garbage out)

 

파이썬과 R을 기반으로 머신러닝 프로그램을 작성하는데, 이 책에서는 파이썬 이용

- 쉽고 뛰어난 개발 생산성

- 많은 라이브러리

- 뛰어난 확장성, 유연성, 호환성

- 결합된 다양한 애플리케이션 개발 가능

- 엔터프라이즈 아키텍쳐로 확장, 마이크로서비스 기반 실시간 연계 등으로 확산 가능

 

파이썬 머신러닝 주요 패키지

- 머신러닝 패키지 : 사이킷런(Scikit-Learn)

- 행렬/선형대수/통계 패키지 : 넘파이(NumPy), 사이파이(SciPy)

- 데이터 핸들링 : 판다스

- 시각화 : 맷플롯립(Matplotlib), 시본(Seaborn)

그 외 주피터 노트북(Jupyter Notebook) - IPython 툴(대화형 툴)

 

 

공부는 넘파이와 판다스가 머신러닝 예제와 어떻게 결합되어 어떻게 데이터 가공에 사용되는지를 인지하는 방향으로!

 

 

- 넘파이

머신러닝 주요 알고리즘은 선형대수와 통계 등에 기반하고, Numerical Python을 의미하는 NumPy는 선형대수 기반 프로그램을 쉽게 만들 수 있게 지원함. 배열 연산 지원

C/C++과 같은 저수준 언어 기반 호환 API를 제공

파이썬 언어 자체의 성능 제약으로 인해, 수행 성능이 중요한 부분은 C/C++ 기반 코드로 작성하고 이걸 넘파이에서 호출하는 방식으로 쉽게 통합할 수 있다. -> 구글의 텐서플로가 이런 방식으로 배열 연산 수행 속도를 개선하고 넘파이와도 호환될 수 있게 작성됨

 

-> 많은 머신러닝 알고리즘이 넘파이 기반으로 작성돼 있고, 알고리즘의 입력 데이터와 출력 데이터를 넘파이 배열 타입으로 사용함

 

ndarray

넘파이 기반 데이터 타입, 다차원 배열을 쉽게 생성하고 다양한 연산 수행 가능

np.array() : 다양한 인자를 입력받아 ndarray로 변환함

ndarray.shape : ndarray의 차원과 크기를 튜플tuple 형태로 나타내줌

array.ndim : array의 차원

 

ndarray 의 데이터 타입

  • int(8bit, 16bit, 32bit)
  • unsigned int(8bit, 16bit, 32bit)
  • float(16bit, 32bit, 64bit, 128bit)
  • complex 타입(더 큰 숫자 값이나 정밀도)

 

array1 = np.array([1, 2, 3])
print('array1 type:', type(array1))
print('array1 array 형태:', array1.shape)

# array1 type: <class 'numpy.ndarray'>
# array1 array 형태: (3,)

array2 = np.array([[1, 2, 3], [2, 3, 4]])
print('array2 type:', type(array2))
print('array2 array 형태:', array2.shape)

# array2 type: <class 'numpy.ndarray'>
# array2 array 형태: (2, 3)

array3 = np.array([[1, 2, 3]])
print('array3 type:', type(array3))
print('array3 array 형태:', array3.shape)

# array3 type: <class 'numpy.ndarray'>
# array3 array 형태: (1, 3)


print('array1: {:0}차원, array2: {:1}차원, array3: {:2}차원'.format(array1.ndim, array2.ndim, array3.ndim))

 

한 ndarray 안에 int와 float가 함께 있을 수 없음

만약 데이터 유형이 섞인 리스트를 ndarray로 변경하면 데이터 크기가 더 큰 타입으로 형 변환을 일괄 적용한다.

array.dtype으로 속성 확인

array.astype()으로 ndarray 내 데이터 값의 타입 변경도 가능 - 보통 메모리 절약을 위해 사용(ndarray 만들 때 메모리가 많이 사용되고, 데이터 타입이 float이라면 int형으로 바꿔서 메모리를 절약할 수 있음)

 

list1 = [1, 2, 3]
print(type(list1))
array1 = np.array(list1)
print(type(array1))
print(array1, array1.dtype)

# <class 'list'>
# <class 'numpy.ndarray'>
# [1 2 3] int32

list2 = [1, 2, 'test']
array2 = np.array(list2)
print(array2, array2.dtype)

list3 = [1, 2, 3.0]
array3 = np.array(list3)
print(array3, array3.dtype)

# ['1' '2' 'test'] <U11 // 문자열로 형 변환
# [1. 2. 3.] float64 // 실수로 형 변환

 

특정 크기와 차원을 가진 ndarray를 연속값이나 0 또는 1로 초기화해 쉽게 생성해야 할 필요가 있는 경우가 발생할 수 있음

→ arange(), zeros(), ones() 를 이용해 ndarray를 생성

  • arange() : 0부터 함수 인자 값 - 1까지의 값을 순차적으로 ndarray의 데이터 값으로 변환해줌
  • zero() : 함수 인자로 튜플 형태의 shape 값을 입력하면 모든 값을 0으로 채운 해당 shape를 가진 ndarray를 반환한다.
  • ones() : 값을 1로 채움(제로와 비슷한데), dtype을 안정하면 float64 데이터로 채움

 

sequence_array = np.arange(10)
print(sequence_array)
print(sequence_array.dtype, sequence_array.shape)

# [0 1 2 3 4 5 6 7 8 9]
# int32 (10,)

zero_array = np.zeros((3, 2), dtype='int32')
print(zero_array)
print(zero_array.dtype, zero_array.shape)

one_array = np.ones((3,2))
print(one_array)
print(one_array.dtype, one_array.shape)

# [[0 0]
#  [0 0]
#  [0 0]]
# int32 (3, 2)
# [[1. 1.]
#  [1. 1.]
#  [1. 1.]]
# float64 (3, 2)
  • reshape() : ndarray의 차원과 크기를 변경
    • 지정된 사이즈로 변경이 불가능하면 오류 발생
    • 인자로 -1을 적용하는 경우에 효율적
    • -1을 인자로 사용하면 원래 ndarray와 호환되는 새로운 shape로 변환해준다.
    • -1 인자는 reshape(-1, 1)의 형태로 많이 사용 : 여러 개의 로우를 가지되, 반드시 1개의 컬럼을 가진 ndarray로 변환됨을 보장함

 

array5 = np.arange(10)
print('array5:\n', array5)

array6 = array5.reshape(2, 5)
print('array6:\n', array6)

array7 = array5.reshape(5, 2)
print('array7:\n', array7)

array5:
 [0 1 2 3 4 5 6 7 8 9]
array6:
 [[0 1 2 3 4]
 [5 6 7 8 9]]
array7:
 [[0 1]
 [2 3]
 [4 5]
 [6 7]
 [8 9]]


array8 = np.arange(10)
print(array8)
array9 = array8.reshape(-1, 5)
print('array9 shape:', array9.shape)
array10 = array8.reshape(5, -1)
print('array10 shape:', array10.shape)

# [0 1 2 3 4 5 6 7 8 9]
# array9 shape: (2, 5)
# array10 shape: (5, 2)
# 여기서 array9 같은 경우 행은 -1이고 열은 5로 고정하되,
# array8이 10개의 데이터가 들어있으므로 행은 자동으로 5에 맞게 2개를 넣어주게!
# 고정된 5개의 컬럼에 맞는 로우를 자동으로 새롭게 생성해 변환하라는 뜻


array11 = np.arange(8)
array3d = array11.reshape((2, 2, 2))
print('array3d:\n', array3d.tolist())

# 3차원 ndarray를 2차원 ndarray로 변환
array12 = array3d.reshape(-1, 1)
print('array12:\n', array12.tolist())
print('array12 shape:', array12.shape)

# 1차원 ndarray를 2차원 ndarray로 변환
array13 = array11.reshape(-1, 1)
print('array13:\n', array13.tolist())
print('array13 shape:', array13.shape)

array3d:
 [[[0, 1], [2, 3]], [[4, 5], [6, 7]]]
array12:
 [[0], [1], [2], [3], [4], [5], [6], [7]]
array12 shape: (8, 1)
array13:
 [[0], [1], [2], [3], [4], [5], [6], [7]]
array13 shape: (8, 1)

 

 

  • 넘파이의 ndarray의 데이터 세트 만들기 - 인덱싱
    • 특정한 데이터만 추출
      • 단일 값 추출
    • 슬라이싱
      • : 기호 사용해서 연속한 데이터 슬라이싱
      • 단일 값 추출을 제외한 슬라이싱, 팬시 인덱싱, 불린 인덱싱으로 추출한 모든 데이터 세트는 ndarray 타입이다.
      • ':' 기호 앞에 시작 인덱스 생략하면 자동으로 맨 처음 인덱스인 0으로 간주
      • 종료 인덱스 생략시 자동으로 맨 마지막 인덱스로 간주
      • : 기호 앞/뒤에 시작/종료 인덱스 생략시 자동으로 맨 처음/맨 마지막 인덱스로 간주

 

# 1부터 9까지 1차원 ndarray 생성
array14 = np.arange(start=1, stop=10)
print('array14:', array14)
# index는 0부터 시작하므로 array14[2]는 3번째 index 위치의 데이터값을 의미
value = array14[2]
print('value:', value)
print(type(value))

array14: [1 2 3 4 5 6 7 8 9]
value: 3
<class 'numpy.int32'>

array1 = np.arange(start=1, stop=10)
array4 = array1[:3]
print(array4)

array5 = array1[3:]
print(array5)

array6 = array1[:]
print(array6)

[1 2 3]
[4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9]

array1d = np.arange(start=1, stop=10)
array2d = array1d.reshape(3, 3)
print('array2d:\n', array2d)

print('array2d[0:2, 0:2]\n:', array2d[0:2, 0:2])
print('array2d[1:3, 0:3]\n:', array2d[1:3, 0:3])
print('array2d[1:3, :]\n:', array2d[1:3, :])
print('array2d[:, :]\n:', array2d[:, :])
print('array2d[:2, 1:]\n:', array2d[:2, 1:])
print('array2d[:2, 0]\n:', array2d[:2, 0])

array2d:
 [[1 2 3]
 [4 5 6]
 [7 8 9]]
array2d[0:2, 0:2]
: [[1 2]
 [4 5]]
array2d[1:3, 0:3]
: [[4 5 6]
 [7 8 9]]
array2d[1:3, :]
: [[4 5 6]
 [7 8 9]]
array2d[:, :]
: [[1 2 3]
 [4 5 6]
 [7 8 9]]
array2d[:2, 1:]
: [[2 3]
 [5 6]]
array2d[:2, 0]
: [1 4]

 

 

행(row) → axis0

열(column) → axis1

 

  • 팬시 인덱싱(Fancy Indexing)
    • 리스트나 ndarray로 인덱스 집합을 지정하면 해당 위치의 인덱스에 해당하는 ndarray를 반환하는 인덱싱 방식
  • 불린 인덱싱(Boolean Indexing)
    • 조건 필터링과 검색을 동시에 할 수 있어 자주 사용되는 인덱싱 방식
    • ndarray의 필터링 조건을 []을 기재
    • False 값을 무시하고 True 값에 해당하는 인덱스값만 저장함(값을 저장하는게 아니라 인덱스를 저장한다)
    • 저장된 인덱스 데이터 세트로 ndarray 조회

 

array1d = np.arange(start=1, stop=10)
array2d = array1d.reshape(3, 3)

array3 = array2d[[0,1], 2]
print('array2d[[0,1], 2] => ', array3.tolist())

array4 = array2d[[0,1], 0:2]
print('array2d[[0, 1], 0:2] =>', array4.tolist())

array5 = array2d[[0,1]]
print('array2d[[0,1]] =>', array5.tolist())

array2d[[0,1], 2] =>  [3, 6]
array2d[[0, 1], 0:2] => [[1, 2], [4, 5]]
array2d[[0,1]] => [[1, 2, 3], [4, 5, 6]]

array1d = np.arange(start=1, stop=10)
array3 = array1d[array1d > 5]
print('array1d > 5 불린 인덱싱 결과 값 :', array3)

array1d > 5 불린 인덱싱 결과 값 : [6 7 8 9]

array1d > 5

# 넘파이 ndarray 객체에 조건식 할당하면 false, true로 이뤄진 ndarray 객체가 반환됨
# false는 무시하고 true 값이 있는 위치 인덱스 값으로 자동 변환해 
# 해당하는 인덱스 위치의 데이터만 반환
array([False, False, False, False, False,  True,  True,  True,  True])

 

  • 행렬을 정렬하는 대표적인 방법
    • np.sort()
      • 원 행렬은 그대로 유지한 채 원 행렬의 정렬된 행렬을 반환
    • ndarray.sort()
      • 원 행렬 자체를 정렬한 형태로 변환하고 반환 값은 None이다.
    기본적으로 오름차순으로 행렬 내 원소 정렬
  • 내림차순으로 정렬하려면 [::-1]을 적용
  • 정렬된 행렬의 인덱스를 반환
    • argsort() - 원본 행렬 자체를 바꾸진 않음, 행렬을 정렬하고 그 인덱스 추출해서 반환

 

org_array = np.array([3, 1, 9, 5])
print('원본:', org_array)

sort_array1 = np.sort(org_array)
print('np.sort() 호출 후 반환된 정렬 행렬 :', sort_array1)
print('np.sort() 호출 후 반환된 원본 행렬 :', org_array)

sort_array2 = org_array.sort()
print('org_array.sort() 호출 후 반환 행렬:', sort_array2)
print('ort_array.sort() 호출 후 원본 행렬:', org_array)

원본: [3 1 9 5]
np.sort() 호출 후 반환된 정렬 행렬 : [1 3 5 9]
np.sort() 호출 후 반환된 원본 행렬 : [3 1 9 5]
org_array.sort() 호출 후 반환 행렬: None
ort_array.sort() 호출 후 원본 행렬: [1 3 5 9]

sort_array1_desc = np.sort(org_array)[::-1]
print('내림차순으로 정렬:', sort_array1_desc)

내림차순으로 정렬: [9 5 3 1]

array2d = np.array([[8, 12], [7, 1]])
sort_array2d_axis0 = np.sort(array2d, axis = 0)
print('로우 방향으로 정렬:\n', sort_array2d_axis0)

sort_array2d_axis1 = np.sort(array2d, axis=1)
print('컬럼 방향으로 정렬:\n', sort_array2d_axis1)

로우 방향으로 정렬:
 [[ 7  1]
 [ 8 12]]
컬럼 방향으로 정렬:
 [[ 8 12]
 [ 1  7]]

org_array = np.array([3,1,9,5])
sort_indices = np.argsort(org_array)
print(type(sort_indices))
print('행렬 정려 시 원본 행렬의 인덱스:', sort_indices)

<class 'numpy.ndarray'>
행렬 정려 시 원본 행렬의 인덱스: [1 0 3 2]

name_array = np.array(['존', '마이크', '사라', '케이트', '사무엘'])
score_array = np.array([78, 95, 84, 98, 88])

sort_indices_asc = np.argsort(score_array)
print(name_array[sort_indices_asc])
['존' '사라' '사무엘' '마이크' '케이트']

 

  • ndarray는 RDBMS의 TABLE 컬럼이나 판다스 DataFrame 칼럼과 같은 메타 데이터를 갖을 수 없음
  • 고로 실제 값과 그 값이 뜻하는 메타 데이터를 별도의 ndarray로 각각 가져야 한다.

 

 

 

 

  • 선형대수 연산 - 행렬 내적과 전치 행렬 구하기
    • 행렬 내적(행렬 곱) : np.dot()
    • 전치 행렬 : 행과 열을 교환한 원소로 구성한 행렬을 그 행렬의 전치 행렬이라고 함. transpose() 이용
# 행렬 내적(행렬 곱)
A = np.array([[1, 2, 3], [4, 5, 6]])
B = np.array([[7, 8], [9, 10], [11, 12]])
dot_product = np.dot(A, B)
print('행렬 내적 결과:\n',dot_product)

행렬 내적 결과:
 [[ 58  64]
 [139 154]]

A = np.array([[1, 2], [3, 4]])
transpose_mat = np.transpose(A)
print('A의 전치 행렬:\n', transpose_mat)

A의 전치 행렬:
 [[1 3]
 [2 4]]

 

 

csv 파일은 , 로 구분되어 있고 table은 \t(탭)으로 구분되어 있음

필드 구분 문자(Delimeter)의 차이

 

판다스는 다양한 포맷으로 된 파일을 DataFrame으로 로딩할 수 있는 편리한 API를 제공함

read_csv(), read_table(), read_fwf()

read_fwf는 fixed width, 즉 고정 길이 기반 컬럼 포맷을 DataFrame으로 로딩하기 위한 API

 

read_csv()의 인자인 sep에 구분 문자를 넣으면 된다.

예를 들어, 탭으로 구분 되어 있으면

read_csv('파일명', sep='\t')

read_csv에서 sep가 생략되면 자동으로 콤마 , 가 할당됨

 

read_csv(filepath_or_buffer, sep=',' ,...)

 

import pandas as pd

titanic_df = pd.read_csv(r'C:\Users\jnh02\파이썬 머신러닝 완벽가이드\01\titanic_train.csv')
titanic_df.head(3)

print('titanic_df 변수 타입:', type(titanic_df))
titanic_df 변수 타입: <class 'pandas.core.frame.DataFrame'>

print('DataFrame 크기:', titanic_df.shape)
DataFrame 크기: (891, 12)

# 칼럼 타입, Null 데이터 개수, 데이터 분포도 등의 메타 데이터 등 조회
# info(), describe() 
titanic_df.info()
titanic_df.describe()

titanic_pclass = titanic_df['Pclass']
print(type(titanic_pclass))
<class 'pandas.core.series.Series'>


value_counts = titanic_df['Pclass'].value_counts()
print(type(value_counts))
print(value_counts)

<class 'pandas.core.series.Series'>
3    491
1    216
2    184
Name: Pclass, dtype: int64

리스트 → DataFrame

ndarray → DataFrame

딕셔너리 → DataFrame

 

import numpy as np

col_name1=['col1']
list1 = [1, 2, 3]
array1 = np.array(list1)
print('array1 shape:', array1.shape)

#리스트를 이용해 DataFrame 생성
df_list1 = pd.DataFrame(list1, columns=col_name1)
print('1차원 리스트로 만든 DataFrame:\n', df_list1)

#넘파이 ndarray를 이용해 DataFrame 생성
df_array1 = pd.DataFrame(array1, columns=col_name1)
print('1차원 ndarray로 만든 DataFrame:\n', df_array1)

array1 shape: (3,)
1차원 리스트로 만든 DataFrame:
    col1
0     1
1     2
2     3
1차원 ndarray로 만든 DataFrame:
    col1
0     1
1     2
2     3

# 3개의 칼럼명 필요
col_name2=['col1', 'col2', 'col3']

# 2행x3열 형태의 리스트와 ndarray 생성한 뒤 이를 DataFrame으로 변환
list2 = [[1,2,3], [11,12,13]]
array2 = np.array(list2)
print('array2 shape:', array2.shape)

df_list2 = pd.DataFrame(list2, columns=col_name2)
print('2차원 리스트로 만든 DataFrame:\n', df_list2)
df_array2 = pd.DataFrame(array2, columns=col_name2)
print('2차원 ndarray로 만든 DataFrame:\n', df_array2)

array2 shape: (2, 3)
2차원 리스트로 만든 DataFrame:
    col1  col2  col3
0     1     2     3
1    11    12    13
2차원 ndarray로 만든 DataFrame:
    col1  col2  col3
0     1     2     3
1    11    12    13

# key는 문자열 칼럼명으로 매핑, value는 리스트형(또는 ndarray) 컬럼 데이터로 매핑
dict = {'col1':[1, 11], 'col2':[2, 22], 'col3':[3, 33]}
df_dict = pd.DataFrame(dict)
print('딕셔너리로 만든 DataFrame:\n', df_dict )

딕셔너리로 만든 DataFrame:
    col1  col2  col3
0     1     2     3
1    11    22    33

 

 

DataFrame → ndarray (values 이용해 쉽게 바꿀 수 있음)

DataFrame → list (tolist() 이용)

DataFrame → 딕셔너리(to_dict('list') 이용)

 

# DataFrame을 ndarray로 변환
array3 = df_dict.values
print('df_dict.values 타입:', type(array3), 'df_dict.values shape:', array3.shape)
print(array3)

# DataFrame을 리스트로 변환
list3 = df_dict.values.tolist()
print('df_dict.values.tolist() 타입:', type(list3))
print(list3)

# DataFrame을 딕셔너리로 변환
dict3 = df_dict.to_dict('list')
print('\n df_dict.to_dict() 타입:', type(dict3))
print(dict3)

df_dict.values 타입: <class 'numpy.ndarray'> df_dict.values shape: (2, 3)
[[ 1  2  3]
 [11 22 33]]

df_dict.values.tolist() 타입: <class 'list'>
[[1, 2, 3], [11, 22, 33]]

 df_dict.to_dict() 타입: <class 'dict'>
{'col1': [1, 11], 'col2': [2, 22], 'col3': [3, 33]}

 

DataFrame의 칼럼 데이터 세트 생성과 수정

[ ] 연산자를 이용해 데이터 세트 생성과 수정을 쉽게 할 수 있음

 

# Age_0 이라는 컬럼 추가하고 0이라는 값 할당
titanic_df['Age_0']=0
titanic_df.head(3)


# 기존 컬럼 가공해서 새로운 칼럼 Series 생성
titanic_df['Age_by_10'] = titanic_df['Age']*10
titanic_df['Family_No'] = titanic_df['SibSp'] + titanic_df['Parch']+1
titanic_df.head(3)


# 기존 칼럼 값 쉽게 일괄 업데이트
titanic_df['Age_by_10'] = titanic_df['Age_by_10'] + 100
titanic_df.head(3)

 

 

삭제 drop 메서드 이용

DataFrame.drop(labels=None, aixs=0, index=None, columns=None, level=None, inplace=False, errors='raise')

 

titanic_drop_df = titanic_df.drop('Age_0', axis=1)
titanic_drop_df.head(3)
# 원본에는 삭제되어 있지 않음. 
# inplace를 false 설정을 해둬서 그럼

drop_result = titanic_df.drop(['Age_0', 'Age_by_10', 'Family_No'], axis=1, inplace=True)
print('inplcae true로 drop 후 결과:', drop_result)
titanic_df.head(3)
inplcae true로 drop 후 결과: None

# inplace true로 설정하면 반환 값은 None임
# 원본 DataFrame이 알아서 바뀌니 다시 할당하면 안됨
# 다시 할당하면 titnaic_df 객체 변수를 아예 None으로 바꿔버림


pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 15)
print('#### before axis 0 drop ####')
print(titanic_df.head(3))

# 로우 인덱스로 삭제
titanic_df.drop([0,1,2], axis=0, inplace=True)

print('#### after axis 0 drop ####')
print(titanic_df.head(3))
  • axis : DataFrame의 로우를 삭제할 때는 axis=0, 칼럼을 삭제할 때는 axis=1으로 설정
  • 원본 DataFrame을 유지하고 드롭된 DataFrame을 새롭게 객체 변수로 받고 싶으면 inplace=False로 설정(디폴트도 False)
  • 원본 DataFrame에 드롭된 결과를 적용할 경우 inplace=True 로 적용
  • 원본 DataFrame에서 드롭된 DataFrame을 다시 원본 DataFrame 객체 변수로 할당하면 원본 DataFrame에서 드롭된 결과를 적용할 경우와 같음(단, 기존 원본 DataFrame 객체 변수는 메모리에서 추후 제거됨)

 

 

인덱스

  • 식별성 데이터를 1차원 array로 가짐
  • 단일 값 반환, 슬라이싱 가능
  • 한 번 만들어진 DataFrame, Series의 Index 객체는 함부로 변경할 수 없음
  • Series 객체는 Index 객체를 포함하나 Series 객체에 연산 함수를 적용할 때 Index는 연산에서 제외된다. Index는 오직 식별용으로 사용된다.
  • DataFrame 및 Series에서 reset_index() 메서드 수행시 새롭게 인덱스를 연속 숫자형으로 할당하며 기존 인덱스는 'index'라는 새로운 칼럼 명으로 추가한다.
  • Series에 reset_index를 적용하면 DataFrame이 반환된다. 새로운 연속 숫자형 인덱스가 만들어지고 기존 인덱스는 'index' 칼럼명으로 추가되면서 DataFrame을 반환함(Series를 반환하는 것이 아님)
  • reset_index()의 파라미터 중 drop=True를 설정하면 기존 인덱스는 새로운 칼럼으로 추가되지 않고 삭제된다. 새로운 칼럼이 추가되지 않으므로 그대로 Series로 유지된다.

 

 

# 인덱스 객체 추출
indexes = titanic_df.index
print(indexes)

# index 객체를 실제 값 array로 변환
print('Index 객체 array값:\n', indexes.values)


titanic_reset_df = titanic_df.reset_index(inplace=False)
titanic_reset_df.head(3)

print('#### before reset_index ####')
value_counts = titanic_df['Pclass'].value_counts()
print(value_counts)
print('value_counts 객체 타입 변수:', type(value_counts))
new_value_counts = value_counts.reset_index(inplace=False)
print('### After reset_index ###')
print(new_value_counts)
print('new_value_counts 객체 타입 변수:', type(new_value_counts))

 

 

데이터 셀렉션 및 필터링

넘파이의 경우 [ ] 연산자를 통해 단일 값 추출, 슬라이싱, 팬시 인덱싱, 불린 인덱싱을 해서 데이터를 추출함.

판다스는 ix[], iloc[], loc[] 연산자를 통해 동일한 작업을 수행한다.

  • 데이터프레임의 [ ] 연산자
    • 행의 위치, 열의 위치, 슬라이싱 범위 등을 지정해 데이터를 가져올 수 있음
    • [ ] 안에는 칼럼 명 문자, 인덱스로 변환 가능한 표현식
    • DataFrame의 []는 넘파이의 []나 Series[] 와 다름
    • 칼럼명을 지정해 칼럼 지정 연산에 사용하거나 불린 인덱스 용도로만 사용해야 한다.
    • DataFrame[0:2] 같은 슬라이싱 연산으로 데이터 추출은 안하는게 좋음

 

print(titanic_df['Pclass'].head(3))
print(titanic_df[['Pclass', 'Survived']].head(3))
print(titanic_df['Pclass'].head(3))
titanic_df[titanic_df['Pclass']==3].head(3)

 

  • DataFrame ix[] 연산자
    • DataFrame의 인덱스값은 명칭 기반 인덱싱
    • ix[]는 명칭과 위치 기반 인덱싱을 모두 허용하고
    • loc[] 는 명칭 기반 인덱싱
    • iloc[]는 위치 기반 인덱싱
  • iloc[] 연산자
    • 위치 기반 인덱싱
    • 행과 열 값으로 integer 또는 integer형의 슬라이싱, 팬시 리스트 값을 입력
    • 불린 인덱싱은 제공하지 않음
  • loc[] 연산자
    • 명칭 기반 인덱싱
    • 행 위치에는 DataFrame index 값을, 열 위치에는 칼럼 명 입력
    • 인덱스가 숫자 형일 수 있기 때문에 명칭 기반이라고 무조건 문자열을 입력하라는 선입견은 안됨
    • 주의할 점으로 loc[] 안에서 슬라이싱을 할 경우 보통 0:3이면 3 미만으로 0 1 2지만 loc 안에서는 0 1 2 3 으로 마지막 숫자를 포함함
    • 명칭 기반 인덱스라서 그럼. 명칭은 숫자형이 아닐 수 있기 때문에 -1을 적용하지 않음.

 

data_df.iloc[0, 0]

# 인덱싱이 아닌 명칭을 입력하면 오류 발생
# ValueError
data_df.iloc[0, 'Name']

# 문자열 인덱스를 행 위치에 입력해도 오류 발생
data_df.iloc['one', 0]

data_df_reset.iloc[0, 1]

# 명칭 기반인 loc[] 연산자
data_df.loc['one', 'Name']
data_df_reset.loc[1, 'Name']

# 인덱스값이 0인 행이 없으므로 오류 발생
data_df_reset.loc[0, 'Name']
  • ix, iloc, loc의 차이
    • 명칭 기반 인덱싱과 위치 기반 인덱싱의 차이를 이해할 것.
    • DataFrame의 인덱스나 칼럼명으로 데이터에 접근하는게 명칭 기반, 0부터 시작하는 행, 열의 위치 좌표에만 의존하는게 위치 기반 인덱싱
    • ix[]는 명칭, 위치 모두 적용할 수 있음. DataFrame의 인덱스가 숫자 형인 경우 행 위치에 오는 숫자는 위치 기반 인덱싱이 아니라 명칭 기반 인덱싱의 DataFrame 인덱스를 가리킴
    • iloc[] 는 위치 기반 인덱싱만 가능함. 따라서 행과 열 위치 값으로 정수형 값을 지정해 원하는 데이터를 반환
    • loc[] 는 명칭 기반 인덱싱만 가능함. 따라서 행 위치에 DataFrame 인덱스가 오며, 열 위치에는 칼럼 명을 지정해 원하는 데이터를 반환함
    • 명칭 기반 인덱싱에서 슬라이싱을 '시작점:종료점'으로 지정할 때 시작점에서 종료점을 포함한 위치에 있는 데이터를 반환함
  • 불린 인덱싱
titanic_boolean = titanic_df[titanic_df['Age']>60]
print(type(titanic_boolean))
titanic_boolean

titanic_df[titanic_df['Age']>60][['Name', 'Age']].head(3)

titanic_df.loc[titanic_df['Age']>60][['Name', 'Age']].head(3)

titanic_df[(titanic_df['Age']>60) & (titanic_df['Pclass']==1) & (titanic_df['Sex']=='female')]


cond1 = titanic_df['Age'] > 60
cond2 = titanic_df['Pclass']==1
cond3 = titanic_df['Sex']=='female'
titanic_df[cond1 & cond2 & cond3]

 

  • 정렬, Aggregation 함수, GroupBy 적용
    • sort_values() 메서드
      • 파라미터 : by, ascending, inplac
    • Aggreagation 함수
      • count() → 모든 칼럼에 count() 결과 반환
      • 특정 컬럼에만 적용하려면 aggregation
    • groupby() 적용
      • SQL의 group by 와 달리, DataFrame에 groupby()를 호출해 반환된 결과에 aggregation 함수를 호출하면 groupby() 대상 칼럼을 제외한 모든 칼럼에 해당 aggreagtion 함수를 적용함.

 

titanic_sorted = titanic_df.sort_values(by=['Name'])
titanic_sorted.head(3)

titanic_sorted = titanic_df.sort_values(by=['Pclass', 'Name'], ascending=False)
titanic_sorted.head(3)

titanic_df.count()

titanic_df[['Age', 'Fare']].mean()

titanic_groupby = titanic_df.groupby('Pclass').count()
titanic_groupby

titanic_groupby = titanic_df.groupby('Pclass')[['PassengerId', 'Survived']].count()
titanic_groupby

titanic_df.groupby('Pclass')['Age'].agg([max, min])

agg_format={'Age':'max', 'SibSp':'sum', 'Fare':'mean'}
titanic_df.groupby('Pclass').agg(agg_format)
  • 결손데이터 처리
    • NaN으로 표시됨
    • 기본적으로 머신러닝은 NaN 값을 처리하지 않으므로 이 값을 다른 값으로 대체해야함
    • NaN은 평균, 총합 등의 함수 연산 시 제외된다.
    • isna()으로 NaN 여부를 확인할 수 있고 다른 값으로 대체하려면 fillna() 사용

 

titanic_df.isna().head(3)

titanic_df.isna().sum()

titanic_df['Cabin'] = titanic_df['Cabin'].fillna('C000')
titanic_df.head(3)

titanic_df['Age'] = titanic_df['Age'].fillna(titanic_df['Age'].mean())
titanic_df['Embarked'] = titanic_df['Embarked'].fillna('S')
titanic_df.isna().sum()

 

  • apply lambda 식으로 데이터 가공
    • 판다스는 apply 함수에 람다 식을 결합해 데이터프레임이나 시리즈의 레코드별로 데이터를 가공하는 기능을 제공
    • 판다스의 경우 속도를 위해 apply lambda를 이용함
    • lambda x(입력인자) : x ** 2(입력 인자를 기반으로 한 계산식이며 호출 시 계산 결과가 반환됨)
lambda_square = lambda x : x ** 2
print('3의 제곱은:', lambda_square(3))

3의 제곱은: 9

a=[1, 2, 3]
squares = map(lambda x : x**2, a)
list(squares)

[1, 4, 9]

titanic_df['Name_len'] = titanic_df['Name'].apply(lambda x : len(x))
titanic_df[['Name', 'Name_len']].head(3)

titanic_df['Child_Adult'] = titanic_df['Age'].apply(lambda x : 'Child' if x <=15 else 'Adult')
titanic_df[['Age', 'Child_Adult']].head(8)

titanic_df['Age_cat'] = titanic_df['Age'].apply(lambda x : 'Child' if x <=15 else ('Adult' if x <= 60 else 'Elderly'))
titanic_df['Age_cat'].value_counts()


# 나이에 따라 세분화된 분류 수행하는 함수
def get_category(age):
    cat = ''
    if age <= 5: cat = 'Baby'
    elif age <= 12: cat = 'Child'
    elif age <= 18: cat = 'Teenager'
    elif age <= 25: cat = 'Student'
    elif age <= 35: cat = 'Young Adult'
    elif age <= 60: cat = 'Adult'
    else : cat = 'Elderly'
        
    return cat

# lambda 식에 위에서 생성한 get_category() 함수를 반환값으로 지정
# get_category(x)는 입력값으로 'Age' 칼럼 값을 받아서 해당하는 cat 반환
titanic_df['Age_cat'] = titanic_df['Age'].apply(lambda x : get_category(x))
titanic_df[['Age', 'Age_cat']].head()

'머신러닝' 카테고리의 다른 글

[파이썬 머신러닝 완벽가이드] CH03  (0) 2021.09.26
[파이썬 머신러닝 완벽가이드] CH02  (0) 2021.09.26