Rootgram은 큰 분산을 갖거나 비정규 형태의 데이터를 위한 히스토그램입니다.

Rootgram은 큰 분산을 갖거나 비정규 형태의 데이터를 위한 히스토그램입니다.
Photo by Kelly Sikkema / Unsplash

Rootgram

  • 히스토그램의 변형으로 데이터가 비정규적이거나 큰 분산을 가지는 경우, 정확한 분포를 파악하기 위해 사용됩니다.
  • 일반적으로 히스토그램은 데이터의 빈도를 직접적으로 나타내기 때문에, 큰 값이 빈번하게 발생하는 경우 상대적으로 작은 값을 잘 드러내지 못하는 경향이 있습니다. 반면, Rootgram은 빈도를 제곱근 형태로 변환하여, 데이터 분포의 차이를 더 잘 시각화할 수 있도록 돕습니다
  • 여기서 비정규데이터란, 드문 이벤트 발생을 특징으로 하는 데이터를 말합니다. 이러한 데이터는 대부분의 관측치가 0이거나 매우 낮은 값을 가지며 특정 상황에서만 높은 값이나 이벤트가 발생하는 경향이 있습니다.

장단점

장점

  • 분포 파악의 용이성: 데이터 빈도를 제곱근으로 변환하므로, 큰 값과 작은 값을 균형 있게 시각화할 수 있어 데이터의 전체적인 분포를 이해하기 쉽습니다.
  • 노이즈 제거: 큰 빈도 값을 가진 데이터에서 작은 값들이 잘 보이지 않는 문제를 줄여줍니다.
  • 포아송 분포와의 호환성: 포아송 분포처럼 비정규적이고 분산이 큰 데이터를 다룰 때 유용하게 사용할 수 있습니다.

단점

  • 복잡성: 일반적인 히스토그램에 비해 계산이 추가되므로, 사용자가 해석에 익숙하지 않으면 혼란을 줄 수 있습니다.
  • 비선형 변환: 데이터를 제곱근으로 변환하기 때문에, 원래의 값과 직접적인 해석이 어려울 수 있습니다.

대안

  • 히스토그램: 가장 일반적으로 사용되는 도구로, 단순한 데이터 분포를 파악하는 데 적합합니다. 그러나, 데이터의 분산이 크거나 비정규적인 분포에서는 정보를 왜곡할 수 있습니다.
  • 커널 밀도 추정(Kernel Density Estimation, KDE): 히스토그램보다 부드러운 분포 추정을 가능하게 해주는 방법입니다. 연속적인 분포를 추정하는 데 적합하지만, 설정에 따라 정확도가 다를 수 있습니다.

예시

Bayesian Inference에서 사용하는 경우

  • 베이지안 추론에서는 사전 분포(prior distribution)와 사후 분포(posterior distribution)를 사용하여 데이터 기반으로 추론을 수행합니다. 포아송 분포 같은 희소 데이터 모델링에서, 사후 분포가 Zero-Inflated하거나 특정 값에 집중될 수 있습니다. 이 경우 Rootgram을 사용하여 사후 분포를 더 명확하게 시각화할 수 있습니다.
  • 예를 들어, 고객의 사이트 방문 빈도를 포아송 분포로 모델링하고, 이를 기반으로 베이지안 추론을 수행하는 상황을 가정해봅시다. 데이터가 대부분 0 또는 낮은 값에 집중되어 있다면, 일반적인 히스토그램만으로는 분포의 세부 사항을 파악하기 어려울 수 있습니다. Rootgram을 사용하면 사후 분포의 빈도를 제곱근으로 변환하여, 데이터 분포의 패턴을 명확히 확인할 수 있습니다.
  • X축에서의 분포: X축은 포아송 분포의 파라미터 $\lambda$ (lambda)의 값을 나타냅니다. 이 분포는 모델이 주어진 데이터에 대해 $\lambda$ 값이 어떤 범위에서 가장 유력한지를 시사합니다. 즉, 포아송 분포에서 사건 발생 빈도의 추정치를 보여줍니다.
    • 가장 빈도가 높은 구간: Rootgram에서 빈도가 높은 구간은 사후 분포에서 $\lambda$ 값이 가장 가능성이 높은 범위입니다. 이 구간이 실제로 $\lambda$ 값이 어떠한 범위에 집중되는지 보여줍니다.
    • 분포의 폭: 사후 분포의 폭이 넓을수록, $\lambda$ 값에 대한 불확실성이 큽니다. 즉, 모델이 $\lambda$에 대해 확신하지 못하고 여러 값이 가능할 수 있음을 의미합니다.
    • 분포의 중심: Rootgram에서 가장 빈도가 높은 구간이 분포의 중심값에 해당하며, 이는 $\lambda$의 사후 평균값에 해당할 수 있습니다.
import numpy as np  
import matplotlib.pyplot as plt  
import pymc as pm  
  
# 샘플 데이터 생성 (포아송 분포에서 베이지안 추론)  
np.random.seed(42)  
data = np.random.poisson(lam=3, size=100)  
  
# PyMC 베이지안 모델 정의 및 추론  
with pm.Model() as model:  
    lambda_param = pm.Gamma('lambda_param', alpha=1, beta=1)  
    observations = pm.Poisson('observations', mu=lambda_param, observed=data)  
    trace = pm.sample(1000, return_inferencedata=True)  
  
# 사후 분포 시각화  
posterior_lambda = trace.posterior['lambda_param'].values.flatten()  
  
# Rootgram을 그리기 위해 사후 분포의 빈도 계산  
counts, bins = np.histogram(posterior_lambda, bins=30)  
root_counts = np.sqrt(counts)  
  
# 시각화  
plt.bar(bins[:-1], root_counts, width=np.diff(bins), alpha=0.6, color='b')  
plt.title('Rootgram of Posterior Lambda Distribution')  
plt.xlabel('Lambda')  
plt.ylabel('Square Root of Frequency')  
plt.show()

A/B 테스트에서 Rootgram 사용

  • 상황: A/B 테스트는 두 가지 또는 그 이상의 실험군을 비교하여 한쪽의 성능이 더 우수한지 평가하는 데 사용됩니다. A/B 테스트에서 얻은 데이터는 이벤트가 드물거나 0이 많은 경우가 흔합니다. 이런 데이터에서 결과 분포를 히스토그램으로만 시각화할 경우, 특정한 값에 집중된 데이터를 제대로 파악하기 어렵습니다. 이때 Rootgram을 사용하면 두 집단 간의 분포 차이를 더 명확하게 확인할 수 있습니다.
  • 예를 들어, 광고 클릭 수를 기반으로 한 A/B 테스트에서 광고 클릭이 매우 드문 경우, 0 클릭이 매우 많은 데이터를 처리할 수 있습니다. Rootgram은 두 그룹 간 클릭 수 분포의 차이를 더 명확히 시각화할 수 있습니다.
import numpy as np  
import matplotlib.pyplot as plt  
  
# A/B 테스트 데이터 생성 (포아송 분포)  
np.random.seed(42)  
group_a = np.random.poisson(lam=2, size=500)  # 그룹 A 클릭 수  
group_b = np.random.poisson(lam=3, size=500)  # 그룹 B 클릭 수  
  
# 그룹 A Rootgramcounts_a, bins_a = np.histogram(group_a, bins=np.arange(0, max(group_a) + 2) - 0.5)  
root_counts_a = np.sqrt(counts_a)  
  
# 그룹 B Rootgramcounts_b, bins_b = np.histogram(group_b, bins=np.arange(0, max(group_b) + 2) - 0.5)  
root_counts_b = np.sqrt(counts_b)  
  
# Rootgram 시각화  
plt.bar(bins_a[:-1] - 0.1, root_counts_a, width=0.2, alpha=0.6, label='Group A', color='blue')  
plt.bar(bins_b[:-1] + 0.1, root_counts_b, width=0.2, alpha=0.6, label='Group B', color='red')  
plt.title('Rootgram of A/B Test Results')  
plt.xlabel('Number of Clicks')  
plt.ylabel('Square Root of Frequency')  
plt.legend()  
plt.grid(True)  
plt.show()