이 포스트는 [인공지능 보안을 배우다] 책을 참고해 학습한 내용을 정리한 글입니다.
특징공학 기법을 사용하여 분류에 도움이 되는 특징과 그렇지 않은 특징을 분류하고, 성능이 가장 좋은 특징 조합을 찾아 낸다.
1. 첫번째 코드
백업 해둔 pe_all 데이터를 다시 가지고와 불필요한 열을 제거하는 과정이다.
pe_all = pe_all_tmp # 백업 데이터프레임 복원
- 이전에 백업해 둔 pe_all_tmp를 다시 가져온다.
pe_all = pe_all.drop(['filename', 'MD5', 'packer_type'], axis=1) # 불필요 열(col) 제거
- 해당 데이터 중 filename, MD5, packer_type 열을 제거한다.
pe_all.shape # ( 937 x 69 )
- pe_all의 크기를 출력한다.
결과
(937, 69)
2. 두번째 코드
col = pe_all.columns
- pe_all의 칼럼(열)의 이름을 가져와 col에 저장한다. col은 열 이름을 가진 리스트가 된다.
3. 세번째 코드
세번째 코드는 랜덤포레스트를 수행하고 그 결과를 출력한다.
imp = md_pe.do_randomforest(1)
- 이전에 생성했던 md_pe 인스턴스의 do_randomforest()메소드를 호출하여 수행한후, imp에 저장한다.
3.1. 랜덤포레스트 코드
- 특징데이터와 모드를 가지고 랜덤포레스트 수치를 계산하는 메소드이다.
- y_train 데이터를 1차원 numpy 배열로 변환하여 평탄화 한다.
- fit메서드를 사용하여 랜덤포레스트 모델을 학습한다.
- mode가 1일 경우 랜덤포레스트가 계산한 "해당 특징의 중요도"를 반환한다.
- x_test 를 기반으로 y_test를 예측한다.
- y_test와 y_pred를 비교하여 정확도를 return한다.
imp
- imp를 출력한다.
결과
총 68개의 특징의 중요도가 출력되었다.
열의 개수가 69개인데 출력된 중요도는 68개인 이유는 나머지 하나는 class열이기 때문이다. (모델의 예측대상= 악성코드인지 아닌지)
숫자가 클수록 해당 특징이 데이터를 판별하는데 도움이 많이 되었다는 의미이다.
7.04338257e−02는 7.04338257× 즉 0.0704338257
0에 가까울 수록 해당 특징을 예측에 사용하지 않았다.
0.0의 경우 모델 예측에 무시된 특징이다.
4. 네번째 코드
네번째 코드는 '특징데이터의 열'과 세번째 코드에서 추출한 '특징중요도'를 짝 지은 쌍을 중요도 기준으로 상위 20개를 내림차순으로 출력한다.
imp = dict(zip(col, imp))
- col은 데이터셋의 이름 imp는 특징 중요도 zip(col,imp)는 col과 imp를 짝짓는다.
- dict 딕셔너리 자료형으로 변환한다. ex { 'feature1': 0.1, 'feature2': 0.2, ... }
sorted_imp = sorted(imp.items(), key=operator.itemgetter(1), reverse=True)
- items() : 딕셔너리 변수에만 사용할 수 있고, (key,value) 쌍의 튜플의 리스트 형태로 반환한다.
- key=operator.tiemgetter(1) : 두번째 열을 기준으로 정렬한다. (0부터 시작)
- reverse=True : 내림차순으로 정렬한다.
imp_20 = sorted_imp[0:20]
- 정렬된 리스트 중 상위 20개 항목만 추출하여 imp_20에 저장한다.
imp_20
- imp_20를 출력한다.
결과
'E_file'이 가장 구분하는데 중요한 특징이다.
5. 다섯 번째 코드
imp_20 의 key 만 출력한다
출력결과
6. 여섯 번째코드
특징중요도가 높은 상위 20개만 가지고 분류모델을 학습하고, 그 결과를 출력한다.
pe_all = pe_all_tmp # 백업 데이터프레임 복원
pe_all = pe_all.drop(['filename', 'MD5', 'packer_type'], axis=1)
- filename MD5 packer_type 열 제거
Y = pe_all['class'] # 카테고리 열을 별도로 추출
pe_top20 = pe_all.drop('class', axis=1) # 카테고리 열 제거
X = pe_top20[imp_20.keys()]
- imp_20의 열들 = 특징 중요도 상위 20개 특징 데이터만 추출한다.
md_pe_top20 = model.Classifiers(X, Y) # 학습 모듈 인스턴스 초기화
rns = md_pe_top20.do_all()# 분류 모델 학습
rns.append(0)
- 리스트 rns 의 맨 끝 값에 0을 대입 (cnn 값에)
rns.append(0)
- avg 값에 0을 대입
df.loc['pe_top20'] = rns
- df 데이터프레임에 'pe_top20'행을 추가하여 rns 데이터를 입력
df_tmp = df.drop(['cnn', 'avg'], axis=1)
- 평균을 계산하기 위하여 cnn, avg 행을 제외한 데이터를 df_tmp에 저장한다.
avg_20 = df_tmp.loc['pe_top20'].mean(axis=0)
- df_tmp의 'pe_top20'행의 평균을 계산하여 avg_20에 저장한다.
df.loc['pe_top20', 'avg'] = avg_20
- df 데이터프레임의 'pe_top20'행 'avg'열에 avg_20 데이터 값을 저장한다.
결과
우선 학습한 결과를 보여준다. 이전과 마찬가지로 15번의 학습 횟수를 가진다.
7. 일곱 번째 코드
df데이터 프레임을 출력한다.
추가된 pe_top20 행을 보면, pe, pe_pakcer들과 비교하여 평균이 좀 더 높고 ngram보다는 낮은 것을 알 수있다.
8. 여덟 번째 코드
x의 칼럼들을 출력한다.
이전에 추출했던 특징 중요도가 높은 순의 pe header 상위 20개가 출력된다.
결과
이전에 실행했던 코드의 결과와 동일한 것을 확인할 수있다.
9. 아홉 번째 코드
아홉 번째 코드는 메타플로립을 사용하여 상관계수 그래프를 그리는 과정이다.
%matplotlib inline
- 메타플로립 그래프를 그리되, inline으로 표시한다.
- inline의 의미는 Jupyter Notebook에서 작성된 코드라면, 그래프를 노트북 내부에 직접 표시하도록 설정하라는 의미이다.
plt.rcParams['figure.figsize'] = [50, 50]
- 메타플로립 그래프의 사이즈를 50,50으로 지정한다.
- plt : 첫번째 코드에서 정의했던 메타플로립의 별칭이다.
- rcParams : 메타플로립 그래프 설정 매개변수를 저장한 딕셔너리로, 그래프의 크기, 선 두께, 글꼴 크기를 지정할 수있다.
- rcParams['figure.figsize'] : 그래프의 사이즈를 지정한다.
X = X.copy() #X를 명시적으로 복사
- '명시적으로 복사'의 의미는 원본 데이터에 독립적인 복사본을 생성한다는 것이다.
- 이전의 X = pe_top20[imp_20.keys()] 과정에서 슬라이싱 데이터인 X가 pe_top20와 연결될 가능성이 있다. 즉 X를 수정하면 pe_top20이 수정될 수 있다. 이를 방지하기위해 복사본을 생성한다.
X['class'] = Y
- X의 새로운 열 'class'를 생성하여 그 값으로 Y값을 대입한다.
pe_mal = X[X['class'] == 1]
pe_nor = X[X['class'] == 0]
- class 열의 값이 각각 1,0인 행만 추출하여 pe_mal, pe_nor에 저장한다. 악성/정상으로 나누어 데이터를 비교하기 위함이다.
fig, ax = plt.subplots(figsize=(15,15))
- subplots : 메타플로립에서 그래프를 여러가지 하위 플롯으로 나눠 그리게 하는 메소드
- 15x15인치 사이즈의 그림을 그림
- fig : 그림을 담는 프레임 액자 같은 것.
- ax : 실제 그림이 그려지는 캔버스
sns.heatmap(X.corr(), annot=True, linewidth=.5, ax=ax)
- seaborn 라이브러리를 사용하여 상관계수를 히트맵으로 표현한다.
- corr() : 판다스의 상관계수를 계산하는 메소드
- annot =True : 각 셀에 숫자 값을 표시
- linewidth=.5 : 셀 간격의 너비 값이 클수록 간격이 넓어짐
- ax=ax : matplotlib의 ax 객체를 지정하여 그래프를 그림.
- 히트맵 그래프란 : 2차원 데이터를 열 분포형태로 시각화 하는 그래프이다
결과 - 그래프분석
- 셀이 하얗고 1에 가까울수록 양의 상관관계 - 한 변수도 증가하면 다른 변수도 증가한다.
- 셀이 까맣고 -1에 가까울수록 음의 상관관계 - 한 변수가 감소하면 다른 변수도 감소한다.
- FH_char2 와 FH_char3 의 관계는 1로 완전히 같이 움직인다. 그러므로 둘 중하나를 삭제하더라도 학습결과에 큰 영향을 미치지 않을 것이다.
- 마이너스 중 가장 작은 수는 -0.86으로, OH_DLLchar0과 FH_char3는 음의 상관관계를 가진다. 즉 반대로 움직인다.
- 지수가 0게 가까우면 두 요소는 독립적으로 움직인다는 의미이다.
10. 열 번째 코드
열 번째 코드는 히트맵 그래프의 결과에서 FH_char2, FH_char3 관계가 1임에 착안해, FH_char3 요소를 삭제하고 학습했을 때 어떤 결과를 보여주는지 확인하는 과정이다.
class, FH_char3열을 삭제하고 분류모델에 학습한 뒤 평균을 낸다. 그 결과를 pe_top19 행에 저장한다.
결과
11. 열한 번째 코드
df 데이터프레임을 출력한다.
결과
pe_top19_cor 와 pe_top20을 비교하면 결과에 거의 차이가 없다는 것을 확인 할 수있다.