본문 바로가기
> 레벨업의 테크노트

[프론트엔드]데이터 시각화-닥지지 리더보드 개선

by rabelais 2021. 9. 28.

안녕하세요, 빅픽처 인터랙티브에서 프론트엔드 및 대회 데이터 시각화를 맡고 있는 박성렬입니다.👋🏼

저번에는 dak.gg(이하 닥지지)의 PUBG rating 분포 그래프📈를 개선해 보았습니다.

이번에는 닥지지의 리더보드📊를 개선해 보려고 합니다.

웹 스크레이핑(웹 크롤링)

우선 리더보드에 있는 자료를 가져와서 재활용하기 위해 자료 추출을 시도했습니다. 이 과정을 좀 더 전문적으로는 웹 스크레이핑 또는 웹 크롤링이라고 합니다. 보통은 별도의 API 엔드포인트로부터 자료를 가져옵니다. 이번에는 자료가 서버 사이드 렌더링을 통하여 바로 HTML에 렌더되고 있습니다. 따라서 HTML을 다운로드하고 HTML 내용을 해석하는 과정을 거쳐서 자료를 추출합니다.

제가 자바스크립트로 웹 스크레이핑을 할 때에는 퍼페티어(puppeteer)크로미움(chromium) 기반 도구를 사용하는 경우가 대부분입니다. 이번에는 예외적으로 파이썬을 이용해 보기로 했습니다. 파이썬은 각종 데이터 사이언스 도구가 잘 마련되어 있기 때문입니다. 이를 이용하여 간단하게나마 랭킹의 지표들이 유효한 지표인가를 재확인해 보기로 했습니다. 따라서 파이썬에서 가장 자주 사용되는 웹 스크레이핑 도구인 뷰티풀 수프(Beautiful Soup)를 사용하여 자료를 바로 파이썬으로 가져왔습니다.

외부에서도 코드에 쉽게 접근하여 관찰할 수 있도록, 구글 코랩을 이용하여 주피터 노트북과 유사한 환경에서 작업했습니다.

자료를 파이썬의 데이터 분석 도구인 pandas에 넣어 엑셀 스프레드시트처럼 유연하게 사용할 수 있도록 정비했습니다.

import pandas as pd
pd.Dataframe(scraped_data)

닥지지 리더보드의 수치가 pandas를 통하여 엑셀 스프레드시트처럼 정리된 모습.

필요없는 지표 걷어내기

닥지지의 리더보드. 모두 steam으로 같은 region인 것을 확인할 수 있고, 랭킹 순서=RP 순서인 것을 확인할 수 있다.

닥지지의 리더보드를 한 번 살펴보니 랭킹이 사실상 RP(rating)를 중심으로 결정되고 있습니다. 지역(플랫폼)의 경우 동일한 지역과 플랫폼끼리만 순위가 결정되기 때문에 굳이 별도의 컬럼(column)을 만들 필요가 없어 보였습니다. 티어(Tier)의 경우도 순위권 내에 있는 유저들은 모두 마스터이므로 별도로 표기할 필요가 없습니다. 따라서 필요가 없는 세 가지 자료를 지표에서 제거해 주기로 했습니다.

  • 랭킹 → RP로 대체
  • 지역, 플랫폼(Region) → 삭제
  • 티어(Tier) → 삭제

자세히 들여다보니 흥미로운 점이 하나 있습니다. 평균 딜량(AVG Damage) 및 승률 정보(WinRatio)에 백분율을 나타내는 미니 바그래프가 붙어있습니다.

이 바그래프가 흥미로운 이유는, 수치로만 볼 때에도 단순 비교가 가능한 부분인데, 굳이 퍼센트를 바 그래프로 나타내고 있다는 점입니다. 각 항목은 아래의 이유 때문에 바 그래프가 필요하지 않습니다.

  • 승률: 리더보드 내에서 바 그래프의 최대값이 100%가 아니며, 반대로 최소값도 0%가 아닙니다.
  • 평균 데미지: 숫자만으로도 단순 비교가 가능한 부분입니다. 만약 표기를 할 경우 바그래프를 이용하여 정밀하게 비교할 필요 없이 구간화(binning)을 통하여 평균 평균 데미지가 높은지, 낮은지 여부만 분류해주어도 됩니다.

만약 리더보드의 형태를 그대로 둔 채로, 바 그래프만 개선한다면 아래와 같이 개선해 볼 수 있습니다.

승률은 제일 낮은 유저와 제일 높은 유저를 다른 색으로 표기하여 강조하고, 평균 데미지는 구간화를 통하여 높은 구간의 유저만 다른 색으로 표기해줘도 충분히 구분이 가능합니다. 

이와 같은 정보는 바 그래프를 사용하지 않고 수치로만 볼 때에도 단순 비교가 가능합니다. 에드워드 터프트는 사람이 도표상의 숫자를 비교하여 읽는 능력이 생각보다 둔하지 않다고 합니다. 그래프가 더 읽기 쉬울 것이라는 우리의 편견과 달리, 경우에 따라서는 표로 나타낼 때 더욱 읽기 쉬울 수도 있다는 것입니다.

별 의미 없는 바 그래프 대신에, 추세를 나타낼 수 있는 스파크라인(sparkline)형태면 더 좋았을 것 같습니다. 이 인사이트는 잠시 후에 다시 활용해 보도록 하겠습니다.

불필요한 지표를 더 찾기 위해서 랭킹을 보기 위해 리더보드에 들어온 사용자의 입장에서 생각해 보았습니다. 우선 순위를 먼저 확인하고, 순위와 거리가 먼 간접적인 지표를 확인하여 메타를 파악하고 순위 변동에 대비할 것입니다. 리더보드 내의 어떤 지표가 순위와 완전히 동일하다면, 순위를 확인한 뒤에는 따로 해당 지표를 확인할 필요가 없습니다. 따라서 순위와 가장 연관이 큰 RP와, 다른 나머지 지표의 상관계수를 계산하여 불필요한 지표를 찾아 보기로 했습니다.

이 과정에서 아까 준비해둔 파이썬의 데이터 사이언스 도구를 사용합니다. 말이 거창하긴 한데, 사실 코드로 엑셀 작업을 하는 것에 가깝습니다.

# 상관계수 dict로 구하기
import pandas as pd
df = pd.DataFrame(scraped_data)
corr_table = {
    'kd':df['rp'].corr(df['kd']),
    'avgdeals':df['rp'].corr(df['avgdeals']),
    'winratio':df['rp'].corr(df['winratio']),
    'games':df['rp'].corr(df['games']),
    'wins':df['rp'].corr(df['wins'])
}
corr_table
# rating(RP)를 중심으로 비교한 상관계수(1=상관도가 높음, 0=상관도가 낮음)
{'avgdeals': -0.0469168740662585,
 'games': 0.10192800386206963,
 'kd': 0.37578799706742727,
 'winratio': 0.43332919040635653,
 'wins': 0.6880445414631278}

피어슨 상관계수에 따른 분포를 나타낸 그래프. .7을 거쳐 1에 가까워 질수록 상관관계가 강하다는 것을 나타낸다

상관계수를 구하는 방법은 여러가지가 있지만, 일반적으로는 피어슨 상관계수를 이용합니다. pandas에서도 별도로 다른 상관계수를 이용하도록 지정하지 않는 이상 피어슨 상관계수를 이용합니다.

상관계수는 완전 동일한 추세일 때 1에 가까워지고, 추세가 반대가 될수록 0(또는 음수)에 가까워집니다. 완전히 같은 값이 아닌 이상 1은 드뭅니다. 몬테카를로 기법을 이용하여 랜덤한 값을 만든 뒤에 분포도를 그려서 확인해보면, 사실상 0.4정도만 되어도 거의 동일한 추세로 증가하거나 감소한다고 볼 수 있습니다. 따라서 상관계수가 0.68에 달하는 승수(wins)와 승률(winratio)은 불필요한 지표입니다.

직관적으로도 사실 큰 의미가 없을거라는 예상이 가능한데, 이유는 게임에서 RP를 결정하는 지표가 결국 승리한 횟수이기 때문입니다.

시각화 계획하기

시각화를 해야할 유의미한 값은 총 4가지 입니다:

  • RP(rating) → 순위 대체. 리더보드 내에서 순위가 달라도 RP가 같을 수 있기 때문에, RP를 비교할 수 있게 하는 편이 낫다.
  • 평균 딜량(avgdeals)
  • 게임 횟수(games)
  • 킬-어시 횟수(KDA)

존재하는 축이 총 4가지로 볼 수 있는데, 유저를 중심으로 자료를 볼 수 있어야 하기 때문에 축을 별도의 열로 분리하는 것 보다는 하나로 묶어주는 것이 나을 것 같습니다. 따라서 분포도를 사용하기로 했습니다. 문제는 축이 4가지나 되기 때문에, 2차원 분포도로는 표현하기가 어렵습니다.

3차원 공간의 분포도에서는 3가지 축을 모두 나타낼 수 있습니다. 또한 색을 이용하면 나머지 한 가지 축도 표현할 수 있게 됩니다.

따라서 가로 세로 높이 세 가지 축을 가진 3차원 공간에 분포도를 그리기로 했습니다. 여전히 하나의 축이 남는데, RP와 가장 관계성이 적은 평균 딜량 자료를 색으로 표현하기로 했습니다.

3차원 그래픽을 나타내기 위하여 react-three-fiber를 사용하고, 수치를 차트용으로 벡터화하는데 d3를 활용하여 직접 플롯을 그려줍니다. 저번과 마찬가지로 별도의 외부 차트를 사용하지 않고 직접 그렸기 때문에 각각의 값에 커스텀한 라벨을 붙일 수 있습니다. 라벨에 웹 스크레이핑을 하면서 가져온 사용자 닉네임과 프로필 아이콘을 표기해 주었습니다.

라벨에 유저명과 아이콘을 표기했습니다

3차원이기는 하지만 기존에 에드워드 터프트에게서 배운 원칙은 그대로 지켜보았습니다. 데이터-잉크 비율(Data-ink ratio)를 최대한 줄이고, 필요하지 않은 눈금과 정보는 차트쓰레기(chartjunk)로 보고 과감히 삭제합니다. 대신 바닥과 그림자를 추가하여 RP가 드러나는 중심축인 높이축을 조금 더 강조했습니다.

인기있는 전략(메타) 확인하기

시각화를 구현하고 인기있는 전략들을 확인해 보기로 했습니다.

킬-어시(KDA)

분포도를 그려놓고 보니 생각보다 플레이 성향의 차이가 확실히 드러납니다. RP가 곧 승률이므로, 킬-어시 횟수가 많은 유저가 그렇지 않은 유저에 비해서 승리할 확률은 생각보다 낮습니다. 생존형 게임의 특성상 잘 숨어다니는 유저가 잘 죽이는 유저보다 유리하다는 것을 알 수 있습니다.

BMZ_FeiFeiNB3유저의 경우 가장 높은 KDA 횟수를 기록하고 있지만, RP는 랭킹에서 거의 꼴등에 가깝습니다.

게임 횟수

게임 횟수가 승률에 미치는 영향도 생각보다 작은데, 매치 횟수와 RP가 모두 높은 Aquu_ 유저를 제외하고 대부분의 고 RP유저들은 평균수준의 매치 횟수를 가지고 있었습니다.

게임을 여러 횟수 거듭한 유저일수록, 킬-어시 수치가 극단적으로 감소했습니다. 원인은 별도의 분석이 필요할 것으로 예상합니다.

평균 딜량

딜량이 높을수록 킬-어시 수치가 높은 모습이 관찰되었습니다. 특별한 부분은 없지만, 시각화 하는 부분이 재미있었습니다. 특이하게도 평균딜량이 제일 높은 유저가 비교적 상위권 rating을 가지고 있었지만, 반대로 상위권 rating인 유저 대부분의 평균 딜량은 고르게 분포하고 있었습니다.

상위 랭커의 비결

 

전체적으로 높은 RP인 유저들은 KDA와 게임 수에서 극단적으로 높은 수치 보다는 가운데 위치한 평균적인 수치를 보여주었고, 딜량에 있어서는 상관계수에서 확인한 바 대로 RP와는 상당한 차이가 있었습니다. 상위 랭커중에서도 딜량이 높은 유저가 있는 반면, 매우 낮은 유저도 있었습니다. 이처럼 복합적인 관계는 직접 3D화면에서 돌려보며 확인하는 것이 낫기 때문에, 동영상을 첨부했습니다.

킬 수가 높거나 게임을 얼마나 많이했는지는 상관이 없고, 오히려 적당히 밸런싱 있게 플레이한 유저가 상위 랭크에 위치함을 확인할 수 있었습니다.

시간축 부여하기

여기까지 작업하고 나니 생각보다 분포표가 꽤 심심하다는 느낌을 받았습니다. 그러나 이미 충분한 인사이트를 확보한 것도 사실입니다. 에드워드 터프트의 이론에 따르면 여기서 무언가를 더 추가하는 것은 사실상 차트 쓰레기(chartjunk)를 더하는 것이나 다름 없습니다. 그러나 일반적인 정지화상으로 된 시각화와 달리, 인터랙션이 가미된 웹 차트로써 유저가 선택적으로 화면을 열고 닫으면서 주목하고 싶은 범위를 선택할 수 있기 때문에 기능을 더 추가할 수 있습니다.

특히 닥지지 리더보드를 개선하면서 놓친 부분이 있었습니다. 앞서 리더보드를 관찰하는 과정에서 평균 딜량이나 승률이 스파크라인으로 전달되지 않는 점이 아쉬웠는데, 랭킹의 각 유저를 클릭해보니 히스토리를 볼 수 있었습니다. 내용으로는 최근 20개 게임에서의 킬 수와 가장 긴 사격거리가 나열됩니다. 자료의 총합이나 평균을 보는 랭킹과 달리 시간순으로 정렬되어 있었습니다. 꽤 흥미있는 자료이고, 리더보드에 결합하여 플레이어 개개인의 메타를 확인하기 위해 사용하면 더 재미있을 것 같았습니다.

이 시간축 자료를 바탕으로 유저의 정보를 확인하기 위해 마우스를 올리면 볼 수 있는 스파크라인을 추가하고 추가적으로 플레이어의 플레이 방식을 다시 확인해 보았습니다.

DearYJ520유저의 경우 킬 수가 비교적 꾸준히 높고, 최대 사격 거리가 일반적으로 매우 길어 저격 플레이를 즐겨하는 유저라는 것을 알 수 있습니다.

Mr_Faith1 유저의 경우 비교적 킬 수가 더 낮고, 최대 사격거리가 대부분 짧아서 방어 및 은신 위주의 플레이를 즐겨하는 유저라는 것을 알 수 있습니다. 일부 최대 사격거리가 높은 구간이 있어서, 이를 스파크라인으로 표기하지 않고 평균으로 표기할 경우 중거리 사격하는 유저로 오인될 여지가 있지만 스파크라인으로 표기할 경우 실제로는 공격을 그다지 지향하지 않는 성향이라는 것을 파악하기 조금 더 유리합니다.

 

완성된 최종 형태는 이와 같습니다

댓글