Search

2022 카카오 Tech 겨울 인턴십 1. 인턴십에서 무얼 했나?

광고 도메인을 처음 접했다.

첫 코딩을 자동화 주식매매 프로그램을 목표로 했기 때문에, 내 프로그램이 곧바로 돈을 버는 것으로 이어진다는 공통점이 있어 광고 분야에 약간의 관심을 가지고 있는 분야였다. 그러나 지금 자연어 처리도 잘 소화 못하고 있는 와중에 새로운 분야를 도전하는건 무리라고 생각하고 공부는 미뤄뒀었다.
그러던 중 갑자기 뜬 카카오 인턴십 공고…
최종 합격까지 바라지도 않았고, 카카오 코딩테스트가 그렇게 어렵다길래 만약 서류라도 합격하면 코딩테스트 경험해보고 싶어 지원했다.
얼레벌레 코딩테스트 붙고, 과제 전형 붙고, 최종 면접까지 다 붙어버렸다….?
(최종 합격후 ’어쩌면 내 안에 흑염룡이…있을 수도’라는 생각을 했다.)
그래서 첫 출근 후 온보딩 하고 초기 셋팅하고, 사내교육받고 그렇게 1-2주이 지나갔다.
그 후 본격적으로 과제를 받게 되는데,,,,

무얼 했나? (What)

한 줄로 말하자면, ‘광고주의 Seed List와 유사한 유저 상위 300만명을 타게팅하는 전환최적화 모델을 구현’ 하는 과제를 부여받았다. 세부 광고는 2가지 업종(기업)에 대해서 타게팅 하는 것을 목표로 했다.
막연했다. 기존에 다뤘던 프로젝트에서는 데이터가 300만개 이하였던게 대부분이었는데, 추리고 추려서 300만 명을 뽑으라니, 이게 현업인가? 싶었다.
자세한 과정들은 아래서 설명하겠다.
(자주 올라갔던 테라스, 밤이 되면 더 이뻤다.)
(하루에 커피를 몇 번 마셨는지 모르겠다.)

어떻게 했나? (How)

했던 실험들을 나열해보자면,
1.
데이터 EDA를 깊게 했다.
2.
Baseline을 만들었다.
3.
Outlier Detection(Hybrid Sampling) 실험을 했다.
4.
전날의 Weight를 가져와서 추가 학습을 하는 pretrained-model과 관련된 실험을 했다.
5.
Feature Engineering 실험을 했다.

1. 데이터 EDA

주어진 feature가 너무 많아서 고생했다. Row도 너무 많은데, Column도 너무 많았던거다.
모든 Feature에 대해서 EDA를 할 순 없었고, Seed user와 Non-seed User에 대한 차이를 확인할 수 있는 Feature들을 더 깊게 분석했다. (자세한 내용은 말하면 안될거 같아서 Pass)

2. Baseline

직관적으로 0에 가까울수록 non-seed user, 1에 가까울수록 seed user인 Logistic Regression 모델을 만들었다. Solver는 L2가 더 나은 모습을 보여 L2로 했다.(Feature간 상관관계가 나타나 L1의 성능이 떨어졌다는 것도 확인)
데이터셋은 유저의 기본적인 Demography feature들과 유저의 관심사와 관련된 feature들을 사용했다. 추후에 Embedding 실험을 목표로 Sparse Matrix 형태 그대로 학습을 시켰다.

3. Outlier Detection(Hybrid Sampling) 실험

데이터가 너무 많아서 1차 필터링을 똑똑하게 해내고 싶다는 생각으로 시작하게 되었다. 하지만 시간복잡도를 고려하지 않았던게 나의 문제였다.
나의 게획은 Seed user들의 feature를 모으면 Centroid를 구할 수 있겠다는 생각과, 그 것으로부터 멀리 떨어질 수록 고려 대상이 아닐것이라는 아이디어에서 출발했다. 그래서 거리 기반으로 Under Sampling을 하고, Centroid와 근접한 Sample들은 SMOTE와 ADASYN 등의 방법을 통해 Over Sampling하고자 했다.
하지만 멘토님들의 피드백과 같이 직접 실험을 해보니, 시간복잡도로 인해 불가능한 실험이었다. 방대한 규모의 유저들을 일일이 유사도 계산을 할순 없는 노릇이었다. (처음엔 280일이 걸린다고 했는데, 나중에 줄이고 줄여서 50시간까지 줄였다. 그래도 불가능했던 수치였다.) 혹시나 하여 적은 수의 Sample들만 따로 Sampling하여 실험을 해서 성능을 확인했으나 성능이 저조했다. 결국 실험에는 실패했다.

4. Pretrained Model 실험

내가 맡은 유저 타게팅 모델은 도메인 특성상 주기적 혹은 실시간으로 유저의 관심사 업데이트가 가능해야한다. 그 주기는 내가 설정하기 나름이었지만, 일별 데이터가 주어졌기 때문에, 그 데이터를 모두 활용하고자 일별 배치 업데이트하는 모델을 만들었다.
그런데 매일 신규 학습하기보단 전날의 Weight를 가져와서 다음날 추가 학습한다면 성능이 향상되지 않을까 하는 아이디어로 Pretrained Model을 실험했다.
지금 와서 생각해보면, 이 때, 모델 자체를 Neural Network로 바꿨어야 했나 싶다. logistic regression에서는 복잡한 비선형성을 충분히 갖추지 못하기 때문에 아무리 데이터를 많이 학습시키더라도 그 한계가 존재했음을 느낄 수 있었다. 결과적으로 유의미한 성능 향상을 얻지 못했다.

5. Feature Engineering 실험

가장 공들이고 오랜시간 했던 실험이었다. 앞선 실험들이 모조리 실패했기 때문에, 이 것만큼은 꼭 성공하고 싶어서 집요하게 파고들었다.
Baseline 이후 한 번 더 EDA를 깊게 하는 시간을 가졌다. Logistic Regression 모델을 통해 역으로 odds를 해석하면서 알게된 점으로는, 3,4개의 feauture를 제외한 나머지 feature는 Classifer의 기능에 도움이 되지 않는 무의미한 feature들인 것을 확인할 수 있었다. 따라서 이런 feature말고, 유의미한 차이를 보이는 feature를 추가하고, 무의미한 feature를 덜어내면, 성능이 향상될 것으로 기대하며 실험을 시작했다.
우선 당일 구매 전환 유저와 미전환 유저의 과거 행동의 차이에 초점을 두고 EDA를 했다. 분명 유저의 과거 행동을 통해서 힌트를 얻을 수 있을 것이라고 생각했다. 결과적으로 총 29개의 추가적인 feature를 가공해낼 수 있었고, 기존 baseline dataset에 추가해주었다. 하지만 나의 기대와 달리 곧장 성능향상이 이뤄지진 않았다.
또 분석에 돌입했는데, 나의 불찰이었는지 기존 정답 label(Seed or not)과 신규 Feature들간의 Data Leakage가 발생했음을 그제서야 확인할 수 있었다. 그래서 Seed User기간을 오히려 줄였다. 최근 30일간 구매한 유저에 대해서 Seed User라고 정의했던 Baseline과 달리 최근 7일 내에 구매한 유저만 Seed User라고 정의한 것이다. 따라서 Seed User가 4배가량 줄어들었음에도 불구하고, 오히려 성능이 5%가량 향상되었다. 그런데 나머지 한가지 업종에 대해서는 5% 떨어진 결과를 확인할 수 있었다.
똑같은 과정으로 똑같이 학습을 진행했는데 왜 이건 오르고, 저건 떨어졌을까? 하며 두 업종간의 차이를 면밀히 분석해보았다. 결과적으로 한 업종은 업종 특성상 유저 접근이 쉬운 가벼운 업종이기에 인터랙션이 잦은편이었고, 그 중에서 인터랙션이 많았던 유저들이 주로 구매전환으로 이어지는 모습을 보였다. 그에 반해 다른 한 업종은 매우 신중한 업종이었기에 한 번의 인터랙션도 구매 전환으로 이어질 가능성이 있곤 했다. 따라서 이들간의 feature scaling에 차이를 두어 다시 학습했고, 결과적으로 두 업종 모두 높은 성능 향상을 이뤄낼 수 있었다.
자세한 결과는 아래에서 이어 설명하겠다.
(내 자리, 하늘보리는 하루에 7~10병씩은 마셨던 기억이 난다.)

어떤 문제가 있었나? (Problem)

1.
방대한 데이터를 다루는데 경험이 부족했다.
이건 좀 부끄러웠다. 멘토님들은 데이터 사이언티스트 인턴이 데이터를 못다루는게 말이 되나 싶었을거다. 게다가 면접 당시에 ‘나의 장점은 데이터를 통해 인사이트를 잘 뽑아낸다’라고 했는데, 인사이트는 커녕 데이터를 뽑아내고 있지도 못하는 상황이니 말이다.
돌이켜보면, 이전에 접했던 데이터들은 AI대회를 목적으로 이미 잘 정돈되고, 누구나 쉽게 사용할 수 있는 적당한 양의 데이터들이었다. 그래서 EDA를 할 때 굳이 SQL을 사용하지 않고, 주피터에서 CSV를 읽고 모든 row를 다 불러오곤 했었다. 결국 1년 전에 떠듬떠듬 공부했었던 SQL을 급하게 바짝 익히고, 대부분의 EDA를 SQL로 했다.
주피터에서 데이터를 볼 일이 있다면 parquet를 사용해서 Column 기반의 압축을 사용해서 좀 더 가볍게하고, 청크별로 잘라서 데이터를 확인하거나 샘플링해서 빠르게 데이터를 확인하고 넘어가는 등 갖가지 방법들을 활용했다.
나중에 알고보니 parquet이 데이터 사이언티스트에게는 업계 표준이었음을 알게 되었다.
결국, SQL와 꽤 친해졌다. 내맘대로 엄청 긴 쿼리를 그자리에서 쭉 치지는 못하지만, 원하는 복잡한 쿼리가 있다면 대략 틀을 잡고 부족한 부분은 구글링으로 채워서 코드를 완성하는 정도 까지는 할 수 있게 되었다.
2.
리즈닝을 세우는게 부족했다.
멘토님들 그리고 우리 셀분들이 모두 가장 중요하게 여기는 것이 리즈닝이었다. 이전의 내 활동들, 그리고 내가 공부하던 방향은 막연히 성능을 어떻게 올리냐가 주안점으로 삼고 근본없는 공부를 했던 것 같다. 그래서 그런지 ‘이 상황에 이런 것을 쓰면 좋겠다.’ 라는 것은 알아도, 이것을 어떻게 사용해야 최고의 성능을 낼 수 있는지, 지금 문제에 이 방법을 쓰는 것이 맞는지, 이 방법을 왜 써야하는지 등 문제해결과 방법에 대한 충분한 근거와 논리가 필요하다는 것을 잘 모르고 있었다.
어쩌면 학문에 대한 나의 태도를 되돌아 볼 수 있던 계기가 되었던 것 같다. 논문을 읽더라도 수식은 가볍게 여기고 지나치곤 했던 상황들이 떠오르기도 했다. 그런 것들을 작업 중간쯤 뼈저리게 깨닫곤, 다시 처음으로 돌아가서 EDA부터 시작했었다. 앞으로는 어떤 작업을 하던간에 리즈닝과 방법의 타당성을 고민하는 시간을 충분히 가져야겠다는 교훈을 얻을 수 있었다.
3.
기초 개념 공부가 필요하다.
2번 내용과 약간 유사하긴 했다. 나는 개념이 부족했다. 길게 설명할 것 없이 선형대수학, 확률, 통계 등의 지식이 부족하다는 것을 느꼈다. 리즈닝을 할 때, 이런 기초 지식이 부족하니까 근거를 세우는 과정에 어려움을 겪었던 것도 있었던 것 같다. 아직 졸업까지 1년이 남은 지금 알게된게 다행이라고 생각한다.
(코드 돌려놓고 자러 가면 이렇게 ‘죽었음’이 떠서 작업 스케줄이 꼬이곤 했다.)

결과는 어땠나? (Result)

결과적으로 내가 설계한 Baseline에 대비하여 금융업 광고는 30.3%, 소매업 광고는 18.1% 전환 고객을 높일 수 있었다.
하지만 시간이 촉박하여 목표했던 임베딩 모델을 구현할 수 없었던 것이 아쉬움이 남는다.
그리고 나에게 주어진 광고는 2가지뿐이었기 때문에 그 둘의 차이를 비교하며 Rule Based로 feature scaling을 했는데, 만약 광고주가 몇천명일 때는? 이라는 생각이 들었다. 만약 다시 기회가 주어진다면, 이런 feature scaling에 대한 효과적인 솔루션을 찾아보고 싶다.
그리고 실패했던 실험들에 대해서도, ‘혹시 성공할 수 있을 방법은 없었을까’하는 생각이 들며 아쉬움이 남기도 했다.

느낀점?

1.
졸업 전까지 정말 열심히 공부해야겠다는 걸 느꼈다.
재미로 시작했던 AI가 직업으로서 다가오게 되니 많은 생각이 들었다. 데이터 사이언티스트로서 내 역할을 다하기 위해서는 내가 하는 업무와 관련된 기술들에 깊은 개념까지 꿰뚫고 있어야함을 느꼈다. 이건 회고에서 좀 더 자세히 말해보고자 한다.
2.
앞으로 나의 미래가 기대됐다.
비록 전환 인터뷰에서는 떨어졌지만, 딱 1년전까지만 해도 상상도 못했던 회사에서 인턴생활을 했다는 자체로도 큰 수확이었다. 불과 몇 주 전까지만 해도 속상한 감정이 남아있었지만, 꾸준히 하면 또다른 좋은 기회가 찾아올 것이라고 믿는다.
(밤샐때마다 먹은 카카오라면)
(셀회식, 너~무 맛있었다.)
fin