가장 주요한 기법
Funnel 분석
acquisition (사용자 획득) : 사용자가 어떻게 서비스를 접하는가?
activation (사용자 활설화) : 사용자가 처음 서비스를 이용했을 때 경험이 좋았는가?
retention (사용자 유지) : 사용자가 우리 서비스를 계속 이용하는가?
referral (추천) : 어떻게 돈을 버는가?
revenue (매출) : 사용자가 다른 사람들에게 제품을 소개하는가?
acquisition : 미디어 별 데이터로 효율적인 마케팅 믹스 도출
activation : 활성 사용자의 고객 획득 비용 계산(CAC)
retention : AB 테스트 결과 분석으로 고객유지율 높이기(Statistical verfification)
referral : 적당한 것이 없어, 고객 구매 후기 분석으로 소비자 인식 조사(Text Mining)
revenue : 고객 세그먼트 도출과 각 고객군별 전략 수립(Clustering)
데이터 셋 설명
TV - TV 매체비 입니다.
radio - 라디오 매체비 입니다.
newspaper - 신문 매체비 입니다.
sales - 매출액 입니다.
전제
분석의 목적
데이터 불러오기 및 확인
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 데이터를 불러옵니다.
from google.colab import files
uploaded = files.upload()
# 데이터를 확인 합니다.
df = pd.read_csv('Advertising.csv')
print(df.shape)
df.tail()
df.info()
df.describe()
(200, 5)
첫번쨰 column은 index인것으로 추정하고 단위가 명확하지는 않음
DF 가공
#0번 column 제거
df = df[['TV', 'radio', 'newspaper', 'sales']]
df.tail()
EDA-heatmap
df.describe()
# 변수간의 correlation을 확인합니다.
df.corr()
corr = df.corr()
sns.heatmap(corr, annot=True)
sales와 높은 상관관계를 가지는 것은 TV, radio 인것을 알 수 있음
EDA-pairplot
sns.pairplot(df)
plt.show()
TV와 radio는 거의 선형 그래프를 나타냄
target과 feature 분리
# Labels와 features를 지정해줍니다.
Labels =df['sales']
features = df[['TV' ,'radio', 'newspaper']]
EDA
# 3개의 시각화를 한 화면에 배치합니다.
figure, ((ax1, ax2, ax3)) = plt.subplots( 1,3)
# 시각화의 사이즈를 설정해줍니다.
figure.set_size_inches(20, 6)
# 미디어별 매체비 분포를 scatterplot으로 시각화해봅니다.
sns.scatterplot(data =df, x='TV', y='sales', ax=ax1)
sns.scatterplot(data =df, x='radio', y='sales', ax=ax2)
sns.scatterplot(data =df, x='newspaper', y='sales', ax=ax3)
선형회귀 분석
import statsmodels.formula.api as sm
model1 = sm.ols(formula = 'sales ~ TV + radio + newspaper', data =df).fit()
print(model1.summary())
OLS분석
선형회귀분석 in scikitlearn
# sklearn의 선형회귀분석 결과와도 같습니다.
from sklearn.datasets import make_regression
from sklearn.linear_model import LinearRegression
model = LinearRegression().fit(features, Labels)
print(model.intercept_, model.coef_)
2.938889369459412 [ 0.04576465 0.18853002 -0.00103749]
계수가 똑같다
# 변수의 포함여부에 따른 ols 결과를 봅니다.
model1 = sm.ols(formula = 'sales ~ TV + radio + newspaper', data =df).fit()
model2 = sm.ols(formula = 'sales ~ TV + radio ', data =df).fit()
model3 = sm.ols(formula = 'sales ~ TV', data =df).fit()
print(model1.summary())
print(model2.summary())
print(model3.summary())
결과 해석
이를 바탕으로 sales 예측
# 각 미디어별 매체비에 따른 sales를 예측해봅니다.
model1.predict({"TV":300, "radio":10, "newspaper":4})
0 18.549433
dtype: float64
학습된 모델에 원하는 값을 dic 형태로 넣어 예측값을 확인 할 수 있다.
데이터 변환 후 재분석
# 데이터의 분포를 다시 시각화 해봅니다.
# 3개의 시각화를 한 화면에 배치합니다.
figure, ((ax1, ax2, ax3)) = plt.subplots(1, 3)
# 시각화의 사이즈를 설정해줍니다.
figure.set_size_inches(20, 6)
# 미디어별 매체비 분포를 seaborn의 distplot으로 시각화해봅니다.
sns.distplot(df['TV'], ax=ax1)
sns.distplot(df['radio'], ax=ax2)
sns.distplot(df['newspaper'], ax=ax3)
다른 매체에 비해 newspaper는 소액광고가 많은 것을 알 수 있음
newspaper의 경우에는 '왜도'가 심해 정확한 분석을 하기 어려울 수 있다. 그렇기 떄문에 정규화가 필요한데 이럴 떄 사용하는 정규화는 log정규화
# 데이터의 분포를 다시 시각화 해봅니다.
# 3개의 시각화를 한 화면에 배치합니다.
figure, ((ax1, ax2, ax3, ax4)) = plt.subplots(1, 4)
# 시각화의 사이즈를 설정해줍니다.
figure.set_size_inches(20, 6)
# 미디어별 매체비 분포를 seaborn의 distplot으로 시각화해봅니다.
sns.distplot(df['TV'], ax=ax1)
sns.distplot(df['radio'], ax=ax2)
sns.distplot(df['newspaper'], ax=ax3)
sns.distplot(df['log_newspaper'], ax=ax4)
어느정도 정규화가 되었음을 알 수 있다.
이를 바탕으로 새로운 OLS model 생성
model4=sm.ols(formula='sales ~ TV + radio + log_newspaper', data=df).fit()
print(model4.summary())
model1과 비교하였을 떄 newspaper의 coef값이 소폭 증가하였고 p-value도 소폭 감소하였지만 여전히 0.05구간 에서 유의하지 않았다. 결국 신문광고가 매출액에 큰 영향을 미치지 않는다는 것을 알 수 있다.
여기서 시사점은 라디오의 coef가 가장 큰것을 알 수 있다. 비용대비 효율은 라디오가 가장 좋다는 것을 알 수 있다.
적용 방안
허상적 지표와 행동적 지표
OMTM : 친구추천 기능
A/B Test로 고객 retention을 높이자
모바일 게임의 고객 로그 데이터를 분석해서 고객 유지율을 높여봅니다.
A/B Test는 각 버전을 나누어 어느것이 전략적으로 뛰어난지를 판별하는 테스트. 재구매율 및 구매 전환률등 컨샙에 따라 다양한 지표가 기준이 될 수 있음
데이터 설명
데이터는 다음의 링크에서 다운받을 수 있습니다. (https://www.kaggle.com/yufengsui/mobile-games-ab-testing)
문제 정의
EDA
from google.colab import files
uploaded = files.upload()
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
데이터 기본 정보
df = pd.read_csv('cookie_cats.csv')
df.info()
df.shape
결측치는 없는 것으로 확인 shape을 통해 user 수가 9만인 것을 확인
버전별로 어떤 차이가 있는지 분석
# AB 테스트로 사용된 버전별로 유저들은 몇 명씩 있을까요?
df.groupby('version').count()
게임의 버전은 gage_30과 gate_40으로 구분되어 있고 유저 유입률은 두 버전 다 4만 정도로 비슷한것을 알 수 있다.
게임플레이 횟수 확인
# box plot을 그려봅니다.
sns.boxenplot(data = df, y='sum_gamerounds')
확실히 아웃라이어가 있는 것으로 보입니다.
첫 14일 동안 50,000회 가까이 게임을 한 사람들이 분명히 있지만 일반적인 사용행태라고 하기는 어렵습니다.
엄청나게 skewed한 데이터 분포입니다.
고로 데이터 4만회 이상 플레이한 플레이어는 제거하는 것이 분석에 용이할것
df = df[df['sum_gamerounds']< 40000]
df.shape
sns.boxenplot(data = df, y='sum_gamerounds')
어느 정도 분석에 용이한 그래프가 나옴
sum_gamerounds에 대한 분석
df[sum_gamerounds].describe()
count 90188.000000
mean 51.320253
std 102.682719
min 0.000000
25% 5.000000
50% 16.000000
75% 51.000000
max 2961.000000
Name: sum_gamerounds, dtype: float64
전반적으로 51회 게임을 진행을 했고
중앙값은 16회 인것으로 보아 빠진 사람은 푹빠지는 느낌
각 게임실행횟수 별 유저의 수를 카운트 해봅니다.
plot_df = df.groupby('sum_gamerounds')['userid'].count()
%matplotlib inline
ax = plot_df[:100].plot(figsize=(10,6))
ax.set_title("The number of players that played 0-100 game rounds during the first week")
ax.set_ylabel("Number of Players")
ax.set_xlabel('# Game rounds')
그래프를 분석해 보면 다운로드만 하는 플레이어 수도 무척 많다는 것을 알 수 있음 라운드가 진행되면 진행될 수록 유저수는 지속적으로 감소
1-day retention의 평균을 살펴봅니다.
df['retention_1'].mean()
0.4452144409455803
절반 미만이 이 게임을 다음날 실행함
version별 1-day retention의 평균을 살펴봅니다.
df.groupby('version')['retention_1'].mean()
version
gate_30 0.448198
gate_40 0.442283
Name: retention_1, dtype: float64
7-day retention의 평균을 살펴봅니다.
df['retention_7'].mean()
df.groupby('version')['retention_7'].mean()# 그룹별 7-day retention의 평균을 살펴봅니다.
0.1860557945624695
version
gate_30 0.190183
gate_40 0.182000
Name: retention_7, dtype: float64
Bootstrap
T-Square
K-Square
Bootstrapping
두 그룹간의 차이가 유의미한지 알아보는 다른 방법을 사용해보겠습니다.
# 각각의 AB그룹에 대해 bootstrapp된 means 값의 리스트를 만듭니다.
boot_1d = []
for i in range(1000):
boot_mean = df.sample(frac = 1,replace = True).groupby('version')['retention_1'].mean()
boot_1d.append(boot_mean)
# list를 DataFrame으로 변환합니다.
boot_1d = pd.DataFrame(boot_1d)
# A Kernel Density Estimate plot of the bootstrap distributions
boot_1d.plot(kind='density')
위의 두 분포는 AB 두 그룹에 대해 1 day retention이 가질 수 있는 부트 스트랩 불확실성을 표현합니다.
비록 작지만 차이의 증거가있는 것 같아 보입니다.
자세히 살펴보기 위해 % 차이를 그려 봅시다.
# 두 AB 그룹간의 % 차이 평균 컬럼을 추가합니다.
boot_1d['diff'] = (boot_1d.gate_30 - boot_1d.gate_40)/boot_1d.gate_40*100
# bootstrap % 차이를 시각화 합니다.
ax = boot_1d['diff'].plot(kind='density')
ax.set_title('% difference in 1-day retention between the two AB-groups')
# 게이트가 레벨30에 있을 때 1-day retention이 클 확률을 계산합니다.
print('게이트가 레벨30에 있을 때 1-day retention이 클 확률:',(boot_1d['diff'] > 0).mean())
T-test
통계적인 기준으로 판단하는 방법을 알아봅니다.
df_30 =df[df['version'] == 'gate_30']
df_40 =df[df['version'] == 'gate_40']
from scipy import stats
#독립표본 T-검정 (2 Sample T-Test)
tTestResult = stats.ttest_ind(df_30['retention_1'], df_40['retention_1'])
tTestResultDiffVar = stats.ttest_ind(df_30['retention_1'], df_40['retention_1'], equal_var=False)
tTestResult
Ttest_indResult(statistic=1.7871153372992439, pvalue=0.07392220630182521)
값이 애매하다
tTestResult = stats.ttest_ind(df_30['retention_7'], df_40['retention_7'])
tTestResultDiffVar = stats.ttest_ind(df_30['retention_7'], df_40['retention_7'], equal_var=False)
tTestResult
0초
tTestResult = stats.ttest_ind(df_30['retention_7'], df_40['retention_7'])
tTestResultDiffVar = stats.ttest_ind(df_30['retention_7'], df_40['retention_7'], equal_var=False)
tTestResult
Ttest_indResult(statistic=3.1575495965685936, pvalue=0.0015915357297854773)
T Score
P-values
t-test
https://www.statisticshowto.datasciencecentral.com/probability-and-statistics/t-test/
사실은 t-test 수치형 데이터에 사용하는 것이고
범주형 데이터는 k-square을 사용
chi-square