////////
Search
Duplicate
🍯

데이터 타입 불일치 및 정제

Tags
Archive
ETA
2025/06/17
Main Task
Sub Task
담당자
메모
상태
Done
생성 일시
2025/06/12 13:32
우선 순위
진행률 %
Task
큐에르
# exit_position_numeric 75 이상이면 완독한 것으로 간주 df['is_completed'] = df['exit_position_numeric'] >= 75 # 유입 경로별 완독률 completion_by_channel = df.groupby('entry_channel')['is_completed'].mean().sort_values(ascending=False) # 추천 클릭 + 자발적 이탈 + 세부 이탈 사유 필터링 filtered = df[ (df['recommendation_clicked'] == 1) & (df['dropout_reason_category'] == '자발적') # & (df['dropout_reason_detail'].isin(['지루함', '너무 김'])) ] reason_ratio = filtered['dropout_reason_detail'].value_counts(normalize=True) # 이탈 기준: exit_position_numeric < 75 (완독 실패) df['is_dropout'] = df['exit_position_numeric'] < 75 # 추천 or 홈메인배너 유입자만 필터 subset = df[df['entry_channel'].isin(['추천', '홈메인배너'])] # 미리보기 사용 여부별 이탈률 비교 dropout_by_preview = subset.groupby('quick_preview_used')['is_dropout'].mean()
Python
복사
석미느
# theme_mode 입력값 중 오타 정제 merged_df["theme_mode"] = merged_df["theme_mode"].replace("customized", "custom") merged_df["theme_mode"] = merged_df["theme_mode"].replace("dark_mode", "dark") merged_df["theme_mode"] = merged_df["theme_mode"].replace("Light", "light") # birthday 컬럼으로 age / age_group 파생 변수 생성 merged_df["birth_year"] = pd.to_numeric(merged_df["birthday"].str[:4], errors="coerce") current_year = pd.Timestamp.now().year merged_df['age'] = current_year - merged_df['birth_year'] bins = [0, 19, 29, 39, 49, 200] labels = ['10대 이하', '20대', '30대', '40대', '50대 이상'] merged_df['age_group'] = pd.cut(merged_df['age'], bins=bins, labels=labels, right=True)
Python
복사
재웅티비
여기에 입력하세욝!
정무느
birthday 990 non-null object
last_access_timestamp 1000 non-null object
⇒ datetime으로 변환 필요
기준일과 6개월 이전 날짜 정의 cutoff_date = pd.Timestamp("2024-01-01") - pd.DateOffset(months=6)
이녕으
Python
복사
실행 및 진행 사항 정리
큐에르
# exit_position_numeric 95 이상이면 완독한 것으로 간주 df['is_completed'] = df['exit_position_numeric'] >= 95 # 유입 경로별 완독률 completion_by_channel = df.groupby('entry_channel')['is_completed'].mean().sort_values(ascending=False) # 추천 클릭 + 자발적 이탈 + 세부 이탈 사유 필터링 filtered = df[ (df['recommendation_clicked'] == 1) & (df['dropout_reason_category'] == '자발적') # & (df['dropout_reason_detail'].isin(['지루함', '너무 김'])) ] reason_ratio = filtered['dropout_reason_detail'].value_counts(normalize=True) # 이탈 기준: exit_position_numeric < 80 (완독 실패) df['is_dropout'] = df['exit_position_numeric'] < 95 # 추천 or 홈메인배너 유입자만 필터 subset = df[df['entry_channel'].isin(['추천', '홈메인배너'])] # 미리보기 사용 여부별 이탈률 비교 dropout_by_preview = subset.groupby('quick_preview_used')['is_dropout'].mean()
Python
복사
석미느
# theme_mode 입력값 중 오타 정제 merged_df["theme_mode"] = merged_df["theme_mode"].replace("customized", "custom") merged_df["theme_mode"] = merged_df["theme_mode"].replace("dark_mode", "dark") merged_df["theme_mode"] = merged_df["theme_mode"].replace("Light", "light") # birthday 컬럼으로 age / age_group 파생 변수 생성 merged_df["birth_year"] = pd.to_numeric(merged_df["birthday"].str[:4], errors="coerce") current_year = pd.Timestamp.now().year merged_df['age'] = current_year - merged_df['birth_year'] bins = [0, 19, 29, 39, 49, 200] labels = ['10대 이하', '20대', '30대', '40대', '50대 이상'] merged_df['age_group'] = pd.cut(merged_df['age'], bins=bins, labels=labels, right=True)
Python
복사
재웅티비
Python
복사
정무느
*데이터 정제 및 변환 # 1. last_access_timestamp datetime 변환 df['last_access_timestamp'] = pd.to_datetime(df['last_access_timestamp']) # 2. birthday datetime 변환 df['birthday'] = pd.to_datetime(df['birthday'], errors='coerce') #요일별평균 exit_position_numeric #1 이상치 날짜 빼기 df = df.dropna(subset=["last_access_timestamp"]) # 2 weekday 컬럼 생성 df["weekday"] = df["last_access_timestamp"].dt.dayofweek # 3 요일별 평균 exit_position_numeric 계산 weekday_avg_exit = ( filtered_df.groupby("weekday")["exit_position_numeric"] .mean() .reset_index()) # 4 요일 숫자를 이름으로 매핑 weekday_avg_exit["weekday_name"] = weekday_avg_exit["weekday"].map({ 0: "월요일", 1: "화요일", 2: "수요일", 3: "목요일", 4: "금요일", 5: "토요일", 6: "일요일"}) # 5 평균 이탈 위치 기준 내림차순 정렬 weekday_avg_exit_sorted = weekday_avg_exit.sort_values(by="exit_position_numeric", ascending=False) # 6 출력 print(weekday_avg_exit_sorted) => 주말완독율이 더 높지 않음, 틀린 가설 # 6개월 이상 미접속자의 이탈 사유 분석 # 1. 기준일과 6개월 이전 날짜 정의 cutoff_date = pd.Timestamp("2024-01-01") - pd.DateOffset(months=6) # 2. 6개월 이상 접속하지 않은 유저 필터링 inactive_users = df[df["last_access_timestamp"] < cutoff_date] # 3. dropout_reason_category 비율 계산 dropout_reason_pct = ( inactive_users["dropout_reason_category"] .value_counts(normalize=True) * 100 ).reset_index() # 4. 컬럼명 정리 dropout_reason_pct.columns = ["dropout_reason_category", "percentage"] # 5. 출력 print(dropout_reason_pct) #자발적 이탈유저 상세사유 # 3. 자발적 이탈한 유저 중 상세 사유 존재하는 데이터만 필터링 voluntary_dropouts = inactive_users[ (inactive_users["dropout_reason_category"] == "자발적") & (inactive_users["dropout_reason_detail"].notna())] # 4. 상세 사유 비율 계산 detail_reason_pct = ( voluntary_dropouts["dropout_reason_detail"] .value_counts(normalize=True) * 100).reset_index() # 5. 컬럼명 정리 detail_reason_pct.columns = ["dropout_reason_detail", "percentage"] # 6. 출력 print(detail_reason_pct)
Python
복사
이녕으
Python
복사
결과
큐에르
user_id gender birthday device_type subscription_plan theme_mode \ 0 user_0001 male 1998-06-17 mobile monthly dark
1 user_0002 male 2010-04-15 mobile monthly dark
2 user_0003 male 1985-02-13 mobile monthly dark
3 user_0004 female 1974-11-21 eReader monthly light
4 user_0005 male 1970-11-01 mobile free_trial dark
.. ... ... ... ... ... ...
995 user_0996 male 2008-08-11 tablet monthly light
996 user_0997 male 1981-01-23 tablet monthly light
997 user_0998 male 2009-07-08 tablet monthly light
998 user_0999 male 2015-07-05 tablet monthly light
999 user_1000 male 1998-10-06 tablet monthly light
entry_channel quick_preview_used recommendation_clicked \\
Plain Text
복사
0 추천 No True
1 추천 No True
2 추천 No True
3 추천 Yes True
4 검색 Yes False
.. ... ... ...
995 추천 Yes True
996 추천 Yes True
997 추천 Yes True
998 추천 Yes True
999 추천 Yes True
last_access_timestamp book_id genre exit_position_numeric \\
Plain Text
복사
0 2023-05-08 14:13:00 E01 경제/시사 68
1 2023-01-13 00:54:00 E01 경제/시사 44
2 2023-07-12 09:13:03 E01 경제/시사 59
3 2023-11-20 21:24:55 N05 소설 97
4 2023-11-01 05:55:04 S02 자기계발 51
.. ... ... ... ...
995 2023-09-03 17:44:46 S01 자기계발 39
996 2023-04-06 07:03:38 S01 자기계발 71
997 2023-12-26 13:44:38 S01 자기계발 10
998 2023-06-26 22:39:14 S01 자기계발 15
999 2023-01-01 20:58:12 S01 자기계발 71
dropout_reason_category dropout_reason_detail is_completed is_dropout
Plain Text
복사
0 자발적 지루함 False True
1 자발적 추천 실패 False True
2 자발적 너무 김 False True
3 UX 불편 NaN True False
4 UX 불편 NaN False True
.. ... ... ... ...
995 자발적 추천 실패 False True
996 자발적 너무 김 False True
997 UX 불편 NaN False True
998 자발적 금한일 False True
999 자발적 지루함 False True
석미느
Python
복사
재웅티비
Python
복사
정무느
#요일별평균 exit_position_numeric weekday exit_position_numeric weekday_name 1 1 62.603604 화요일 2 2 62.076923 수요일 6 6 61.198276 일요일 5 5 60.970588 토요일 3 3 60.791667 목요일 0 0 60.669565 월요일 4 4 58.691589 금요일 # 6개월 이상 미접속자의 이탈 사유 분석 dropout_reason_category percentage 0 자발적 67.849687 1 UX 불편 27.974948 2 기술 이슈 4.175365 dropout_reason_detail percentage 0 추천 실패 51.384615 1 너무 김 19.692308 2 지루함 18.461538 3 금한일 10.461538
Python
복사
이녕으
Python
복사