codingeverybody / codingyahac

https://coding.yah.ac
292 stars 50 forks source link

CNN을 이용한 Fraud Detection 정확도 향상 #558

Open eddie0122 opened 5 years ago

eddie0122 commented 5 years ago

해결하고자 하는 문제

Fraud Detection의 정확도를 더욱 높이기 위한 인공신경망(CNN) 구조에 대한 조언을 요청드립니다.

기본자료는 매출+입금+기말잔고 * 90일 = 총 270개의 자료구성된 레코드들로 구성되어 있습니다.

현재 다층의 CNN으로 모형을 구성했으며, 모형을 위한 자료는 17x17x1 형태로 변환했습니다.(물론 19개 남은 부분은 0으로 채웠습니다.)

스케일링은 전체 자료에 대한 스케일링이 아닌, 각 레코드별 Min-Max Feature Scaling을 진행하였습니다.

그리고 Train - Validation - Test 데이터는 63.75% - 11.25% - 25% 비율로 구성했습니다.

Model Accuracy는 약 98%, False-Positive Rate는 3.4%입니다.

제가 질문드리고 싶은 것은 1) 현재 구축된 인공신경망에서 False-Positive Rate 낮추기 위해서, 신경망구조를 수정하거나 변경할 부분이 있는지 조언을 듣고 싶습니다.

2) 그리고 현재 각 레코드 별 Min-Max Feature Scaling을 진행했습니다. 그런데 3개의 Feature(매출/입금/기말잔고)에서 음수값(반품 등으로 인하여, 발생된 값)이 모형학습에서 큰 영향을 미칠 수 있는지, 질문드리겠습니다.

부족한 질문에도 불구하고, 답변 주실 전문가 분들께 우선 감사드립니다.

코드

Link

환경

Windows 10 / Python 3.6.5 / Keras(Tensorflow backend)

RayleighKim commented 5 years ago

안녕하세요, eddie0122님.

자, 답변 드리기 이전에, 코드로 질문을 주실 때는 가능하면 주석을 상세히 달아주셔야 좋답니다. 저 같이 stakoverflow없이 코드 못짜는 사람들은, 주석이 있으면 코드를 파악하는 시간이 짧아진답니다.

질문하신 것 외에도 눈에 띄는 것들에 대해서 커멘트를 달아보겠습니다.


Y = np_utils.to_categorical(Y) # Y label data to one hot encoding

이진 분류기 때문에 사실, 원핫인코딩을 할 필요는 없어보입니다. 틀린 것은 아닙니다. (제 취향일 수도 있어요.)


질문에 질문을 드리는 것은 좋은 일은 아니지만, 질문드립니다.

X_train에는 9660 명의 정보가 각각 매트릭스(90 x 3) 으로 존재합니다. 이는, 날짜 순서대로, revenue, deposit, end_balance 세 컬럼이니 의미를 이해했습니다.

def reshapeCNN(dataset, square, order='A'):
    returnValue = []
    for i in range(dataset.shape[0]):
        datasetReshape = dataset[i].reshape(dataset[i].shape[0] *  dataset[i].shape[1], order=order)
        zeros = np.zeros(np.power(square, 2) - datasetReshape.shape[0])
        datasetReshape = np.hstack((datasetReshape, zeros)).reshape(square, square, 1, order=order)
        returnValue.append(datasetReshape)
    return np.array(returnValue)

그러나 위의 reshapeCNN 함수를 거치고 나면, 9660명의 정보가 각각 (17 x 17 x 1 )로 바뀌게 됩니다.

Q. 왜 바꾸셨는지요? 이미지를 처리한다고 할 때는 관습적으로 정사각형으로 resize를 하든 자르든 종종 하는 일이지만, 그때는 의미가 어느정도 보존됩니다. 이미지로 말이죠.

하지만 revenue deposit end_balance( 이하, r d, b) 가 원래는 아래처럼 생겼을 텐데 r0 d0 b0 r1 d1 b1 r2 d2 b2 ...

스퀘어로 바꾸는 순간 아래와 같이 의미 구조가 깨집니다. r0 d0 b0 r1 d1 b1 r2 d2 b2 r3 d3 b3 r4 d4 b4 r5 d5 b5 r6 d6 b6 r7 d7 b7 r8 d8 b8 r9 d9 b9 r10 d10 b10 r11 d11 b11 r12 d12 b12...

그러면 사용하신 CNN의 첫번째 커널이 처음 바라보는 정보가 아래와 같고. r0 d0 b0 b5 r6 d6 d11 b11 r12

다음으로 바라보는 정보가 아래와 같습니다. d0 b0 r1 r6 d6 b6 b11 r12 d12

이미지를 처리할 때는 전부 픽셀의 값들이고, 한 픽셀 기준 8방에 있는 픽셀들의 값을 고려하여 특징이 추출되겠지만, 지금 같은 경우 rdb라는 구조가 깨지면서 의미가 일그러지지 않을까 합니다.

이는 문제가 될 수 있습니다.

[문제가 됩니다]하고 강하게 말을 못하는 이유는, 딥러닝의 세계란 '야 해봤더니 이게 더 좋던데?'하는 것을 너무 많이 봐서.....


CNN은 물론 시퀀스 데이터에 대해서도 강합니다. 정사각형 이미지처럼 다루려고 reshape를 하셨을거라 추측합니다. 하지만, reshape를 하지않고서 진행해보시는 건 어떨까요? 예를 들자면, 한명의 정보는 원래대로 90x3으로 되어 있고 kernel_size를 (10, 3)으로 둔다고 하면 rdb를 한꺼번에 10일의 정보씩 관찰하게 할 수 있겠죠. 물론, 이렇게 하는 경우 CNN을 만들때 권장하는 전통적인 기법(?)들은 성능이 좋아질지 나빠질지 전부 해봐야 아는 상태가 될겁니다만, 구조 자체는 더욱 시계열에 알맞을 거에요.


CNN자체에 대해서는 사실 아직 튜닝의 여지가 많이 남아 있습니다. 당장 봐도, relu대신 leaky relu같은 것이 더 좋을 수도 있고, 패딩을 할 수도 있으며 batch normalization도 있겠습니다.

중요하게 여겨지는 정보를 뒤로 더 보내고 싶으면 residual block 같은 것을 구현해볼 수도 있었을 것 같구요. 단, 아까 처럼 시계열의 의미/구조 를 보존하여 모델링하는 순간 보편적인 가이드라인은 전부 해봐야 알거에요.


Q. 그리고 현재 각 레코드 별 Min-Max Feature Scaling을 진행했습니다. 그런데 3개의 Feature(매출/입금/기말잔고)에서 음수값(반품 등으로 인하여, 발생된 값)이 모형학습에서 큰 영향을 미칠 수 있는지, 질문드리겠습니다.

음수값들 중 어떤 값이 Min이 되겠죠? 모델링 이전의 관점에서 고민해야할 부분들이 많습니다. 반품이란 중요한 것인가. 반품발생한 것은 어느 시점의 구매 건인가 등등, 그리고 이런것들이 중요한가. 데이터로 어떻게 넣어줘야 하는가. 모델에 반영하려면 어떻게 해야 하는가.

단순히 모형학습의 관점에서만 말씀드린다면, 큰 영향을 줄지 안줄지는 어느 방향이 더 Error를 낮추는데 도움이 되느냐에 따라 달라집니다. Learning이 된 결과 ( Optimization 된 결과 ) 가중치를 보고 결과적으로 판단하게 될겁니다.

더욱 간단하게만 답변을 드리면, 예. 에러 줄이는데 도움이 된다면, 그 음수값(min-max했으니 0에 가까운값)이 중요할지 아닐지 학습과정에서 결정날겁니다.

데이터와 문제상황, 모델링에 담긴 의도, 전처리 의도에 따라 달라지기 때문에 일반적인 답이 없을거에요.


제 눈에는 문제를 풀어나가는 모델의 구조가 망가져 보이는데, 성능이 좋아 놀랍습니다. 역시 convolutional layer가 많으면 receptive field가 커지기 때문에, 굳이 시계열 구조의 의미가 없는 것인가! 일반적으로 성능을 높이기 위해 하는 시도들을 추가로 해보는 것만으로 성능이 더 올라갈지도 모릅니다.


False-Positive Rate도 다시 계산하셔야 할 것 같습니다.

예를 들어, 제가 적당히 학습을 진행하다가 멈춘 것에 대해서, conMat을 열어보면 Predict 0 1 Actual
0 2743 39 1 41 398

로 되어 있는데, 0과 1 중 어느 것을 True라고 생각하셨는지요? 그리고,

(conMat.iloc[1,0] / conMat[1].sum()*100)

로 되어 있는 계산 결과는, 1이라 예측한것들 중, 실제로는 0인 것의 비율입니다. False-positive rate은, 실제 negative중, positive로 예측된 것의 비율입니다.


일반적으로 fraud detection의 경우,

  1. fraud인걸 fraud라고 못잡으면 손해가 크기 때문에, 일단 실제 fraud중 최대한 fraud를 골라내는 것이 우선입니다. 그 다음에 fraud가 아닌데, fraud취급 당하는 수를 줄이는 방향으로 튜닝을 합니다.
  2. 보통은 데이터가 이렇게 밸런스가 맞지 않을 수 밖에 없어요. 데이터 불균형시 어떻게 문제를 해결하는지 찾아보는 것도 도움은 됩니다. (데이터 사이즈가 클 수록 어려운 문제가 될 수 있음)

fraud를 더 잘잡기 위해서 한가지 추천을 드리자면, loss를 직접 디자인해보는 것도 방법 중 하나입니다. 1을 1이라고 못맞추면 에러가 왕창 늘어나도록 말이죠. 하지만, 이는 모델의 구조를 충분히 튜닝해보신 후 진행하기를 추천드립니다.


eddie0122 commented 5 years ago

답변 감사드립니다. 늦게 글을 올려드려서 죄송합니다.

원래는 일반적으로 사용하는 오토인코더를 통한 감지를 생각했으나, 일반적인 FC 모형과 큰 차이가 없는 결과를 얻어서 CNN을 이용해보았습니다.

그래서 CNN을 이용해봤는데, 1)형태를 변환하지 않는 행렬구조 2)Reshape시 order를 변경하는 행렬구조 등을 적용해봤는데, 큰 차이를 보이지는 않았습니다. CNN의 특징을 생각했을때, 모양이 무너져서 정확도가 낮은 결과를 예상했으나, 실제로는 약간 높은 결과를 얻은 것은 저도 놀랐습니다.

우선은 학습자료가 부족한 것 같아서, 추가적으로 자료를 수집하고 있습니다. 말씀하신 것처럼 기존 형태를 유지 후, 커넬크기를 변경해서 학습을 해보겠습니다. 감사합니다.