λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ’‘ Data Analysis/πŸ“‚ Project - Analysis of KakaoTalk (end)

[DA][Python] λŒ€ν™” 뢄석 κΈ°λŠ₯ - μ‚¬μš©μžλ³„ 각 μ‹œκ°„λŒ€ ν™œλ™ λΉˆλ„ 뢄석 (3)

by Sun A 2024. 7. 23.

μ•ž κ²Œμ‹œκΈ€μ—μ„œ μΉ΄μΉ΄μ˜€ν†‘ 원본 λŒ€ν™” λ‚΄μš©μ„ λ‚΄λ €λ°›μ•„ μ „μ²˜λ¦¬ν•˜λŠ” 과정을 μž‘μ„±ν•˜κ³  ν•¨μˆ˜λ‘œ κ΅¬ν˜„ν•΄λ³΄μ•˜λ‹€.

β–Ό κ²Œμ‹œλ¬Ό ν™•μΈν•˜κΈ°

 

[DA][Python] (2μ°¨ 섀계 및 μ™„μ„±) μΉ΄μΉ΄μ˜€ν†‘ λŒ€ν™” 데이터 μ „μ²˜λ¦¬ μ½”λ“œ μˆ˜μ • 섀계

ν˜„μž¬ ν•΄λ‹Ή λ‚΄μš©μ€ ν”Όλ“œλ°±μ„ λ°›μ•„ μ½”λ“œ μž‘μ„±μ„ μ™„λ£Œν•˜μ˜€μœΌλ©° μ΅œμ’… μ™„μ„±λœ μ½”λ“œμ— λŒ€ν•œ μ„€λͺ…이닀.μˆ˜μ •μ‚¬ν•­1. ν•¨μˆ˜λͺ…을 λͺ…ν™•ν•˜κ²Œ λ³€κ²½2. 원본 데이터에 μ‘΄μž¬ν•˜λŠ” μ„œλ‘œ λ‹€λ₯Έ ν˜•μ‹μ˜ 라인 두 가지에

sundery.tistory.com

 

μ•žμ„œ 두 개의 ν•¨μˆ˜λ₯Ό λ§Œλ“€μ—ˆκΈ° λ•Œλ¬Έμ— μ„Έλ²ˆμ§Έ κΈ°λŠ₯ ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•˜κ³ μž ν•œλ‹€.

μ΄λ²ˆμ—λŠ” μ‹œκ°„λŒ€ λ²”μœ„λ₯Ό λ‚˜λˆ„κ³  각 μ‚¬μš©μžκ°€ 자주 μ±„νŒ…λ°©μ— λ“€μ–΄μ˜€λŠ” ν™œλ™ μ‹œκ°„λŒ€λ₯Ό λΆ„μ„ν•˜λŠ” 것이닀.

λ²”μœ„μ— λŒ€ν•΄ 각자 λ‚˜νƒ€λ‚˜λŠ” 것이기 λ•Œλ¬Έμ— 파이차트둜 좜λ ₯λ˜λ„λ‘ 섀계할 것이며 κ°œλ³„μ μœΌλ‘œ μ‚¬λžŒμ„ ν•„ν„°λ§ν•˜μ—¬ μΆ”μΆœλ  수 μžˆλ„λ‘ μ½”λ“œλ₯Ό μž‘μ„±ν•  μ˜ˆμ •μ΄λ‹€.

 

λ˜ν•œ μ•žμ„œ ν•¨μˆ˜μ—μ„œ μ‚¬μš©ν•œ 데이터듀은 κ°€μ‘± 단톑방을 κ°€μ Έμ™”μ§€λ§Œ μ΄λ²ˆμ—λŠ” 6λͺ…μ˜ μΈμ›μ˜ 단톑방 λ‚΄μš©μ„ κ°€μ Έμ™€μ„œ 6개의파이차트λ₯Ό 보이도둝 ν•˜μ—¬ λ‹€μ–‘ν•œ 결과값을 λ„μΆœν•  μ˜ˆμ •μ΄λ‹€.


뢄석 λ‚΄μš©

μ‚¬μš©μžλ³„ 각 μ‹œκ°„λŒ€ ν™œλ™ λΉˆλ„ 뢄석

λ¨Όμ € ν•¨μˆ˜κ°€ 2개 λ‚˜μ˜¬ μ˜ˆμ •μ΄λ‹€.

μ‹œκ°„λŒ€ λ²”μœ„λ‘œ λ‚˜λˆ μ„œ ν™œλ™ λΉˆλ„λ₯Ό μ§‘κ³„ν•œ ν•¨μˆ˜μ™€ μ΄λ¦„λ³„λ‘œ κ²°κ³Όλ₯Ό λ”°λ‘œ 좜λ ₯ν•΄μ£ΌλŠ” ν•¨μˆ˜ 두 개λ₯Ό μž‘μ„±ν•  것이닀.

λ¨Όμ € μ‹œκ°„λŒ€ λ²”μœ„λ₯Ό λ‚˜λˆ„λŠ” ν•¨μˆ˜λ₯Ό μ •μ˜ν•œλ‹€.

def analyze_activity_by_time(df):

 

원본 데이터λ₯Ό 참고해보면 μ•„λž˜μ™€ 같은데

μ—¬κΈ°μ„œ Time μΉΌλŸΌμ„ κ°€μ Έμ™€μ„œ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

μš°μ„  λ‚΄κ°€ λ‚˜λˆ„κ²Œ 될 μ‹œκ°„λŒ€ λ²”μœ„λŠ” μ•„λž˜μ™€ κ°™λ‹€.

μƒˆλ²½ μ˜€μ „ μ˜€ν›„ 저녁
00μ‹œ ~ 05μ‹œ 59λΆ„ 06μ‹œ ~ 11μ‹œ 59λΆ„ 12μ‹œ ~ 17μ‹œ 59λΆ„ 18μ‹œ ~ 23μ‹œ 59λΆ„

 

λ²”μœ„λŠ” Hoursλ₯Ό κΈ°μ€€μœΌλ‘œλ§Œ λ‚˜λˆ„κΈ° λ•Œλ¬Έμ— μ‹œκ°„ λ°μ΄ν„°κ°’μ—μ„œ Hours만 μΆ”μΆœν•΄μ•Ό ν•œλ‹€.

df['Hours'] = pd.to_datetime(df['Time'], format='%H:%M').dt.hour
  • Time μΉΌλŸΌμ—μ„œ μ‹œκ°„κ³Ό λΆ„ fomat으둜 κ°€μ Έμ™€μ„œ datetime의 hour만 μΆ”μΆœν•œλ‹€.

 

μ‹œκ°„λŒ€λ₯Ό 4개 λ²”μœ„λ‘œ λ‚˜λˆ„κΈ° μœ„ν•΄ 라벨과 λ²”μœ„λ₯Ό μ§€μ •ν•œλ‹€.

boundary = [0, 6, 12, 18, 24]
labels = ['μƒˆλ²½', 'μ˜€μ „', 'μ˜€ν›„', '저녁']

 

 

그리고 λ°μ΄ν„°ν”„λ ˆμž„ 칼럼 'Time_Parts'λ₯Ό λ§Œλ“€μ–΄μ„œ 값을 λ„£μ–΄μ€€λ‹€.

값은 μ•žμ„œ λ‚˜λˆ„μ—ˆλ˜ Hoursμ—μ„œ κ°€μ Έμ˜¨λ‹€.

df['Time_Parts'] = pd.cut(df['Hours'], bins=boundary, labels=labels, right=False, include_lowest=True)
  •  κ°’은 boundary, 각 λ²”μœ„ λͺ…은 labelsμ—μ„œ κ°€μ Έμ˜€κ³  였λ₯Έμͺ½ 값은 ν¬ν•¨ν•˜μ§€ μ•Šκ³  μ™Όμͺ½ 값은 ν¬ν•¨ν•˜λ„λ‘ False와 Trueλ₯Ό μ§€μ •ν•΄μ€€λ‹€.

 

λ‹€μŒμœΌλ‘œ μ‹œκ°„λŒ€λ³„λ‘œ ν™œλ™ λΉˆλ„λ₯Ό μ§‘κ³„ν•΄μ£ΌλŠ” 값을 μž‘μ„±ν•œλ‹€.

activity_by_time = df.groupby(['Name', 'Time_Parts']).size().reset_index(name='Count_Messages')
return activity_by_time
  • Nameκ³Ό Time_Parts 열을 κΈ°μ€€μœΌλ‘œ κ·Έλ£Ήν™”ν•œλ‹€.
  • 각 그룹의 크기, 각 κ·Έλ£Ή λ‚΄μ˜ ν–‰ 수λ₯Ό κ³„μ‚°ν•˜κΈ° μœ„ν•΄ size()λ₯Ό μ“΄λ‹€. 
  • κ·Έλ£Ήν™” κ²°κ³Όλ₯Ό λ°μ΄ν„°ν”„λ ˆμž„ ν˜•νƒœλ‘œ λ³€ν™˜ν•˜κ³  인덱슀λ₯Ό Count_MessagesλΌλŠ” 칼럼 μ΄λ¦„μœΌλ‘œ μ§€μ •ν•œλ‹€.

 

β–Ό μ΅œμ’… μ½”λ“œ

#μ‚¬μš©μžλ³„ 각 μ‹œκ°„λŒ€ ν™œλ™ λΉˆλ„ 뢄석
def analyze_activity_by_time(df):
    """λ°μ΄ν„°ν”„λ ˆμž„μ—μ„œ μ‹œκ°„λŒ€λ³„ ν™œλ™μ„ 뢄석"""
    
    #μ‹œκ°„λŒ€ Hours 칼럼으둜 μΆ”μΆœ
    df['Hours'] = pd.to_datetime(df['Time'], format='%H:%M').dt.hour
    
    #μ‹œκ°„λŒ€ 4개 λ²”μœ„λ‘œ λ‚˜λˆ„κΈ°
    boundary = [0, 6, 12, 18, 24]
    labels = ['μƒˆλ²½', 'μ˜€μ „', 'μ˜€ν›„', '저녁']
    df['Time_Parts'] = pd.cut(df['Hours'], bins=boundary, labels=labels, right=False, include_lowest=True)
    
    #μ‹œκ°„λŒ€λ³„ ν™œλ™ λΉˆλ„ 집계
    activity_by_time = df.groupby(['Name', 'Time_Parts']).size().reset_index(name='Count_Messages')
    
    return activity_by_time

각 μ‚¬μš©μž 개인 값도 좜λ ₯λ˜λ„λ‘ μž‘μ„±

μœ„μ˜ κΈ°λŠ₯을 파이차트둜 좜λ ₯λ˜λ„λ‘ μ„€μ •ν•  것이기 λ•Œλ¬Έμ— λ”°λ‘œ ν•¨μˆ˜λ₯Ό μ§€μ •ν•΄μ€€λ‹€.

def individual_activity_time(activity_by_time, names):
  • names ν•¨μˆ˜μ— 좜λ ₯값을 찾을 이름을 μž…λ ₯ν•œλ‹€.

 

μ‚¬μš©μž λ°μ΄ν„°μ˜ 값이 λ¬Έμžμ—΄μΈμ§€ μ•„λ‹Œμ§€ ν™•μΈν•˜κ³  리슀트둜 λ³€ν™˜ν•œλ‹€.

if isinstance(names, str):
	names = [names]

 

μ•žμ„œ λ§Œλ“  names 값에 λ“€μ–΄κ°€λŠ” 값을 μ œμ™Έν•œ 값듀은 False둜 μ§€μ •ν•  수 μžˆλ„λ‘ ν•œλ‹€.

user_data = activity_by_time[activity_by_time['Name'].isin(names)]
  • 'Name' μ—΄μ—μ„œ names λ¦¬μŠ€νŠΈμ— μžˆλŠ” 이름듀을 κ°€μ§„ 행을 μ°Ύμ•„μ„œ 데이터 ν”„λ ˆμž„μ„ ν˜•μ„±ν•˜μ—¬ user_data λ³€μˆ˜μ— μ‚½μž…ν•œλ‹€.

 

데이터λ₯Ό μž¬κ΅¬μ„±ν•˜μ—¬ μ‹œκ°„λŒ€ λ²”μœ„μ— 맞게 값이 좜λ ₯λ˜λ„λ‘ ν”Όλ²— ν…Œμ΄λΈ”μ„ κ΅¬μ„±ν•œλ‹€.

pivot_table = user_data.pivot(index='Name', columns='Time_Parts', values='Count_Messages').fillna(0)
  • ν”Όλ²— ν…Œμ΄λΈ”μ˜ ν–‰ λ ˆμ΄λΈ”μ„ 'Name'  κ°’μœΌλ‘œ μ„€μ •ν•œλ‹€.
  • λ˜ν•œ ν”Όλ²— ν…Œμ΄λΈ”μ˜ μ—΄ λ ˆμ΄λΈ”μ„ Time_Parts둜 μ§€μ •ν•˜μ—¬ 각 열을 μ‹œκ°„ λ²”μœ„λ‘œ μ§€μ •ν•œλ‹€.
  • λ§ˆμ§€λ§‰μœΌλ‘œ ν”Όλ²— ν…Œμ΄λΈ”μ˜ 값은 Count_Messages μ—΄ κ°’μœΌλ‘œ λ©”μ‹œμ§€ 수λ₯Ό μ„Όλ‹€.
  • 그리고 값이 μ—†λŠ” 셀은 0으둜 μ§€μ •ν•˜κΈ° μœ„ν•΄ fillna(0)을 μ‚¬μš©ν•˜μ—¬ νŠΉμ • μ‚¬μš©μžμ™€ μ‹œκ°„ 쑰합에 λ©”μ‹œμ§€κ°€ μ—†λŠ” 경우λ₯Ό μ‚­μ œν•œλ‹€.

 

μƒμ„±ν•œ ν”Όλ²— ν…Œμ΄λΈ”μ„ ν™œμš©ν•˜μ—¬ 파이 차트λ₯Ό μƒμ„±ν•œλ‹€.

if not pivot_table.empty:
	pivot_table.iloc[0].plot(kind='pie', autopct='%1.1f%%', startangle=90, legend=False)
    plt.title(f"{names}의 μ‹œκ°„λŒ€λ³„ ν™œλ™ λΉˆλ„")
    plt.ylabel('')
    plt.show()
  • λ§Œμ•½ pivot_table의 데이터가 λΉ„μ–΄μžˆμ§€ μ•Šλ‹€λ©΄
    • pivot_table의 첫 번째 μ‚¬μš©μž 데이터λ₯Ό μ„ νƒν•˜μ—¬ 좜λ ₯ν•œλ‹€. (user_dataλ₯Ό λ„£μ—ˆκΈ° λ•Œλ¬Έμ— μ‚¬μš©μžκ°€ μž…λ ₯ν•œ μ°Έμ—¬μžμ˜ 값이 좜λ ₯λœλ‹€.)
    • 파이차트둜 μ’…λ₯˜λ₯Ό μ„ νƒν•˜κ³  λ°±λΆ„μœ¨λ‘œ ν‘œν˜„ν•˜λ˜, μ†Œμˆ˜μ  첫 번째 μžλ¦¬κΉŒμ§€λ§Œ 좜λ ₯ν•œλ‹€,
    • startangle=90을 μ¨μ„œ 파이 차트의 μ‹œμž‘ 각도λ₯Ό 90으둜 μ„€μ •ν•œλ‹€.
    • λ²”λ‘€λ₯Ό ν‘œμ‹œν•˜μ§€ μ•Šλ„λ‘ legend=False둜 μ„€μ •ν•œλ‹€.
  • 파이차트의 title λͺ…κ³Ό yμΆ• 라벨을 μ œκ±°ν•˜μ—¬ ν‘œμ‹œν•˜λ„λ‘ μž‘μ„±ν•œλ‹€.

 

λ°˜λŒ€λ‘œ μ „μ²΄λ‘œ 좜λ ₯ν•˜κ³  싢을 λ•Œλ₯Ό μž…λ ₯ν•œλ‹€.

μ‚¬μš©μžμ˜ 이름을 μž‘μ„±ν•˜μ§€ μ•Šμ•˜μ„ λ•Œ 전체 값이 좜λ ₯λ˜λ„λ‘ ν•œλ‹€.

else:
	pivot_table = activity_by_time.pivot(index='Name', columns='Time_Parts', values='Count_Messages').fillna(0)
  • μ•žμ—λŠ” user_data 값을 κ°€μ Έμ™€μ„œ ν”Όλ²— ν…Œμ΄λΈ”λ‘œ λ§Œλ“€μ—ˆμ§€λ§Œ, 전체가 좜λ ₯λ˜μ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ— activity_by_timeμ—μ„œ μƒμ„±ν•œλ‹€.

 

μ—¬λŸ¬ 개의 μ„œλΈŒ ν”Œλ‘―μ„ μƒμ„±ν•˜μ—¬ 파이차트λ₯Ό μƒμ„±ν•œλ‹€. (전체λ₯Ό 좜λ ₯ν•˜κΈ° μœ„ν•΄ ν•„μš”)

fig, axes = plt.subplots(nrows=1, ncols=len(pivot_table), figsize=(15, 5))
  • μ—¬λŸ¬ 개의 μ„œλΈŒν”Œλ‘―μ„ μƒμ„±ν•˜λŠ” subplotsλ₯Ό μ‚¬μš©ν•œλ‹€.
  • nrows=1 을 μ‚¬μš©ν•˜μ—¬ ν•œ 행에 λͺ¨λ‘ λ°°μΉ˜λ˜λ„λ‘ ν•œλ‹€.
  • μ„œλΈŒ ν”Œλ‘―μ˜ κ°œμˆ˜λŠ” pivot_table의 ν–‰ 수만큼 생성해야 ν•˜κΈ° λ•Œλ¬Έμ— len을 μ‚¬μš©ν•œλ‹€.pie
  • 전체 κ·Έλž˜ν”„μ˜ 크기λ₯Ό κ°€λ‘œ 15인치, μ„Έλ‘œ 5인치둜 fig μ‚¬μ΄μ¦ˆλ₯Ό μ§€μ •ν•œλ‹€.

 

ν”Όλ²— ν…Œμ΄λΈ”μ˜ λͺ¨λ“  값을 좜λ ₯ν•˜κΈ° μœ„ν•΄ λ°˜λ³΅ν•˜μ—¬ μ²˜λ¦¬ν•˜λŠ” for 문을 μ‚¬μš©ν•œλ‹€.

for i, (names, data) in enumerate(pivot_table.iterrows()):
	data.plot(kind='pie', ax=axes[i], autopct='%1.1f%%', startangle=90, legend=False)
  • for을 μ‚¬μš©ν•˜μ—¬ ν”Όλ²— ν…Œμ΄λΈ”μ˜ 각 행을 λ°˜λ³΅ν•˜μ—¬ μ²˜λ¦¬ν•œλ‹€.
  • i둜 인덱슀 값을 λ‚˜νƒ€λ‚΄κ³  names둜 ν˜„μž¬ ν–‰μ˜ 이름을 λ‚˜νƒ€λ‚Έλ‹€.
  • enumerate 파이썬의 λ‚΄μž₯ ν•¨μˆ˜λ‘œ, 리슀트λ₯Ό μˆœνšŒν•˜λ©΄μ„œ μΈλ±μŠ€μ™€ μš”μ†Œλ₯Ό λ™μ‹œμ— λ°˜ν™˜ν•œλ‹€.
    • names와 dataλ₯Ό 반볡 μˆœνšŒν•œλ‹€.
  • ax=axes[i]λ₯Ό μ‚¬μš©ν•΄μ„œ ν˜„μž¬ μ„œλΈŒν”Œλ‘―μ— 차트λ₯Ό κ·Έλ¦°λ‹€.
  • autopct = '%1.1f%%' λ₯Ό μ΄μš©ν•˜μ—¬ 파이 μ°¨νŠΈμ—μ„œ 각 쑰각의 λΉ„μœ¨μ„ ν‘œμ‹œν•˜λŠ” ν˜•μ‹μœΌλ‘œ μ§€μ •ν•œλ‹€.
    • pie ν•¨μˆ˜μ—μ„œλ§Œ μ‚¬μš©λœλ‹€.
    • fλ₯Ό μ¨μ„œ 숫자λ₯Ό μ†Œμˆ˜λ‘œ ν˜•μ‹ν™”ν•¨μ„ λ‚˜νƒ€λ‚Έλ‹€.
    • %%λ₯Ό μ‚¬μš©ν•΄μ„œ νΌμ„ΌνŠΈ 기호λ₯Ό 좜λ ₯에 ν¬ν•¨μ‹œν‚¨λ‹€.
  • startangle=90으둜 차트의 μ‹œμž‘ 각도λ₯Ό 90으둜 μ„€μ •ν•˜κ³  legend=False λ₯Ό 톡해 λ²”λ‘€λ₯Ό ν‘œμ‹œν•˜μ§€ μ•Šλ„λ‘ μ„€μ •ν•œλ‹€.

 

μ„œλΈŒν”Œλ‘―μ˜ 제λͺ©κ³Ό yλ ˆμ΄λΈ”μ˜ μ„œμ‹μ„ μ—†μ• κ³  κΉ”λ”ν•œ 파이 차트둜 좜λ ₯ν•˜κΈ° μœ„ν•΄ μ•„λž˜μ™€ 같은 μ½”λ“œλ„ μΆ”κ°€ν•œλ‹€.

            axes[i].set_title(names)
            axes[i].set_ylabel('')
  • 각 μ„œλΈŒ 차트의 이름은 μ‚¬μš©μž μ΄λ¦„μœΌλ‘œ μ§€μ •ν•˜κ³  ylabel은 ν•„μš”μ—†κΈ° λ•Œλ¬Έμ— μƒλž΅ν•΄μ€€λ‹€.

 

그리고 파이 μ°¨νŠΈκ°€ 좜λ ₯λ˜λ„λ‘ ν•˜λŠ” μ½”λ“œλ‘œ λ§ˆλ¬΄λ¦¬ν•œλ‹€.

        plt.tight_layout()
        plt.show()
    return individual_activity_time

 

β–Ό 전체 μ½”λ“œ

## κ°œλ³„ μ‚¬μš©μž ν™œλ™ μ‹œκ°„λŒ€ 좜λ ₯ μ½”λ“œ
def individual_activity_time(activity_by_time, names):
    """νŠΉμ • μ‚¬μš©μžμ˜ μ‹œκ°„λŒ€λ³„ ν™œλ™ λΉˆλ„λ₯Ό 파이 차트둜 ν‘œμ‹œ"""
    
    # νŠΉμ • μ‚¬μš©μž 데이터 필터링
    if isinstance(names, str):
        names = [names]
    
    user_data = activity_by_time[activity_by_time['Name'].isin(names)]
    
    # ν”Όλ²— ν…Œμ΄λΈ” 생성
    pivot_table = user_data.pivot(index='Name', columns='Time_Parts', values='Count_Messages').fillna(0)
    
    # 파이 차트 생성
    if not pivot_table.empty:
        pivot_table.iloc[0].plot(kind='pie', autopct='%1.1f%%', startangle=90, legend=False)
        plt.title(f"{names}의 μ‹œκ°„λŒ€λ³„ ν™œλ™ λΉˆλ„")
        plt.ylabel('')
        plt.show()
    else:
        pivot_table = activity_by_time.pivot(index='Name', columns='Time_Parts', values='Count_Messages').fillna(0)

        fig, axes = plt.subplots(nrows=1, ncols=len(pivot_table), figsize=(15, 5))
    
        for i, (names, data) in enumerate(pivot_table.iterrows()):
            data.plot(kind='pie', ax=axes[i], autopct='%1.1f%%', startangle=90, legend=False)
            axes[i].set_title(names)
            axes[i].set_ylabel('')
        plt.tight_layout()
        plt.show()
    return individual_activity_time

activity_by_time = analyze_activity_by_time(df)
individual_activity_time(activity_by_time, ' ')

 


κ²°κ³Όκ°’