한국어
    • 한국어
    • ENGLISH
    • 日本語
    • 中文-繁體

    2021.01.22 Data Science

    게임의 부정 사용자를 탐지하는 방법, Snorkel을 활용해 라벨 보정하기

    배경

    이번 글에서는 Fraud Detection System 개발 과정 중 탐지 모델 라벨 보정 도구를 적용한 작업에 관해 소개해 드리려 합니다. 게임 서비스에서 Fraud Detection은 매크로나 핵 등의 불법 프로그램 사용과 계정 도용 같은 부정행위를 탐지하는 것을 말합니다. 그리고 이러한 행위를 하는 집단을 부정 사용자로 정의합니다. 이들은 일반 고객에게 악영향을 끼치기 때문에 적절한 제재가 필요합니다. 부정 사용자 예측 모델은 이러한 제재 프로세스를 자동화하는 데 목적이 있습니다.

    게임 속 일반 사용자와 부정 사용자를 구분하는 방법, 라벨

    그렇다면 예측 모델은 어떻게 일반 사용자와 부정 사용자를 분류할 수 있을까요? 모델을 학습하기 위해서는 일반 고객과 부정 사용자를 구분 지을 만한 여러 패턴 및 특성과 부정사용자라고 확신할 만한 정답지가 필요합니다.

    모델은 주어진 특성 정보들을 토대로 일반 고객/부정 사용자 여부를 맞추는 문제를 풀게 되고, 이 과정에서 모델이 예측한 결과와 실제 정답지(라벨)를 비교하며 학습하게 됩니다. 따라서 모델의 성능을 높이기 위해서는 정확하고 많은 라벨 정보를 확보해야 합니다.

    라벨은 믿을만한가

    그러나 실제 ML 서비스를 개발하는 과정에서 라벨 정보를 확보하기 어려운 경우가 많습니다. Fraud Detection System 분야가 대표적인 경우인데, 다음과 같은 문제가 있기 때문입니다.

    이미지나 텍스트, 음성 데이터의 라벨링과 달리 도메인 지식이 없는 비전문가 다수를 이용한 라벨링이 어렵습니다.

    기존에 확보한 탐지 규칙이나 이력을 이용해 학습 데이터를 만들 경우, 이미 알고 있는 탐지 규칙이나 이력은 전체 부정행위 중 일부에만 해당하기 때문에 나머지 데이터가 모두 정상 행위라고 단정할 수 없습니다.

    심지어 운영 부서에서는 탐지를 회피하려는 집단에 혼동을 주기 위해, 제재 정책을 가변적으로 시행하는 경우도 있어, 시점에 따라 라벨 데이터의 분포가 달라져 모델 학습이나 평가가 어려워집니다.

    이 같은 이유로 부정행위 탐지 모델을 위해 단순히 제재가 된 이력이 있는지, 없는지를 라벨 정보로 사용하는 것은 문제가 있다고 생각했습니다. 즉, ‘제재 이력 없음’을 그대로 탐지 모델 라벨에 활용하는 것은 노이즈 라벨을 사용하는 것이므로 보정이 필요합니다. 따라서 저희는 이 문제에 Weak Supervision 방법을 적용해 보았습니다.

    Weak Supervision이란

    Weak Supervision이란 대규모 학습 데이터 세트에 라벨을 지정하기 위해, 노이즈가 있거나 제한적이거나 일부 부정확한 소스(Weak label)를 사용하는 기계 학습의 한 분야입니다. 즉, 라벨이 지정된 데이터의 부족, 라벨링에 대한 시간과 비용 등의 문제에 대응하기 위한 라벨링 자동화 방법입니다. Weak label의 종류에는 도메인 전문가에 의한 휴리스틱 규칙, 기존 리소스(지식 기반 정보, 사전 학습된 모델의 결과) 등이 있습니다. 쉽게 말해, 각각의 Weak label을 곧바로 학습 라벨로 사용하기는 어렵지만, 취합한 여러 가지 태깅 정보를 활용해 학습 라벨로 쓸 만한 결과를 만들어 주는 시스템입니다. 좀 더 자세한 정보는 이 링크를 참조하시길 바랍니다.

    부정 사용자 탐지 작업의 경우 라벨로 바로 활용하기는 어렵지만 이상 패턴으로 볼 수 있는 태깅 정보(Weak label)가 있으므로 Weak Supervision을 적용해 볼 만하다고 판단했습니다. 그중 Snorkel이라는 관련 기법이 구현된 Python 라이브러리를 적용했습니다. 각 과정을 요약하면 아래와 같습니다.

    사용자가 직접 라벨을 지정하지 않는 대신, 임의의 도메인 지식을 표현하는 Label function을 작성

    작성한 Label function들을 토대로 라벨 생성 모델을 학습

    Unlabeled 데이터에 위의 생성 모델을 적용해 레이블링 자동화

    앞서 말씀드린 바와 같이 부정 사용자 탐지 모델링은 ‘제재 이력 없음’이 확실한 일반 고객에 대한 라벨이 아닌 노이즈 라벨 상황이기 때문에 Unlabeled data로 간주해 작업을 진행했습니다. 그렇다면 Snorkel에 적용된 원리와 이를 부정 사용자 탐지 모델에 어떻게 적용했는지 다음 본문에서 계속 설명해 드리겠습니다.

    Snorkel 적용 원리 들여다보기

    전체 과정 요약

    Snorkel의 각 과정은 [그림 1]과 같이 3단계로 간단히 도식화할 수 있습니다.

    [그림 1] Snorkel 각 과정에 대한 도식화

    도메인 전문가에 의한 Label function 작성

    라벨 함수를 토대로 라벨을 생성하는 모델 학습

    생성 모델의 확률 라벨을 최종 분류기에 활용

    각 과정을 하나씩 살펴보겠습니다.

    1. 라벨 함수 작성

    먼저, 도메인 전문가가 라벨 생성 규칙을 작성합니다. 각 Label function이 출력하는 카테고리 값은 Positive, Negative, Unknown으로 이루어져 있습니다. 예를 들어, 스팸 분류 문제의 경우 광고 문구에 단골로 들어가는 ‘check out’ 같은 문구가 들어 있다면 이상 태깅(Pos) 또는 기권으로 태깅(Unk)합니다.

    이렇게 다양한 이상 패턴에 대한 도메인 지식을 활용해 패턴을 함수 형태로 정의한 뒤 각 함수의 summary 정보를 확인할 수 있습니다.

    [그림 2] 취합한 Label Functions의 Summary 정보

    Polarity: LF 결과 유니크 labels

    Coverage: 데이터 세트의 LF labels 비율

    Overlaps: 해당 LF 태깅 결과와 다른 하나 이상의 LF 태깅 결과가 같은 데이터 세트 비율

    Conflicts: 해당 LF 태깅 결과와 다른 하나 이상의 LF 태깅 결과가 다른 데이터 세트 비율

    Correct, Incorrect, Emp. Acc.: 실제 True 정답지가 존재했을 때의 일치, 불일치, 경험적 정확도

    위의 summary 정보를 통해 작성한 라벨 함수 간에 종속적인 관계가 있다는 정보와 주어진 데이터 내에서 얼마만큼의 태깅이 가능한지를 참조 정보로 활용할 수 있습니다. 예를 들어, 어떤 Label function의 Coverage가 아주 낮으면서 다른 Label function과 동떨어진 결과만 출력한다면 올바른 패턴 태깅 함수라 볼 수 없으므로 로직을 재검토해야 합니다. 이 같은 극단적인 경우가 아니라면 사용자가 직접 종속성을 제어할 필요는 없을 것입니다.

    2. 생성 모델 학습

    두 번째 과정은 Snorkel의 과정 중 빨간색 박스에 해당하는 생성 모델 학습 과정입니다. 이 과정에서는 여러 도메인 지식에 근거한 Label function들을 모은 뒤 최종 취합하는 생성 모델을 통해 함수마다 적합한 계수를 학습하게 됩니다. 물론 가장 단순한 방식은 라벨 함수의 계수를 1로 생각하는 것(다수결 투표)입니다. 그러나 라벨 함수의 각 계수를 라벨 함수 간의 종속적인 관계와 설정한 Loss function을 고려해 노이즈가 덜 포함된 데이터 세트로 계수를 학습하고자 하는 것이 생성 모델 학습의 목적입니다. Snorkel 내에 구현된 계수를 학습하는 알고리즘은 아래 두 논문에서 개발되었습니다.

    Data programming: creating large training sets, quickly’ (Ratner 2016)
     • 생성 모델의 기본 학습 원리는 위에서 개발

    Learning the structure of generative models without labeled data’ (Bach 2017)
    라벨 함수 간의 종속성 구조를 자동으로 찾아주는 알고리즘(Structure Learning)을 추가한 것

    기본 원리는 각 함수가 태깅을 달 확률과 함수 간 태깅 결과가 고른지에 대한 확률을 모수로 하는 확률분포를 정의한 뒤, MLE를 통해 확률분포에 대한 두 모수를 추정합니다. 그다음 정의한 Loss function(logistic loss)을 최소화하는 매개변수를 학습하게 되는데, 이때 앞서 학습한 확률분포를 참고해 Loss에 대한 기댓값을 구합니다. 이렇게 되면 주어진 데이터 세트 중 노이즈가 덜 포함된 정보(정의한 확률분포의 확률값이 높은 위주)로 각 Label function의 계수를 학습합니다. 알고리즘 상세 과정은 Appendix를 참고 바랍니다.

    이 같은 과정을 거쳐 학습된 생성 모델을 통해 학습된 계수로 데이터 포인트가 들어왔을 때, 양성에 가까운지 음성에 가까운지 확률 벡터를 만들 수 있습니다. 확률 벡터는 판별 모델의 라벨 정보로 사용됩니다.

    3. 판별 모델 학습

    마지막으로 위 도식화 그림([그림 1])에서 초록색 부분에 해당하는 판별 모델 학습 과정입니다. 이 과정에서는 데이터 포인트마다 얻어낸 클래스에 대한 확률 라벨 벡터 정보로 최종 모델 지도 학습을 합니다. 여기에서는 일반적인 지도 학습 과정과 달리 loss 값을 계산할 때 One-hot 인코딩된 라벨이 입력으로 들어가는 것이 아니라 확률 벡터가 입력으로 들어간다는 차이점이 있습니다.

    상세 분석 내용

    다음으로 부정 사용자 탐지 모델에 Snorkel을 적용한 상세 분석 과정을 소개해 드리겠습니다. 분석 과정은 모델링에 필요한 특성 및 데이터 추출, Label function 작성 그리고 Snorkel 적용 전의 결과와 적용 후의 효과 검정으로 구성되어 있습니다.

    데이터 구성 및 특성 추출

    [표 1] 학습 데이터 구성 정보

    위에서 추출한 피처와 이상/정상 태깅 정보에 사용한 변수 목록은 독립적이며, 이상/정상 태깅 조건에 사용한 변수와 제재 여부와 직접적인 상관관계가 없습니다(이상 태깅 조건은 제재룰에 직접 포함되지 않습니다).

    정상/이상 패턴 분석을 통한 라벨 함수 정의

    도메인 지식과 사전 분석을 통해 정상/이상 패턴이라고 판단되는 항목 등을 라벨 태깅 함수로 등록하는 과정입니다.

    참고로 정상/이상 패턴에 사용한 정보는 게임 안에서와 게임 외적의 다양한 로그 분석을 통해 부정 사용자가 할 만한 행동 패턴과 행위를 사용합니다. 이렇게 패턴 태깅에 사용할 모든 Label function들을 정의하면, 데이터 포인트마다 Label function의 결과(Pos, Neg, Unk)를 취합한 Label Matrix를 얻을 수 있습니다. (분석에 사용한 상세 피처 항목과 로직은 대외비이므로 본 포스팅에서 생략하니 양해해 주시기 바랍니다.)

    Label function 태깅 결과 클래스

    부정 사용자: Pos

    일반 고객: Neg

    알 수 없음: Unk

    생성/분류 모델 학습

    다음은 생성/분류 모델 학습 과정입니다. 먼저 취합한 Label Matrix의 summary 정보는 아래와 같습니다.

    [표 2] Label Matrix의 summary 정보

    이 Label Matrix를 생성 모델의 인자로 넣어 학습을 진행합니다.

    학습된 생성 모델로부터 각 데이터 포인트의 Pos일 확률 벡터를 얻을 수 있습니다. 그리고 이 확률 벡터를 판별 모델의 확률 라벨 벡터로 사용할 수 있습니다. 분류기는 RandomForest, DNN 등 일반적인 지도 학습의 다양한 방법을 사용하면 됩니다.

    라벨 보정 전후의 효과 측정

    이 과정은 라벨 보정 전의 분류기와 Snorkel 생성 모델을 통해 라벨 보정을 한 분류기를 학습한 뒤 효과를 검정하는 작업입니다. ‘제재 이력을 라벨로 이용해 학습한 방식’과 ‘Snorkel을 이용해 라벨을 생성한 후 학습한 방식’을 비교했으며, 두 모델의 피처는 동일합니다.

    [그림 3] 라벨 보정 전후의 모델링 방식 비교

    효과 검정 방법으로는 제재 이력을 라벨로 이용해 학습한 방식과 Snorkel로 라벨 보정 후 학습한 분류 모델의 결과를 비교했습니다. 노이즈가 없는 깨끗한 정답지 마련이 어렵기 때문에 두 모델의 결과가 서로 다른 샘플을 추가 확인하는 작업을 진행했습니다. 즉, 기존 모델이 일반 사용자로 분류했음에도 개선 모델이 부정 사용자로 분류한 표본에 대해 검정을 시행했습니다.

    (분류 결과에 대한 개수는 직접 표기 대신 비율로 간접 표기했습니다.)

    [표 3] 제재이력을 라벨로 사용한 모델과 snorkel 라벨 보정을 적용한 모델과의 비교

    [표 3]은 두 모델의 분류 결과를 비교한 표입니다. 두 모델의 판정 결과가 엇갈린 영역 중 Snorkel 라벨 보정 후 학습한 모델을 통해 ‘부정 사용자’로 추가 분류된 샘플(빨간색 수치 영역 0.144)이 많습니다. 제재 이력 라벨 사용 모델이 Pos라 분류했으나 Snorkel 라벨 보정 후 학습한 모델이 Neg라 분류한 결과는 0.002로 상대적으로 적습니다. 부정 사용자 탐지 모델링의 경우 recall보다 precision(부정 사용자로 판단한 결과) 조사가 더 중요한데, 이는 부정 사용자를 일반 고객으로 판정하는 경우보다 일반 고객을 부정 사용자로 판정하는 오탐이 더 위험하기 때문입니다. 따라서 빨간색 수치 영역이 실제 오탐인지 아닌지 확인하는 상세 분석을 진행했습니다.

    추가 검출한 샘플에 대한 Pos/Neg 판단

    Snorkel 라벨 보정 후 학습한 모델이 추가 검출한 샘플이 부정 사용자인지 아니면 일반 고객인지 판단하기 위해, 유형을 나누어서 생성 모델의 태깅 결과와 데이터를 확인하는 과정을 거쳤습니다. 먼저, 생성 모델의 태깅이 Pos인데 제재 이력이 없는 경우입니다. 이 샘플에 대한 조사에 따르면 적어도 1개 이상 패턴 태깅 함수에 속했습니다. 실제 데이터를 확인해 보니 일반 고객이 하기 어려운 이상 패턴이 존재하는 것을 확인했습니다. 따라서 제재 이력이 없더라도 탐지 모델의 결과가 Pos이면서 생성 모델도 Pos로 태깅된 경우는 부정 사용자로 간주했습니다. 다음은 생성 모델의 태깅은 Neg인데 제재 이력은 없는 경우입니다. 이 샘플의 조사 결과, 이상 패턴 함수의 태깅 결과에 속하지 않으면서 일반 고객에게서 나오는 정상 패턴이 존재했습니다. 따라서 이 유형에 해당하는 경우에는 주어진 정보에 따라 오탐으로 판단했습니다. 이러한 판단 논리로 각 유형을 확인한 결과를 아래에서 살펴보겠습니다.

    아래 [표 4]는 [표 3]의 빨간색 수치 영역 0.144에 대한 제재 이력과 생성 모델(취합한 Label Matrix를 통해 Pos, Neg, Unk로 분류해 주는 모델)의 확인 결과를 나타낸 표입니다.

    [표 4] Snorkel 라벨 보정을 적용한 모델이 추가 검출한 표본에 대한 생성 모델 태깅

    유형 1. 생성 모델 태깅 결과 Pos

    추가 검출된 0.144에 해당하는 샘플 중 유형 1은(76%) 주어진 피처상 부정 사용자와 비슷한 패턴을 보이며, 부정 사용자라 판단할 만한 이상 태깅도 존재함

    이 유형 샘플에 대해 이상 태깅 정보를 집계한 결과, 적어도 1개 이상의 이상 태깅에 해당됨

    각 이상 태깅에 대한 실제 데이터를 확인해 보면, 일반 고객이 할 수 없는 매크로적인 행동이 관찰됨

    유형 2. 생성 모델 태깅 결과 Neg

    추가 검출된  0.144에 해당하는 샘플 중 유형 2는(8%) 주어진 피처가 부정 사용자와 비슷하나, 일반 고객에게서 발견되는 특성이 나타남

    이 유형 중 정상 태깅 조건에 하나라도 해당되는 유저는 99%이고, 이상 태깅 조건에 하나라도 걸린 샘플 수는 17%임

    즉, 대부분 이상 태깅이 없고 정상 태깅 중 한 가지 조건에 해당하기 때문에 Snorkel 라벨링 결과 Neg로 태깅된 것임

    실제 데이터를 확인해 보면 일반 고객의 특징을 갖는 샘플도 섞여 있음

    유형 3. 생성 모델 태깅 결과 Unk

    추가 검출된 0.144에 해당하는 샘플 중 유형 3은(15%) 주어진 피처가 부정 사용자와 비슷한 패턴을 보이나, 이상 태깅 정보로는 부정/일반 유저를 판단하기 어려운 샘플임

    이 유형의 샘플 중 정상/이상 태깅이 단 한 개라도 존재하는 샘플은 1%뿐임

    Label function의 Coverage 한계가 드러난 영역임

    이 결과는 생성 모델의 태깅 정보를 신뢰할 수 있다고 가정했을 때, 아래와 같은 결론으로 요약할 수 있습니다.

    유형 1(생성 모델 태깅 결과 Pos) – 제재 이력은 없지만, 테스트 데이터의 생성 모델 태깅 정보가 Pos이므로 부정 사용자로 판단됨

    유형 2(생성 모델 태깅 결과 Neg) – 생성 모델의 태깅 정보가 Neg인데 Pos로 잘못 분류한 것임. 실제 데이터를 확인한 결과 일반 고객의 특징이 많이 보이는 만큼 잘못 분류한 것으로 판단됨

    유형 3(생성 모델 태깅 결과 Unk) – 생성 모델의 태깅은 Unk인데 Pos로 분류한 경우로, 실제 데이터를 확인해 보니 판단하기 어려움

    아래의 Confusion Matrix는 생성 모델의 태깅 정보를 신뢰했을 때, ‘제재 이력을 라벨로 이용해 학습한 모델’과 ‘Snorkel을 이용해 라벨을 생성한 후 학습한 모델’을 비교한 결과입니다. (전체 테스트 데이터 개수를 백분율로 표기했습니다.)

    [표 5] 제재 이력을 라벨로 이용해 학습한 모델

    f-1 score: 0.830

    precision: 0.819

    recall: 0.842

    [표 6] Snorkel을 이용해 라벨을 생성한 후 학습한 모델

    f-1 score: 0.914

    precision: 0.892

    recall: 0.937

    유형 1번은 부정 사용자로 판단되는 유형이고, 2번 유형은 오탐이 의심되는 유형이며, 3번 유형은 현재 주어진 정보로 판단하기 어려운 영역입니다. 이 논리대로 성능 평가를 진행한다면 제재 이력만을 라벨로 이용한 결과보다 f1 스코어 기준 0.084의 향상을 이룰 수 있습니다. 유형 2번과 3번은 현재 고려한 Label funtion의 Coverage 문제, 피쳐의 한계가 있는 영역입니다. 따라서 이 두 유형의 샘플에 대한 상세 분석을 통해 추후 모델링 고도화 작업이 필요할 것입니다.

    마치며

    지금까지 부정 사용자 탐지 모델 작업에서 Snorkel을 적용한 결과를 소개해 드렸습니다. Weak Supervision의 사용 가능성을 살펴보았지만 앞으로 보완하거나 고민해야 할 부분도 많습니다. 예를 들어, Label function에 대한 지속적인 관리 방안(Label function이 충분한지, 불필요한 Label function이 있다면 제거)과 좀 더 깨끗한 정답지로 정량적 성능을 평가하는 방식을 생각해야 합니다. 체계적인 라벨 데이터 구축을 위한 지속적인 노력을 통해 올바른 탐지 모델에 대한 학습과 제재 프로세스 자동화에 이바지하면 좋겠습니다.

    Appendix.

    backgorund

         매개변수 추정을 위한 ERM 알고리즘

    찾고자 하는 모델 의 Risk를 Loss function(L)의 기댓값으로 정의

    통계적 학습(Statistical Learning)의 목표는 이 loss의 기댓값을 최소화하는 를 찾는 것

    그러나 실제  의 확률분포를 알 수 없기 때문에 Risk를 직접 구할 수 없고 주어진 데이터 세트 내에서 근사화해서 찾아야 함. 그 값이 곧 Empirical Risk

    예를 들어, Logistic 함수를 loss 함수로 활용하면 아래와 같음

    이를 최소화하는 (혹은 매개변수)를 찾는 것이 학습의 목표가 되고 Empirical risk minimization이라 함 → SGD를 통해 찾음

    알고리즘(Data Programming의 기본 학습 원리)

    아래의 조건에서 추정치 (2), (3)을 찾을 수 있음
    Λ: 라벨 함수에 의한 라벨 output
    m: 라벨 함수 개수
    Y: predicted class

    1. Class 분류 확률을 2분의 1이라 하고, 아래와 같은 확률을 최대화하는 모델 식을 정의(1: indicator function)

    이 모델에서 각 라벨링 함수 는 객체에 라벨을 붙일 확률 와 객체를 올바르게 라벨링할 확률 을 가짐

    한 데이터 포인트를 입력했을 때, 이 확률값이 1에 가까울수록 라벨 함수들의 태깅을 붙일 확률이 높으며, 출력한 결과도 고르다는 의미로 해석됨

    반대로 0에 가까울수록 라벨 함수들의 태깅을 붙일 확률이 낮으며, 출력한 결과가 상이하거나 Unknown으로 출력하는 비율이 높은 것으로 해석됨

    2. (1)의 식을 최대화하는 를 MLE를 통해 찾음

    3. 위에서 도출한 를 토대로 다시 1번의 logistic loss function을 최소화(empirical risk minimization)하는 weight를 찾음

    학습 방법은 SGD를 통해 도출함(우항의 의 norm은 과적합 방지를 위해 l2 정규화 항을 추가한 형태이며, 는 특정 training data set, 는 단순한 선형결합 함수)

    즉, 노이즈가 덜 포함된 정보(위의 확률분포가 1에 가까운 샘플 위주)로 라벨 함수의 매개변수를 학습한다는 의미로 해

    종속성을 추가한 확장 알고리즘
    라벨 함수 간의 종속 관계를 고려한 factor를 식에 반영한 형태로 변경함
    Λ: Label function matrix, : 라벨 함수 간 종속적인 관계, Unknown을 덜 출력하는 비율 등이 고려된 factor
    종속적인 관계의 요소는 아래와 같음

    1. 라벨 함수의 출력 결과가 Unk이 아닌 것의 개수

    2. 라벨 함수의 출력 결과와 예측된 클래스가 일치하는 수

    3. i번째 데이터 포인트의 라벨 함수 조합(j, k)을 선택했을 때 결과가 일치하는 수

    위의 식을 Negative Log Loss 꼴로 바꾸고 최소화하는 weight를 찾음

    학습된 weight를 각 라벨 함수의 계수로 사용함

    위 확률을 추정하는 상세 기법

    Y가 잠재변수이므로 위의 직접 확률을 추정하지 않고, Λ에 대한 marginal pseudolikelihood를 구하는 방식으로 근삿값을 찾음 → 자세한 내용은 ‘Learning the structure of generative models without labeled data’(Bach 2017)를 참조


    NCSOFT DANBI BLOG

    Data Analytics aNd Business Insights.
    엔씨에 존재하는 다양한 데이터에 대한
    분석을 통해 인사이트를 찾고
    기계학습 및 통계 모델링을 이용해
    고도화된 지표 및 시스템을 개발합니다.
    엔씨의 살아있는 데이터 이야기,
    DANBI BLOG 바로 가기

    Data Analytics aNd Business Insights.
    엔씨에 존재하는 다양한 데이터에 대한
    분석을 통해 인사이트를 찾고
    기계학습 및 통계 모델링을 이용해
    고도화된 지표 및 시스템을 개발합니다.
    엔씨의 살아있는 데이터 이야기,
    DANBI BLOG 바로 가기