반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
Tags
- marketing
- python
- 시각화
- ttest
- 백분위 변환
- 분위수 변환
- ecommerce data
- spearman
- 빈도주의론
- 데이터 분석
- 다중검정
- plot
- data analysis
- 베이지안론
- marketing insight
- error bar plot
- p value plot
- matplotlib
- FWER
- cltv
- 고객가치분석
- python significance level
- python error plot
- 통계
- Pearson
- E-Commerce
- Yeo-Johnsom 변환
- box-cox변환
- lifetimevalue
- 데이터 시각화
Archives
- Today
- Total
Data 공부
[A/B Test] E-commerce conversion ab test data 본문
A/B Test
A/B 테스트에 대한 정의와 관련된 Issue들을 공부하고, kaggle data를 통해 실습한다.
- A/B 테스트
- 두 가지 또는 그 이상의 시안을 실험하여 비즈니스에 최상의 결과를 가져오는 버전을 알아내는 통계적 검증방식
- 목적: 변형이 더 나은 성능을 보는지 통계적으로 검증.
- A/B 테스트 수행 전 중요한 issue
1. KPI 지표의 잘못된 산출
- 작은 실수로 발생할 수 있는 해당 issue는 실험 data를 왜곡시킨다.
2. post-click landing page
- 변경하고자하는 B 안이 기존의 A 안과 동일하게 모든 기기와 브라우저에서 호환되야 한다.
- 테스트 시 A 안이 순간 나타나고 B 안이 나타나는 flicker effect를 조심해야 한다.
3. 너무 빠른 실험 종료(Peeking)
- 통계적 유의성을 위한 실험이 아닌 충분한 표본이 있어야 한다.
- A/A 테스트(https://instapage.com/blog/what-is-aa-testing)
- A/B 테스트를 무작정 진행하게 된다면, 1종 오류의 늪에 빠질 수 있다.
- A/A 테스트를 진행하게 되면, 트래픽에 대해 동일한 Variation을 나타내는지 확인할 수 있으며, AB 테스트 결과에 향상된 신뢰성을 얻게 된다.
- A/A 테스트는 시간과 비용이 기존 A/B테스트 보다 더 소모되는 단점이 있다.
- A/A/B 테스트를 수행하여 정확한 결과를 도출하는 것이 최선으로 선택할 수 있는 방법.
0. Import Package & Data Load¶
- Kaggle data : https://www.kaggle.com/datasets/surajatiitb/ecommerce-conversion-ab-test-data
- eCommerce 웹사이트의 16일 동안 진행 된 AB 테스트 데이터 셋
- Column 설명
- TvC: C, V1으로 이루어진 열, C: 기존 A안을 본 고객, V1: 새로운 B1안을 본 고객
- date: 유저가 방문한 날짜(2021-02-01 ~ 2021-02-16)
- traffic_source: 유저가 웹사이트를 방문한 경로
- device_type: 유저의 디바이스 type(Mobile web, Desktop, App(ipohne, android))
- browser_language: 유저가 사용한 웹사이트 언어
- login_y_n: 유저가 웹사이트 이용시 로그인 여부
- region: 유저가 웹사이트 이용시 접속 지역
- return_y_n: 유저의 첫번째 방문(n) or not(y)
- conversion: 전활율, 유저가 웹사이트 방문하여 물건 구매 유무
In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import beta
from scipy.special import betaln
from IPython.display import display, Markdown
from scipy.stats import chi2_contingency
from statsmodels.stats import power as pwr
import warnings
warnings.filterwarnings('ignore')
df = pd.read_csv("ecommerce_conversion_ab_test_data.csv")
df.head()
Out[1]:
TvC | date | traffic_source | device_type | browser_language | login_y_n | region | return_y_n | conversion | |
---|---|---|---|---|---|---|---|---|---|
0 | C | 2021-02-14 | Referrals | Mweb | Chinese | n | Southwest | y | 1 |
1 | C | 2021-02-14 | Direct | Iphone | English | y | West | y | 0 |
2 | C | 2021-02-11 | Email Marketing | Mweb | English | y | Northeast | y | 0 |
3 | C | 2021-02-11 | Referrals | Iphone | English | y | Southwest | n | 0 |
4 | C | 2021-02-01 | Referrals | Desktop | English | y | Northeast | n | 0 |
1. EDA¶
1-1. data info 및 type¶
In [3]:
# not null, 2,000,000명의 유저기록
# 데이터의 중복은 없다고 가정한다.
df.info()
print("\nNull값 유무:\n", df.isna().any())
# category type 변경
df[['TvC', 'traffic_source', 'device_type', 'browser_language', 'login_y_n', 'region', 'return_y_n',]] = \
df[['TvC', 'traffic_source', 'device_type', 'browser_language', 'login_y_n', 'region', 'return_y_n',]].astype('category')
# date type 변경
df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2000000 entries, 0 to 1999999
Data columns (total 9 columns):
# Column Dtype
--- ------ -----
0 TvC object
1 date object
2 traffic_source object
3 device_type object
4 browser_language object
5 login_y_n object
6 region object
7 return_y_n object
8 conversion int64
dtypes: int64(1), object(8)
memory usage: 137.3+ MB
Null값 유무:
TvC False
date False
traffic_source False
device_type False
browser_language False
login_y_n False
region False
return_y_n False
conversion False
dtype: bool
1-2. column별 data 분포¶
In [4]:
temp_df = df['date'].value_counts()
plt.figure(figsize=(10,4))
day = np.arange(1, 17)
plt.bar(day, temp_df.values, color='coral')
plt.gca().spines[['top', 'right']].set_visible(False)
plt.title("Distribution of Date", fontsize=15)
plt.xlabel('Day', loc='right'); plt.ylabel('Count', loc='top')
plt.xticks(day)
plt.tight_layout()
plt.show()
def plot_pie_chart(ax, title, sizes, labels, colors):
ax.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', startangle=90)
ax.set_title(title, fontsize=12)
for text in ax.texts:
text.set_fontsize(10)
# 각 카테고리에 대해 3x3 서브플롯으로 파이 차트 그리기
categories = df.columns[df.dtypes == 'category'].tolist()
num_plots = len(categories)
fig, axes = plt.subplots(nrows=3, ncols=3, figsize=(12, 12))
colors = plt.cm.get_cmap('tab20', 6).colors
for i, category in enumerate(categories):
row = i // 3
col = i % 3
unique_values = df[category].value_counts()
labels = list(unique_values.index)
sizes = unique_values.values
colors = colors
plot_pie_chart(axes[row, col], 'Distribution of {}'.format(category), sizes, labels, colors)
# 빈 서브플롯 숨기기
for i in range(num_plots, 9):
row = i // 3
col = i % 3
fig.delaxes(axes[row, col])
plt.tight_layout()
plt.show()
데이터 분포
- TvC: C와 V1이 50:50의 분포로 이루어져있음
- Date: 각 일별로 매우 적은 차이로 균등하게 분포
- traffic_source: 자연검색, 직접 유입, 추천, 유료광고, 이메일마케팅, 소셜미디어 순으로 유입
- device_type: Mweb이 가장 큰 비중
- browser_language: English가 가장 큰 비중이며, Spanish가 두번째, 그 외
- login_y_n: y:n 이 3:7의 분포
- region: West, Northeast가 1, 2순위며 그외는 고루 분포
- return_y_n: 6:4의 분포
- conversion: 구매를 한 유저가 방문한 유저 중 10%이다, 0과 1의 값으로 이루어짐
- A안, B안의 그룹의 일관성을 확인하기 위하여 두 그룹의 [traffice_source, device_type, broswer_language, login_y_n, region, return_y_n] 열에서 분포를 비교한다.
In [5]:
# Distribution Visualization
features = ['traffic_source', 'device_type', 'browser_language',
'login_y_n', 'region', 'return_y_n']
fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(15, 10))
axes = axes.flatten()
for i, feature in enumerate(features):
cross_tab = pd.crosstab(df['TvC'], df[feature])
cross_tab.plot(kind='bar', stacked=True, ax=axes[i], legend=False)
axes[i].set_title(f'Distribution of {feature}', fontsize=14)
axes[i].set_xlabel('')
axes[i].set_ylabel('Count', fontsize=12)
axes[i].tick_params(axis='x', rotation=0, labelsize=12)
axes[i].tick_params(axis='y', labelsize=12)
axes[i].legend(fontsize=12, title_fontsize='medium')
plt.tight_layout()
plt.show()
def compare_groups(feature): # 분포 비교를 위한 카이 제곱 검정
cross_tab = pd.crosstab(df[feature], df['TvC'])
chi2, p_value, dof, expected = chi2_contingency(cross_tab)
return cross_tab, chi2, p_value
# 결과를 담을 데이터프레임 초기화
results_df = pd.DataFrame(columns=['Feature', 'Chi-square', 'P-value'])
# 각 특성에 대해 분포 비교하고 데이터프레임에 결과 저장
for feature in features:
cross_tab, chi2, p_value = compare_groups(feature)
results_df = pd.concat([results_df, pd.DataFrame({
'Feature': [feature],
'Chi-square': [chi2],
'P-value': [p_value]
})], ignore_index=True)
display(Markdown("#### Results of Chi-square Test for Group A vs. Group B:"))
display(results_df)
Results of Chi-square Test for Group A vs. Group B:¶
Feature | Chi-square | P-value | |
---|---|---|---|
0 | traffic_source | 7.482639 | 0.187148 |
1 | device_type | 13430.745573 | 0.000000 |
2 | browser_language | 1.786270 | 0.774993 |
3 | login_y_n | 0.400063 | 0.527057 |
4 | region | 6.947409 | 0.138694 |
5 | return_y_n | 1.403850 | 0.236080 |
- device type에서만 두 그룹의 분포가 다르게 나타난다.
- 이는 테스트시 일관성이 없으며 같은 조건에서 테스트가 이루어질 가능성이 있다.
- 현재로선, 이 데이터를 조정하여 모든열의 분포를 맞추는 방법을 찾지 못하였으므로, device_type은 해당 변화에 영향을 미치지 않는다고 가정하고 분석을 시행한다.
- 결과 분석 후 device type 별로 데이터를 분류하여 각 타입별 결과를 다시 살펴본다.
1-3. Sample Size¶
- Sample Size
- Sample Size를 테스트 전 계산해야하는 이유
- 테스트의 충분한 신뢰성을 입증하기 위해
- 실험을 너무 일찍 중단하지 않기 위해
- Sample Size에 대한 답은 항상 "it depends" 이다.
- 표본의 크기가 클 수록 이상치 등으로 발생하는 개별 불일치의 효과가 최소화 되고, 큰 패턴이 분명해진다.
- 보편적인 rule은 높은 신뢰성 테스트를 위해서 최소 30,000명의 유저와 3000번의 전환이 필요하다.
- sample size caclulator: Evan Miller’s calculator, Optimizely, CXL, Unbounce, Convertize
- 베이지안론에 의한 A/B TEST검정 방법은 Sample size를 미리 계산할 필요가 없다.
- Sample Size를 테스트 전 계산해야하는 이유
In [6]:
## Python으로 Sample size계산
# conversion histogram
plt.figure(figsize=(6, 4))
plt.hist(df['conversion'], edgecolor='black')
plt.gca().spines[['top', 'right']].set_visible(False)
plt.xlabel('Conversion'); plt.ylabel('Frequency')
plt.title('Histogram of Conversion for Group C')
plt.xticks([0, 1])
plt.show()
cvr_mean = df['conversion'].mean()
cvr_std = df['conversion'].std()
print("CVR MEAN: {}, STD: {}".format(cvr_mean, cvr_std))
# 원하는 효과 크기와 비교하여 효과 크기 계산
desired_cvr_v1 = 0.11 #우리가 원하는 변환율
effect_size = (desired_cvr_v1 - cvr_mean)/cvr_std # 효과크기 계산
power = 0.8 # 통계적 검정력
alpha = 0.05 # 유의수준
sizes = [len(df[df['TvC']=='C']), len(df[df['TvC']=='V1'])]
ratio = max(sizes)/min(sizes)
# Initialize analysis and calculate sample size
analysis = pwr.TTestIndPower()
ssresult = analysis.solve_power(effect_size=effect_size, power=power, alpha=alpha, nobs1=None, ratio=ratio)
print(f'Sample Size: {int(ssresult)}')
print(f'Real Data Size: {len(df)}')
CVR MEAN: 0.104988, STD: 0.3065380348999424
Sample Size: 58720
Real Data Size: 2000000
- 이상적인 Sample Size보다 실제 데이터의 sample size가 훨씬 크게 나타났다.
2. A/B Test¶
2-1. 빈도주의론(Frequentist Approach)¶
- 빈도주의론은 두 그룹간의 차이가 고정된 값이라 고정하며, 이 차이는 어떤 분포나 확률을 가지지 않는다.
- 귀무가설을 설정한다. "A안과 B안의 전환율에는 차이가 없다."
- 가설이 우연히 발생할 확률(p_value)를 계산하여 이를 기준으로 귀무가설을 기각하거나 채택한다.
- 이 A/B테스트의 종속변수는 conversion이다. conversion은 0과 1로 이루어진 범주형 데이터로서 베르누이 분포를 따르므로, Chi-squared test를 이용하여 두 표본 집단의 분포가 동일한지 확인한다.
- T-Test(Independent T-Test)로 A/B Test를 검증하기 위한 만족사항
- 각 표본의 데이터가 정규 분포를 이루고 있는지 검증
- 두 개의 표본 데이터가 서로 독립성을 이루고 있는지 검증
- 두 개의 표본 데이터가 등분산성을 이루고 있는지 검증
In [7]:
cvr_data = [len(df[(df['TvC']=='C') & (df['conversion']==1)]), len(df[df['TvC']=='C']),
len(df[(df['TvC']=='V1') & (df['conversion']==1)]), len(df[df['TvC']=='V1'])]
conv = [cvr_data[0], cvr_data[2]]
no_conv = [cvr_data[1]-cvr_data[0], cvr_data[3]-cvr_data[2]]
chi2, p_val, d_f, expected = chi2_contingency([conv, no_conv])
print("카이제곱 통계량 :", format(chi2, '.3f'))
print("p_value:", p_val)
카이제곱 통계량 : 510.100
p_value: 6.031020407491849e-113
- 카이제곱 검정 결과 p_value < 0.05로 귀무가설을 기각하여, A안과 B안의 conversion차이는 통계적으로 유의미한것으로 나타남.
In [8]:
conv_date = df.groupby(['TvC', 'date'])['conversion'].mean()
conv_date = conv_date.reset_index()
c_conv_date = conv_date[conv_date['TvC']=='C']['conversion'].values
v1_conv_date = conv_date[conv_date['TvC']=='V1']['conversion'].values
plt.figure(figsize=(10,4))
day = np.arange(1, 17)
plt.plot(day, c_conv_date, color='blue', linewidth=1.5)
plt.plot(day, v1_conv_date, color='red', linewidth=1.5)
plt.gca().spines[['top', 'right']].set_visible(False)
plt.title("Distribution of Date", fontsize=15)
plt.xlabel('Day', loc='right'); plt.ylabel('Conversion', loc='top')
plt.xticks(day)
plt.legend(['A', 'B'], loc='upper right')
plt.ylim(.05, 0.12)
plt.tight_layout()
plt.show()
from statsmodels.stats.multitest import multipletests
day_p_val = []
for i in day:
df_temp = df.copy()
df_temp = df_temp[df_temp['date'].dt.day==i]
cvr_data = [len(df_temp[(df_temp['TvC']=='C') & (df['conversion']==1)]), len(df_temp[df_temp['TvC']=='C']),
len(df_temp[(df_temp['TvC']=='V1') & (df['conversion']==1)]), len(df_temp[df_temp['TvC']=='V1'])]
conv = [cvr_data[0], cvr_data[2]]
no_conv = [cvr_data[1]-cvr_data[0], cvr_data[3]-cvr_data[2]]
chi2, p_val, d_f, expected = chi2_contingency([conv, no_conv])
day_p_val.append(p_val)
alpha = 0.05
rejects, corrected_p_values, _, _ = multipletests(day_p_val, alpha=alpha, method='bonferroni')
results = pd.DataFrame({
'Date': df['date'].dt.day.unique(),
'P-Value': day_p_val,
'Corrected P-Value (Bonferroni)': corrected_p_values,
'Reject Null Hypothesis': rejects
})
display(Markdown("#### \n일자 별 conversion 통계 검증 결과(다중 검정: bonferroni)\n"))
display(results)
¶
일자 별 conversion 통계 검증 결과(다중 검정: bonferroni)
Date | P-Value | Corrected P-Value (Bonferroni) | Reject Null Hypothesis | |
---|---|---|---|---|
0 | 14 | 6.793221e-09 | 1.086915e-07 | True |
1 | 11 | 1.543596e-10 | 2.469753e-09 | True |
2 | 1 | 1.067558e-03 | 1.708093e-02 | True |
3 | 2 | 1.021614e-06 | 1.634582e-05 | True |
4 | 5 | 2.423799e-07 | 3.878079e-06 | True |
5 | 6 | 1.093360e-07 | 1.749377e-06 | True |
6 | 4 | 4.933559e-10 | 7.893694e-09 | True |
7 | 12 | 4.400096e-08 | 7.040154e-07 | True |
8 | 8 | 2.045580e-13 | 3.272927e-12 | True |
9 | 3 | 2.050740e-10 | 3.281183e-09 | True |
10 | 15 | 7.807755e-10 | 1.249241e-08 | True |
11 | 13 | 9.084723e-11 | 1.453556e-09 | True |
12 | 9 | 6.978170e-10 | 1.116507e-08 | True |
13 | 16 | 3.962219e-04 | 6.339551e-03 | True |
14 | 7 | 3.807186e-09 | 6.091498e-08 | True |
15 | 10 | 9.688563e-09 | 1.550170e-07 | True |
- 날짜별 conversion을 살펴보며, 특정 날짜에 결과가 전체 기간에 영향을 미쳤는지 확인해본다.
- 일자별 A, B안의 conversion 추이를 살펴봐도 B안이 항상 A안보다 높게 나타난다.
- 다중검정을 해결하기 위한 bonferroni를 통해 p_value를 보정하더라도 모든 일자에서 A안과 B안의 유의한 차이는 나타난다.
- 이는 추이와 통계량을 확인함으로인해 B안이 A안에 비해 확실한 conversion rate 상승에 대한 효과가 있다는 통계적 근거가 될 수 있다.
2-2. 베이지안론(Bayesian Approach)¶
- Bayesian에서는 귀무가설에 대한 기각없이 확률을 사용하여 미래의 결과를 계산
- Bayesian은 conversion의 정확한 범위를 결정할 수 있다.
- Ex) 빈도주의: A안과 B안의 차이는 통계적으로 유의합니다
- Ex) 베이지안론: B안이 A안에 비해 3%의 전환율 상승을 일으킬 확률은 90% 입니다.
- Sample size와 test 기간 중요하지 않으며, peeking 이슈가 발생하지 않는다.
- 단점: computing power가 많이소요되며, 사전분포 선택의 주관성
In [9]:
cvr_data = [len(df[(df['TvC']=='C') & (df['conversion']==1)]), len(df[df['TvC']=='C']),
len(df[(df['TvC']=='V1') & (df['conversion']==1)]), len(df[df['TvC']=='V1'])]
conversions_A = cvr_data[0]
users_A = cvr_data[1]
conversions_B = cvr_data[2]
users_B = cvr_data[3]
# B가 A를 이길 확률을 계산하는 함수
def prob_B_beats_A(alpha_A, beta_A, alpha_B, beta_B):
total = 0
for i in range(0, alpha_B - 1):
total += np.exp(betaln(alpha_A + i, beta_B + beta_A) - \
np.log(beta_B + i) - betaln(1 + i, beta_B) - betaln(alpha_A, beta_A))
return total
# 확률 계산(Laplace Smoothing으로 인해 +1)
alpha_A = 1 + conversions_A # A의 전환횟수
beta_A = 1 + (users_A - conversions_A) # A의 미전환 횟수
alpha_B = 1 + conversions_B # B의 전환 횟수
beta_B = 1 + (users_B - conversions_B) # B의 미전환 횟
p_test_is_winner = prob_B_beats_A(alpha_A, beta_A, alpha_B, beta_B)
# B의 전환율이 A의 전환율보다 얼마나 높은지 계산
mean_conversion_A = alpha_A / (alpha_A + beta_A)
mean_conversion_B = alpha_B / (alpha_B + beta_B)
relative_increase = (mean_conversion_B - mean_conversion_A) / mean_conversion_A
# 결과 출력
print("Probability that B beats A is: {:2.2f}%".format(100 * p_test_is_winner))
print("Relative increase in conversion rate of B over A: {:.2f}%".format(100 * relative_increase))
Probability that B beats A is: 100.00%
Relative increase in conversion rate of B over A: 9.78%
- bayesian 결과 B안이 A안보다 9.78%의 전환율 상승을 일으킬 확률은 100%이다.
- 카이제곱과 결과는 동일하나, 더욱 효과적으로 설명력이 있는 결과를 나타냈다.
2-3. Device type별 A/B 테스트¶
- 이전 A,B 그룹의 분포를 비교했을 때, Device type의 분포가 다른 것을 확인했다.
- 해당 요인이 결과에 영향을 미칠 수 있는지 device type별로 나누어 a/b test를 재시행하여 결과를 확인.
In [10]:
devices = df['device_type'].unique()
def frequentist_ab(cvr_data):
conv = [cvr_data[0], cvr_data[2]]
no_conv = [cvr_data[1]-cvr_data[0], cvr_data[3]-cvr_data[2]]
chi2, p_val, d_f, expected = chi2_contingency([conv, no_conv])
print("*빈도주의론")
print("카이제곱 통계량 :", format(chi2, '.3f'),
"p_value:", p_val)
def bayesian_ab(cvr_data):
alpha_A = 1 + cvr_data[0]
beta_A = 1 + (cvr_data[1] - cvr_data[0])
alpha_B = 1 + cvr_data[2]
beta_B = 1 + (cvr_data[3] - cvr_data[2])
p_test_is_winner = prob_B_beats_A(alpha_A, beta_A, alpha_B, beta_B)
mean_conversion_A = alpha_A / (alpha_A + beta_A)
mean_conversion_B = alpha_B / (alpha_B + beta_B)
relative_increase = (mean_conversion_B - mean_conversion_A) / mean_conversion_A
print("*베이지안론")
print("Probability that B beats A is: {:2.2f}%".format(100 * p_test_is_winner))
print("Relative increase in conversion rate of B over A: {:.2f}%".format(100 * relative_increase))
for device in devices:
df_temp = df.copy()
df_temp = df_temp[df_temp['device_type'] == device]
cvr_data = [len(df_temp[(df_temp['TvC']=='C') & (df_temp['conversion']==1)]), len(df_temp[df_temp['TvC']=='C']),
len(df_temp[(df_temp['TvC']=='V1') & (df_temp['conversion']==1)]), len(df_temp[df_temp['TvC']=='V1'])]
print("Device: ", device)
frequentist_ab(cvr_data)
bayesian_ab(cvr_data)
print("")
Device: Mweb
*빈도주의론
카이제곱 통계량 : 210.016 p_value: 1.36255270496987e-47
*베이지안론
Probability that B beats A is: 100.00%
Relative increase in conversion rate of B over A: 9.04%
Device: Iphone
*빈도주의론
카이제곱 통계량 : 97.309 p_value: 5.930591425253484e-23
*베이지안론
Probability that B beats A is: 100.00%
Relative increase in conversion rate of B over A: 9.81%
Device: Desktop
*빈도주의론
카이제곱 통계량 : 141.912 p_value: 1.0167871865841328e-32
*베이지안론
Probability that B beats A is: 100.00%
Relative increase in conversion rate of B over A: 10.86%
Device: Android
*빈도주의론
카이제곱 통계량 : 61.897 p_value: 3.619684553697633e-15
*베이지안론
Probability that B beats A is: 100.00%
Relative increase in conversion rate of B over A: 11.07%
- 각 device_type별 ab 테스트 결과 모든 device_type에서 A안과 B안의 차이가 통계적으로 유의하다고 나타났음.
- 해당 변수가 두 그룹간의 conversion차이에 크게 영향을 끼치는 부분은 없는 것으로 확인.
반응형
'Data 분석' 카테고리의 다른 글
News Map 만들기 - PyQt5 (0) | 2021.09.09 |
---|---|
BTS의 성공요인 분석 - 토픽모델링과 소셜 네트워크 분석 활용 (0) | 2021.08.26 |
CNN을 통한 구름 분류 (0) | 2021.08.25 |
휴대폰 사진 정보를 활용한 날씨확인 (0) | 2021.08.25 |
Comments