개요 Domain : 배달음식 어플리케이션 Data set : app_logs 테이블 데이터기간: 2022.08~2022.12 목적: Foodie 현황 데이터분석 데이터분석 1. 월별 활성 사용자 수 목적: 월별 활성 고객 파악을 통해 서비스의 전반적인 흐름 파악 1-1 지표정의 MAU (Monthly Active Users) 한 달 동안 앱을 사용한 순수 고유 사용자 수 중복을 제거한(COUNT DISTINCT) user_id 기준으로 집계 서비스의 전반적인 성장과 규모를 보여주는 핵심 지표 Cart Users 한 달 동안 장바구니에 상품을 담은 순수 고유 사용자 수 event_name = 'click_cart'인 이벤트의 고유 사용자 수 실제 구매 의도를 가진 잠재 고객의 규모를 파악할 수 있는 지표 Payment Users 한 달 동안 실제 결제를 진행한 순수 고유 사용자 수 event_name = 'click_payment'인 이벤트의 고유 사용자 수 실제 매출 발생에 기여한 고객의 규모를 나타내는 지표 Cart to Payment Rate 장바구니 사용자 중 실제 결제로 이어진 비율 (%) (Payment Users / Cart Users) * 100으로 계산 주요 의미: 구매 전환율을 나타내는 핵심 지표 장바구니 단계에서의 이탈률 파악 가능 높을수록 구매 전환이 잘 이루어짐을 의미 쿼리 WITH base AS ( SELECT DISTINCT user_id, user_pseudo_id, event_name, DATE(DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul')) AS event_date, DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_datetime, event_params.key AS param_key, event_params.value.string_value AS string_value, event_params.value.int_value AS int_value FROM advanced.app_logs CROSS JOIN UNNEST(event_params) as event_params WHERE event_date BETWEEN "2022-01-01" AND "2022-12-31" ) # 월별 활성 사용자 분석 ,monthly_active AS ( SELECT FORMAT_DATE('%Y-%m', event_date) as year_month, COUNT(DISTINCT user_id) as MAU, COUNT(DISTINCT CASE WHEN event_name = 'click_cart' THEN user_id END) as cart_users, COUNT(DISTINCT CASE WHEN event_name = 'click_payment' THEN user_id END) as payment_users, ROUND(COUNT(DISTINCT CASE WHEN event_name = 'click_payment' THEN user_id END) * 100.0 / NULLIF(COUNT(DISTINCT CASE WHEN event_name = 'click_cart' THEN user_id END), 0), 2) as cart_to_payment_rate FROM base GROUP BY year_month ORDER BY year_month ) SELECT * FROM monthly_active 시각화 결론 8월~10월 사이 사용자 확대 특시 10월에 MAU가 증가하여 서비스의 성장 사용자 수가 크게 증가했음에도 구매전환율이 안정적으로 유지 MAU증가와 함께 실제 구매자 수도 증가 ⇒ 서비스가 8~10월 사이 급격한 성장세를 통해 사용자가 증가하였으며 일시적인 효과가 아닌 안정적으로 성장세에 맞는 고객을 확보하고 있는 중 Action Item MAU 증가 원인 파악하기 신규고객, 기존고객 중 어떤 고객이 활성화가 된건지 (신규, 기존에 따른 프로모션 등 확인하기) 신규고객이라면 어떤 채널로 유입이 된건지 유입 근거 찾아보기 기존고객이라면 기존고객 대상 프로모션을 한게 있는지, 특정페이지 개선이 되었거나, 변경사항이 있는지 확인해보기 2. Funnel 분석 쿼리 WITH base AS ( SELECT DISTINCT user_id, event_name, event_timestamp, DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_datetime, DATE(DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul')) AS event_date, user_pseudo_id FROM advanced.app_logs WHERE event_date BETWEEN "2022-01-01" AND "2022-12-31" ), user_journey AS ( SELECT user_id, event_date, event_name, event_datetime, -- 사용자별 이벤트 발생 순서 ROW_NUMBER() OVER (PARTITION BY user_id, event_date ORDER BY event_datetime) as event_sequence FROM base ), funnel_steps AS ( SELECT event_date, COUNT(DISTINCT CASE WHEN event_name = 'screen_view' THEN user_id END) as view_users, COUNT(DISTINCT CASE WHEN event_name = 'click_cart' THEN user_id END) as cart_users, COUNT(DISTINCT CASE WHEN event_name = 'click_payment' THEN user_id END) as payment_users FROM user_journey GROUP BY event_date ), funnel_rates AS ( SELECT event_date, view_users, cart_users, payment_users, ROUND(cart_users * 100.0 / NULLIF(view_users, 0), 2) as view_to_cart_rate, ROUND(payment_users * 100.0 / NULLIF(cart_users, 0), 2) as cart_to_payment_rate, ROUND(payment_users * 100.0 / NULLIF(view_users, 0), 2) as view_to_payment_rate FROM funnel_steps ) #SELECT * FROM funnel_rates #ORDER BY event_date SELECT event_date, view_users as view_users_count, cart_users as cart_users_count, payment_users as payment_users_count, ROUND((cart_users * 100.0 / view_users), 2) as view_to_cart_rate, ROUND((payment_users * 100.0 / cart_users), 2) as cart_to_payment_rate, ROUND((payment_users * 100.0 / view_users), 2) as total_conversion_rate FROM funnel_rates ORDER BY event_date 시각화 ⇒ 공휴일 등 특정 날짜에 고객 유입 변동이 큼 8월부터 10월까지 고객이 급격하게 늘었으나 이탈율은 9월에 높게 나타났음 그에 비해 10월은 고객이 크게 늘어났음에도 이탈율은 큰폭으로 보이지 않음 view > cart는 20% 수준의 이탈율이나, cart > payment가 60% 수준의 큰 이탈율 발생 ⇒ 구간별 고객수가 전체적으로 같이 확대되어 이탈율은 월별 특이점 없음 Action Item cart에서 payment 이탈 고객에게 쿠폰지급 프로모션 또는 결제단계 최소화를 통해 이탈율 개선 방법 모색 필요
cols =['neighbourhood_group','neighbourhood','room_type'] # from sklearn.preprocessing import LabelEncoder # for col in cols: # le = LabelEncoder() # train[col] = le.fit_transform(train[col]) # test[col] = le.fit_transform(test[col]) train = pd.get_dummies(train) test = pd.get_dummies(test) train[cols] --------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-89-9aca98e66a02> in <cell line: 14>() 12 test = pd.get_dummies(test) 13 ---> 14 train[cols] 2 frames /usr/local/lib/python3.10/dist-packages/pandas/core/indexes/base.py in _raise_if_missing(self, key, indexer, axis_name) 6247 if nmissing: 6248 if nmissing == len(indexer): -> 6249 raise KeyError(f"None of [{key}] are in the [{axis_name}]") 6250 6251 not_found = list(ensure_index(key)[missing_mask.nonzero()[0]].unique()) KeyError: "None of [Index(['neighbourhood_group', 'neighbourhood', 'room_type'], dtype='object')] are in the [columns]"
섹션19 강의 중 에러메세지와 마주하기 영상에서 에러3 : 결측치가 있는 경우, 모델 학습시 에러가 나므로 결측치를 처리해야 한다고 나와있습니다만, 코드를 실행해보니 결측치가 있는 상태에서도 에러가 나지 않고 학습이 되었습니다 영상을 제작하셨을 당시와 지금의 버전 차이로 인해 에러가 나지 않는 것 같아서 교재 작업형2 ch4 회귀 파트의 코드를 이용해 비교 확인해보았는데요, 교재의 코드에서 수치형 데이터(Item_Weight)의 결측치를 채우지 않고 모델을 실행했을 때 선형회귀 모델에서는 결측치로 인한 에러가 발생하였고, 랜덤포레스트, lightgbm에서는 에러가 발생하지 않았습니다. 저는 랜덤포레스트, lightgbm 모델을 사용하려고 하는데, 이러한 경우에도 전처리를 하는게 더 좋은 방법인지 문의드립니다. 평가지표로 확인을 해보기는 하겠지만 모델 학습에 에러가 나는게 아니라면 없는 값은 없는 대로 학습하는게 더 나을 것 같다는 생각이 들어서요. 감사합니다
안녕하세요 일코님 한글 블록저장에 대해 살펴보다가 궁금한 점이 생겨서 여쭤봅니다. 커서를 이동해서 블록선택한 다음 hwp.HAction.GetDefault("FileSaveAs_S", hwp.HParameterSet.HFileOpenSave.HSet) hwp.HParameterSet.HFileOpenSave.filename = filename hwp.HParameterSet.HFileOpenSave.Format = "HWP" hwp.HParameterSet.HFileOpenSave.Attributes = 1 hwp.HAction.Execute("FileSaveAs_S", hwp.HParameterSet.HFileOpenSave.HSet) 이 코드를 실행하면 블록 저장이 됨을 확인했습니다. 여기서 궁금한 점이 있는데요 hwp.SaveAs(hwp.Path.replace('.hwp', " - 계약서.hwp"), Format="HWP") 이 코드와의 차이점이 뭘까요? 실행하면 위에 코드는 블록저장이 되지만, 아래 코드는 전체 파일이 다른이름으로 저장되더라구요. FileSaveAs_S가 블록저장 메소드인가요? 혹시 가능하다면 한글API설명서 어디에 있는지도 알려주실 수 있을까요? 한글API설명서도 읽을 수 있는 수준이 되고싶은데 너무 어렵네요..
book type은 왜 지정하지 않는지 궁금합니다. 그리고 왜 book type은 지정하지않아도 typescript에서 체킹(?)을 하지 않는지도 궁금합니다. 항상 강의잘보고있습니다. 감사합니다. 아래의 가이드라인을 꼭 읽고 질문을 올려주시기 바랍니다 질문 하시기 전에 꼭 확인해주세요 - 질문 전 구글에 먼저 검색해보세요 (답변을 기다리는 시간을 아낄 수 있습니다) - 코드에 오타가 없는지 면밀히 체크해보세요 (Date와 Data를 많이 헷갈리십니다) - 이전에 올린 질문에 달린 답변들에 꼭 반응해주세요 (질문에 대한 답변만 받으시고 쌩 가시면 속상해요 ) 질문 하실때 꼭 확인하세요 - 제목만 보고도 무슨 문제가 있는지 대충 알 수 있도록 자세한 제목을 정해주세요 (단순 단어 X) - 질문의 배경정보를 제공해주세요 (이 문제가 언제 어떻게 발생했고 어디까지 시도해보셨는지) - 문제를 재현하도록 코드샌드박스나 깃허브 링크로 전달해주세요 (프로젝트 코드에서 문제가 발생할 경우) - 답변이 달렸다면 꼭 확인하고 반응을 남겨주세요 - 강의의 몇 분 몇 초 관련 질문인지 알려주세요! - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
질문 있습니다. 아래와 같이 로짓모델에서 "B"가 사람 유형으로 이미 수치로 인코딩 되어있다고 합니다. (어른은 1, 아이는 2, 청소년은 3) 즉 B열은 수치형으로 되어 있죠. 그러나 성격은 범주형 데이터 입니다.((B = [3,1,3,2,3,...]) 그럼 B열을 C(B)로 하는게 맞는지? B로 하는게 맞는지요?( llf 값과 parameter값이 달라집니다.) from statsmodels.formula.api import logit model = logit("A ~ B + C", data=df).fit() from statsmodels.formula.api import logit model = logit("A ~ C(B) + C", data=df).fit()