문제 정의 : 재방문율이 너무 낮다
저번에는 시간 순서로 다음 강의를 듣는지 안듣는지였다면 이번에는
고객이 한 강의만 들었는지 여러 강의를 들었는지 보는 multiple 컬럼을 만들었다.
df['multiple'] = df['userid_DI'].duplicated(keep=False)
d = df.groupby('userid_DI').agg(
multiple=('multiple', 'first'),
age_group=('age_group', 'first')
).reset_index()
sns.countplot(x='multiple',data=d)
plt.title('한 강의만 본 학생 vs 여러 강의를 본 학생')
for p in plt.gca().patches:
plt.text(p.get_x() + p.get_width() / 2, p.get_height(),
f'{int(p.get_height())}명', ha='center', va='bottom', fontsize=12)
plt.show()
전체 402843명의 학생 중 한 강의만 수강한 학생이 318701명
다들 한 강의만 수강했기 때문에 재방문을 높일 필요가 있어 보인다.
가설 1: 연령대 별로 재방문율이 다를 것이다.
# 나이대별 다음 강의 수강 비율 계산
age_course = d.groupby('age_group')['multiple'].mean().reset_index()
age_course['multiple'] *= 100
# 시각화
plt.figure(figsize=(12, 6))
bars = sns.barplot(x='age_group', y='multiple', data=age_course)
sorted_indices = age_course['multiple'].nlargest(2).index
for i, bar in enumerate(bars.patches):
if i in sorted_indices:
bar.set_facecolor('deepskyblue')
else:
bar.set_facecolor('gray')
for p in plt.gca().patches:
plt.gca().annotate(f'{p.get_height():.2f}%',
(p.get_x() + p.get_width() / 2., p.get_height()),
ha='center', va='baseline', fontsize=12)
plt.title('연령대별 다음 강의 수강 비율"')
plt.show()
import numpy as np
from scipy import stats
a0 = df[df['multiple'] == 0]
a0 = a0['age']
a1 = df[df['multiple'] == 1]
a1 = a1['age']
t, pvalue = stats.ttest_ind(c0, c1)
print('나이와 다음 강의 수강 여부 ttest')
print(f"t값: {t}")
print(f"p값: {pvalue}")
나이와 다음 강의 수강 여부 ttest
t값: -678.0349267674329
p값: 0.0
t검정 결과 p값이 0.05 이하이므로 통계적으로 유의미하다.
10대~20대 타겟 맞춤 추천 시스템:
- 수강 중인 강의의 카테고리와 동일한 강의 추천.
- 최근 30일 내 10대~20대 사용자에게 인기 있는 강의 우선 추천.
가설 2: 수료한 사람이 재방문율이 높을 것이다
# 상태별 다음 강의 수강 비율 계산
status_next_course = df.groupby('status')['next_course'].mean().reset_index()
status_next_course['next_course'] *= 100
# 시각화
plt.figure(figsize=(12, 6))
bars = sns.barplot(x='status', y='next_course', data=status_next_course)
sorted_indices = status_next_course['next_course'].nlargest(1).index
for i, bar in enumerate(bars.patches):
if i in sorted_indices:
bar.set_facecolor('deepskyblue')
else:
bar.set_facecolor('gray')
for p in plt.gca().patches:
plt.gca().annotate(f'{p.get_height():.2f}%',
(p.get_x() + p.get_width() / 2., p.get_height()),
ha='center', va='baseline', fontsize=12)
plt.title('상태별 다음 강의 수강 여부 비율')
plt.show()
from scipy.stats import chi2_contingency
result = pd.crosstab(df['status'], df['next_course'])
chi2, p, dof, expected = chi2_contingency(result)
print('상태와 다음 강의 수강 여부')
print(f"카이제곱 통계량: {chi2:.3f}, p-value값: {p:.3f}, 자유도: {dof}")
상태와 다음 강의 수강 여부
카이제곱 통계량: 885.251, p-value값: 0.000, 자유도: 2
카이제곱 검정 결과 수료 상태와 다음 강의 수강 여부가 독립적이지 않다.
p값이 0.05 이하이므로 귀무가설 기각.
수료자 맞춤 추천 시스템:
- 학습 완료 시 "학습 마스터" 배지 지급.
- 수료 후 심화 강의 자동 추천 → "더 깊이 배우고 싶다면, 다음 강의로!"
수료율을 높이는 방법: 장기 학습
# 수료 비율 카테고리별 시각화
certification_rate = df.groupby('activity_category')['certified'].mean().reset_index()
certification_rate['certified'] *= 100
plt.figure(figsize=(12, 6))
bars = sns.barplot(x='activity_category', y='certified', data=certification_rate)
sorted_indices = certification_rate['certified'].nlargest(2).index
for i, bar in enumerate(bars.patches):
if i in sorted_indices:
bar.set_facecolor('deepskyblue')
else:
bar.set_facecolor('gray')
for p in plt.gca().patches:
plt.gca().annotate(f'{p.get_height():.2f}%',
(p.get_x() + p.get_width() / 2., p.get_height()),
ha='center', va='baseline', fontsize=12)
plt.title('카테고리별 수료율 (%)')
plt.show()
import numpy as np
from scipy import stats
c0 = df[df['certified'] == 0]
c0 = c0['ndays_act']
c1 = df[df['certified'] == 1]
c1 = c1['ndays_act']
t, pvalue = stats.ttest_ind(c0, c1, equal_var=False)
print('학습일과 수료 ttest')
print(f"t값: {t}")
print(f"p값: {pvalue}")
학습일과 수료 ttest
t값: -191.4522830062952
p값: 0.0
t테스트 결과 수료 여부에 따른 학습일은 통계적으로 유의미한 차이가 있다.
# 액티비티 카테고리별 다음 강의 수강 비율 계산
activity_next_course = df.groupby('activity_category')['next_course'].mean().reset_index()
activity_next_course['next_course'] *= 100
# 시각화
plt.figure(figsize=(12, 6))
bars = sns.barplot(x='activity_category', y='next_course', data=activity_next_course)
sorted_indices = activity_next_course['next_course'].nlargest(2).index
for i, bar in enumerate(bars.patches):
if i in sorted_indices:
bar.set_facecolor('deepskyblue')
else:
bar.set_facecolor('gray')
for p in plt.gca().patches:
plt.gca().annotate(f'{p.get_height():.2f}%',
(p.get_x() + p.get_width() / 2., p.get_height()),
ha='center', va='baseline', fontsize=12)
plt.title('액티비티 카테고리별 다음 강의 수강 비율 (시간적 순서 기준)')
plt.show()
n0 = df[df['next_course'] == 0]
n0 = n0['ndays_act']
n1 = df[df['next_course'] == 1]
n1 = n1['ndays_act']
t, pvalue = stats.ttest_ind(n0, n1, equal_var=False)
print('학습일과 재방문 ttest')
print(f"t값: {t}")
print(f"p값: {pvalue}")
학습일과 재방문 ttest
t값: -32.70660823122103
p값: 7.737018523246995e-234
재방문 여부에 따른 학습일 또한 유의미한 차이가 있다.
장기 학습자 맞춤 추천 시스템:
강의 구조 개선:
- 각 강의는 최소 30일 이상 학습할 수 있도록 단계별 콘텐츠 구성.
- 예: 1주차 기초 → 2주차 중급 → 3주차 심화 → 4주차 마무리 퀴즈.
출석 체크 및 연속 학습 보상:
- 매일 로그인 시 출석 체크 → 누적 일수에 따라 리워드 제공.
- 30일 연속 학습 시 수료증 및 "학습 마스터" 배지 제공.
- 장기 학습자 전용 보상: 30일 이상 학습한 사용자에게 할인 쿠폰 제공.
30일 이상 학습하게 하는 방법: 강의 콘텐츠 탐색
# 그래프 그리기
fig, axes = plt.subplots(1, 2, figsize=(18, 6))
# 콘텐츠를 본 비율
view_rate = df.groupby('activity_category')['viewed'].mean().reset_index()
view_rate['viewed'] *= 100
sns.barplot(x='activity_category', y='viewed', data=view_rate, ax=axes[0])
axes[0].set_title('강의 콘텐츠를 본 비율 (%)')
for p in axes[0].patches:
axes[0].annotate(f'{p.get_height():.2f}%',
(p.get_x() + p.get_width() / 2., p.get_height()),
ha='center', va='baseline', fontsize=12)
# 콘텐츠 적극적으로 본 비율
explored_rate = df.groupby('activity_category')['explored'].mean().reset_index()
explored_rate['explored'] *= 100
sns.barplot(x='activity_category', y='explored', data=explored_rate, ax=axes[1])
axes[1].set_title('강의 콘텐츠를 적극적으로 본 비율 (%)')
for p in axes[1].patches:
axes[1].annotate(f'{p.get_height():.2f}%',
(p.get_x() + p.get_width() / 2., p.get_height()),
ha='center', va='baseline', fontsize=12)
plt.tight_layout()
plt.show()
viewed는 학습일과 관계없이 일정한 비율을 유지. explored는 학습일이 증가할수록 비율이 크게 상승.
즉 강의 콘텐츠를 그냥 보는 것이 아닌 탐색하는 것이 장기 학습에 도움이 된다는 것을 파악함.
e0 = df[df['explored'] == 0]
e0 = e0['ndays_act']
e1 = df[df['next_course'] == 1]
e1 = e1['ndays_act']
t, pvalue = stats.ttest_ind(e0, e1, equal_var=False)
print('학습일과 콘텐츠 탐색 여부 ttest')
print(f"t값: {t}")
print(f"p값: {pvalue}")
학습일과 콘텐츠 탐색 여부 ttest
t값: -73.83936486017481
p값: 0.0
콘텐츠 탐색 여부에 따른 학습일도 유의미한 차이 있음,
단기 학습자 맞춤 학습 시스템
- "학습 자료 더 보기" 버튼 상시 노출.
- 예: "추가 예제 보기", "심화 설명 확인하기".
- 3일 이상 탐색하지 않으면 "추가 콘텐츠 탐색해보세요" 알림 발송.
'데이터분석 6기 > 본캠프' 카테고리의 다른 글
2025-05-15 실전 프로젝트 5 태블로 시작 (0) | 2025.05.15 |
---|---|
2025-05-14 실전 프로젝트 3 (0) | 2025.05.14 |
2025-05-12 실전프로젝트 2 - 학습일 별로 데이터 분류 (1) | 2025.05.12 |
2025-05-09 실전프로젝트 1일차 - EDA (0) | 2025.05.09 |
2025-05-08 태블로 개인과제 (0) | 2025.05.08 |