본문 바로가기

ML/프로젝트CNN

[keras] CNN분류 모델 만들기 3 - Training/Validation/Test set나누기

728x90

 

지난 시간에 우리는 30초 단위로 X,Y,Z데이터를 잘라 한 행으로 만든 후 뒤에 라벨링을 붙였다

결과적으로 960행 , 9000열(+3 label 열)의 데이터를 가지게 되었습니다.

 

저의 ML 게시글을 보셨는지는 몰라도 데이터는 

학습을 위한 학습데이터

과적합 방지를 위한 검증 데이터

최종 모델 테스트를 위한 테스트 데이터

이렇게 3가지가 필요합니다.

자세한 이유 등은  아래의 게시글 2.7 부분을 참고해주시면 됩니다. 

iagreebut.tistory.com/9?category=794421

 

[딥러닝의 정석]02. 전방향 신경망 학습

수학이 정말 많이 나온다... 근데... 교수님 피셜 수식을 하나하나 알아야 아는것보단 큰그림 빅 픽 쳐 를 그리는 게 더 중요하다고 하시고 그냥 수식을 하나하나 한번정도 봐두는 것은 추천한다�

iagreebut.tistory.com

그런데 이에 대한 이야기를 하기전에 잠깐 결측값을 조금 더 처리하겠습니다.

 

 

 

추가적 결측값 처리하기

제 지식으로는 지금 결측값을 적절한 값으로 채우는 것이 불가능 하다고 생각했습니다. 시간도 부족하고요...

 

또한 , 제 데이터의 특성상 

이렇게 중간중간에 뚫린 데이터는 별로 없고 (이런 데이터는 적절한 중간값으로 책정하기 적절할 것 같은데... )

 

이렇게 마지막 라인에 매우 많은 결측값이 발생하는 경우가 많은데 

이렇게 9000열중에 대부분이 결측값인 경우에 오히려 학습에 넣는 것이 방해가 된다고 생각하였습니다

 

 

그래서 제가 생각한 방법은 각 행당 결측값의 수를 세어본 후 

9000열중 200열이상이 결측값(-1)인 경우 그 행을 오히려 학습에 방해되는 데이터라고 생각하여 제거해주기로 했습니다.

 

데이터 불러오기
xyz_data = pd.read_csv("/gdrive/My Drive/데이터/15sec/xyz_data_4500_15sec.csv",header=None)

 

 

조건에 맞는 인덱스 찾기
#-1값 없애기 


# 각 행의 -1값의 수를 세어 count column에 저장
xyz_data['Count'] = (xyz_data.iloc[:,1:] == -1).sum(axis=1)

# -1의 수가 200이상인 행의 "index"저장
drop_nan_xyz = xyz_data.loc[xyz_data['Count']>=200,:].index

 

아래 사진은 .index를 적용하지 않아 그 행의 인덱스를 저장한것이 아닌 그 행들 자체를 저장한 것을 출력해본 모습입니다. 

.index를 한 코드를 출력하면 그 행의 인덱스만 출력됩니다.

다음과 같이 -1이 한행당 거의 절반가까이 되거나 하는 모습을 볼 수 있습니다.

 

제거하기
#-1의 수가 200이상인 행 제거
xyz_data_drop = xyz_data.drop(drop_nan_xyz)

이렇게 해주면 xyz_data_drop이라는 데이터 프레임에 결측값이 200개 이상인 행이 제거된 데이터들이 저장됩니다

이제 이를 csv파일로 저장해주시면 됩니다.

 

 

 

Training/Validation/Test set나누기

 

이제 본격적으로 trainig / validation / test set을 나누어 보도록 하겠습니다.

사실 training data 와 test data로 나누면 대부분

training data를 validation set과 진짜 training set으로 나누어주는 심플한 코드형식이 따로 있긴한데  ( 이 방법은 다음 게시글에 ) 

저는 제 생각대로 나누고 싶어서 그 방법을 사용하지 않았습니다. 

 

 

validation set은 test set을 잘 대변할 수 있어야하며,

test set은 앞으로 나올 미지의 데이터(실제 상용화?되었을 때 들어올 데이터들)를 잘 대변할 수 있어야 합니다.

 

결론은 1~24개의 activity_id를 가진 데이터들이 적절한 비율로 배치되어야 한다는 것 입니다.

 

 

대부분 학습데이터 / 검증데이터 / 테스트 데이터는 5:2:3 을 많이 사용한다고 합니다.

 

그런데 저는 데이터가 너무 적어서 " 6.5 : 1.5 : 2 "을 사용했습니다. (사실 7:1:2 하고싶었는데 실수함...)

 

데이터 열기 
xyz_data_drop = pd.read_csv("방금 만든데이터 가져오기",header=None)


#set column name
xyz_data_drop.rename(columns={4500:'act_id'},inplace=True)
xyz_data_drop.rename(columns={4501:'act_name'},inplace=True)
xyz_data_drop.rename(columns={4502:'sub_no'},inplace=True)
xyz_data_drop.rename(columns={4503:'Count'},inplace=True)

추가로 칼럼이름을 좀 바꾸어 주었습니다 

그리고 Count이부분은 드롭해주셔야해요 (까먹음)

 

 

각 activity_id별로 나누기 
#각 1~24 행동별로 dataframe 생성
import sys
mod = sys.modules[__name__]

# activity num ( 1~24 ) 까지로 파일 나누기
activity_ids = range(1,25)

for i in activity_ids:
    Activity_num = xyz_data_drop['act_id'] == i
    setattr(mod, 'file_{}'.format(i),xyz_data_drop[Activity_num])

 

 

0.65 : 0.15 : 0.2 비율로 나누기 
#빈 데이터 프레임 3개
training_set = pd.DataFrame()
validation_set = pd.DataFrame() 
test_set = pd.DataFrame()


for j in activity_ids:
    current_file = getattr(mod,'file_{}'.format(j))

    #subject를 고르게 분포시키기 위하여 행 섞기 
    #101~109까지 순서대로 들어가 학습데이터에는 101이 전부들어감 
    current_file = current_file.sample(frac=1).reset_index(drop=True)

    if current_file.index.size!=0:
        
        size = current_file.index.size

        #각 set의 비율 
        train = math.floor(size*0.65)
        val = math.floor(size*0.15)
        test = math.floor(size - (train+val)) #나머지

        
        #6.5:1.5:3 비율로 분포시키기 
        training_set = training_set.append(current_file.iloc[0:train,:],ignore_index=True)
        validation_set = validation_set.append(current_file.iloc[train:train+val,:],ignore_index=True)
        test_set = test_set.append(current_file.iloc[train+val:train+val+test,:],ignore_index=True)

인덱스를 사이즈 * 비율을 곱해서 지정해주는 방법으로 나누어주었습니다. 

그리고 마지막은 남은 나머지를 이용해서 지정해주었습니다. 

 

 

데이터 순서 랜덤화
#데이터 섞기 
random_train = training_set.sample(frac=1).reset_index(drop=True)
random_val = validation_set.sample(frac=1).reset_index(drop=True)
random_test = test_set.sample(frac=1).reset_index(drop=True)

위의 방법을 이용해서 set을 지정하고 나면, 데이터셋을 열었을 때 1~24가 순서대로 저장되어 있을 탠데,

이거는 제가 직접 비교해보지는 못했지만 혹시라도 이게 학습에 영향을 줄까봐 순서를 섞어주었습니다.

 

 

저장하기 
#데이터 csv로 저장
random_train.to_csv("/r_training_set_15sec.csv",header=False, index=False)
random_val.to_csv("/r_validation_set_15sec.csv",header=False, index=False)
random_test.to_csv("/r_test_set_15sec.csv",header=False, index=False)

 

 

 

 

이렇게 까지 하면 일단 학습데이터로 사용하기 적절한 모양으로 만들어졌습니다.

 

728x90