티스토리 뷰

전처리를 한 데이터를 기반으로 비즈니스 인사이트를 도출하고 타 부서에게 제안하는 프로세스를 진행해볼게요.

저는 비즈니스 데이터 분석을 사업 기획 방향 및 타당성과 사업 관리를 데이터로 찾고, 검증하는 분야라고 정의하였어요.

각자 생각하는 정의가 있을 텐데 프로젝트 진행 시에는 팀원들과 비즈니스 정의도 통일해서 하는 게 좋겠죠?

상황을 가정해 볼 건데, 우리가 받은 데이터는 라이더가 레스토랑에서 음식을 픽업해서 고객(주문자)에게 전달하는 과정이 담긴 데이터입니다.

즉, 라이더 운영팀이 분석팀에게 요청을 한 거라고 볼 수 있겠죠?

라이더 운영팀은 라이더가 음식 픽업 및 배달을 어떻게 하면 더 효과적으로 할 수 있을지 연구하고, 라이더를 관리하는 팀이라고 하겠습니다.     

그럼 라이더 운영팀 요청 사항을 보겠습니다.

  1. 배달 플랫폼 기업(당사)에서 기획한 배달 프로세스에서 라이더 역할이 잘 이루어지고 있는지
  2. 배달 프로세스를 최적으로 운영하려면 라이더를 얼마큼 영입해야 하는지
  3. 꾸준히 배달을 하는 라이더의 특성은 무엇인지(혹은 배달 업무에 충실하지 않는 라이더의 특성은 무엇인지) 
  4. 지역 기준 시간별 배달 수요 예측을 통해 라이더 배치(프리랜서인 경우 강제적으로 지역 배치를 할 수가 없어 비용으로 라이더 수요를 컨트롤합니다.) 

등등등이 있겠습니다. 

두리뭉실한 요청도 존재하는가 하면, 인사이트 도출할 수 있는 요청도 존재하네요.

먼저 3번을 진행해 볼게요.

 

먼저 코호트 분석을 통해 당사 월별 라이더 가입률과 유지율 혹은 이탈률을 확인해 라이더 특성을 파악해 보겠습니다.

코호트 분석은 쇼핑몰에 유입된 고객들이 시간에 따라 어떤 행동 변화가 있는지 파악하여 군집화 시킬 때 자주 사용되는데, 라이더의 특성을 파악하는데도 도움이 될 거라고 파악이 되어 사용해 보았습니다.

 

1. 기간 파악

저희가 받은 라이더 데이터의 기간을 파악해보겠습니다. 

display(df['Order_Date'].min())
display(df['Order_Date'].max())
display(df['Order_Date'].max() - df['Order_Date'].min() +datetime.timedelta(days=1) )

최초 주문일은 2022년 2월 11일, 마지막 주문일은 2022년 4월 6일 총 55일 데이터입니다.

월별로는 보기에는 기간이 짧으니까 연 기준 주 별로 나누어 보겠습니다. 

df['weekofyear'] = df['Order_Date'].dt.weekofyear
df[['Order_Date','dayoftheweek','weekofyear']]

2월 11일 주는 6주 차이고 4월 6일은 14주 차인 걸 확인할 수 있습니다. 

조금 더 보기 편하게 2월 11일 6주 차를 1주 차로 변환하여 보겠습니다. 

df['weekofyear'] = df['Order_Date'].dt.weekofyear -5
display(df[['Order_Date','dayoftheweek','weekofyear']])
print(df['weekofyear'].max() - df['weekofyear'].min() + 1,'주')

9주 기간이 존재하는 걸 파악하였습니다.

 

전체 데이터에서 Delivery_person_ID, weekofyear 변수 2개만 추출해서 coh_df 프레임에 저장하고 Delivery_person_ID를 인덱스로 설정하겠습니다. 

coh_df = df[['Delivery_person_ID','weekofyear']]
coh_df.set_index('Delivery_person_ID',inplace= True)
coh_df

coh_df의 인덱스 즉 Delivery_person_ID별로 weeofyaer 변수를 groupby 하여 라이더 별 최초 시작일을 확인하겠습니다.    

firstdelivery = coh_df.groupby(coh_df.index)['weekofyear'].min()
firstdelivery

결과를 통해 총 1320명의 라이더가 있다는 것까지 확인할 수 있었습니다. 

라이더 별 최초 배달 시작 주를 coh_df ['firstdelivery'] 변수에 추가하겠습니다. 

coh_df['firstdelivery'] = firstdelivery
coh_df.reset_index(inplace =True)
coh_df

첫 배달을 시작했던 주를 기준으로 주가 지날수록 라이더가 얼마큼 유지되는지 확인해보겠습니다. 

grouped = coh_df.groupby(['firstdelivery', 'weekofyear'])
cohorts=grouped['Delivery_person_ID'].nunique()
cohorts=cohorts.reset_index()
cohorts.rename({'Delivery_person_ID' : 'totaldelivery'}, axis =1, inplace =True)
cohorts

?? 뭔가 이상하네요... 데이터 결과가 깔끔하다는 느낌이 들어요...

제 경험상 실무 데이터가 이렇게 나올 수 없다고 생각을 합니다..(kaggle 데이터의 한계...)

이렇게 나왔다고 말이 안 된다고 생각 하기보다는 왜 이렇게 나왔지를 생각하고 고민해 보는 것도 분석 역량을 키우는데 도움이 된다고 생각해요.

결과를 라이더 운영팀과 미팅하면서 물어봤다고 가정할게요.

미팅에서 라이더 운영팀은 당사와 주 단위 계약을 한 라이더 데이터라는 답변을 받았습니다.

이런 상황이 정확한 정의를 하지 않으면 생기는 문제라고 생각을 해요.(이런 건 너무 극단적이지만..)

라이더 운영팀과 분석팀은 미팅 때 라이더를 이렇게 생각했을 거예요

  • 분석팀이 생각하는 라이더 : 당사에서 발생하는 전체 라이더
  • 라이더 운영팀이 생각 라이더 : 당사와 주 단위로 계약한 라이더

정의를 하지 상태에서 분석을 진행했으면, 라이더 운영 팀과 지속적으로 오해가 생길 거고, 인사이트를 제대로 해석하지 못해 난항을 겪었을 수도 있었을 거예요..(생각만 해도 아찔🤦‍♂️🤦‍♂️)

라이더 운영팀과 라이더 정의를 통일했고, 다시 코호트 분석을 진행하겠습니다.

코호트 분석을 진행하기 위해서는 가로, 세로 칸이 같아야 합니다. (저희는 기간이 9주 니까 9 * 9가 되어야 하는 거죠) 

저희 데이터도 9 * 9로 만들어 보겠습니다. 

s= 3
for i in range(7) :
    cohorts.loc[cohorts.shape[0],'firstdelivery'] = 1
    cohorts.loc[cohorts.shape[0]-1,'weekofyear'] = s
    cohorts.loc[cohorts.shape[0]-1,'totaldelivery'] = 0
    s = s+1
s= 3
for i in range(7) :
    cohorts.loc[cohorts.shape[0],'firstdelivery'] = 2
    cohorts.loc[cohorts.shape[0]-1,'weekofyear'] = s
    cohorts.loc[cohorts.shape[0]-1,'totaldelivery'] = 0
    s = s+1
    
s= 3
for i in range(7) :
    cohorts.loc[cohorts.shape[0],'firstdelivery'] = 3
    cohorts.loc[cohorts.shape[0]-1,'weekofyear'] = s
    cohorts.loc[cohorts.shape[0]-1,'totaldelivery'] = 0
    s = s+1    

s= 5
for i in range(5) :
    cohorts.loc[cohorts.shape[0],'firstdelivery'] = 5
    cohorts.loc[cohorts.shape[0]-1,'weekofyear'] = s
    cohorts.loc[cohorts.shape[0]-1,'totaldelivery'] = 0
    s = s+1    

s= 6
for i in range(4) :
    cohorts.loc[cohorts.shape[0],'firstdelivery'] = 6
    cohorts.loc[cohorts.shape[0]-1,'weekofyear'] = s
    cohorts.loc[cohorts.shape[0]-1,'totaldelivery'] = 0
    s = s+1    

s= 7
for i in range(3) :
    cohorts.loc[cohorts.shape[0],'firstdelivery'] = 7
    cohorts.loc[cohorts.shape[0]-1,'weekofyear'] = s
    cohorts.loc[cohorts.shape[0]-1,'totaldelivery'] = 0
    s = s+1    

s= 8
for i in range(2) :
    cohorts.loc[cohorts.shape[0],'firstdelivery'] = 8
    cohorts.loc[cohorts.shape[0]-1,'weekofyear'] = s
    cohorts.loc[cohorts.shape[0]-1,'totaldelivery'] = 0
    s = s+1    

s= 9
for i in range(1) :
    cohorts.loc[cohorts.shape[0],'firstdelivery'] = 9
    cohorts.loc[cohorts.shape[0]-1,'weekofyear'] = s
    cohorts.loc[cohorts.shape[0]-1,'totaldelivery'] = 0
    s = s+1    
cohorts = cohorts.sort_values(['firstdelivery','weekofyear'])
each_period=cohorts['firstdelivery'].value_counts().sort_index()
cohortperiod = []
for x in each_period : 
    for y in range(x) :
        cohortperiod.append(y)
cohorts['cohortperiod'] = cohortperiod
cohorts.set_index(['firstdelivery','cohortperiod'],inplace =True)

약간의 막일을 통해 비어있는 firstdelivery 주(1 ~ 9주)와 weekofyear, totaldelivery(없으면 0으로)를 채웠습니다.

마지막으로 unstack을 통해 코호트를 마무리하겠습니다. 

cohorts =cohorts['totaldelivery'].unstack(1)
cohorts

해석을 하면 1주 차에 599명의 라이더와 계약을 해서 2주 차까지 배달을 진행하였고(2주 차 때 1명 더 계약), 3주 차 때는 라이더와 계약을 하지 않았으며,  4주 차 때 720명의 새로운 라이더와 9주 차까지 계약해서 배달을 진행하였다고 해석할 수 있습니다. 

여기서 새로운 의문점이 생겼습니다.

1주 차 때 599명을 계약하였고, 4주 차 때 720명을 계약했는데 4주 차 때 720명 계약이 최적이었는지 확인해 보겠습니다.

다음에는 라이더를 더 심도 있게 분석해 당사에게 중요한 라이더가 누구이고 그 특성은 무엇인지 확인해 보겠습니다. 

코호트 분석에 대해서 더 자세히 설명하고 적었어야 했는데, 저는 실제 업무처럼 쓰고 싶은 욕심이 있어 자세한 설명은 제외했습니다.

구글에 코호트 분석을 검색하면 쉽고 친절하게 작성해주신 분들이 계십니다.

그분들의 설명을 참고하시면 쉽게 코호트 분석을 이해할 수 있을 겁니다.😊

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
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
글 보관함