WeniVooks

검색

Right Now, Polars

Tips 데이터 분석

1. 데이터 불러오기

# seaborn의 tips 데이터셋 로드
tips_df = pl.from_pandas(sns.load_dataset('tips'))
tips_df
# seaborn의 tips 데이터셋 로드
tips_df = pl.from_pandas(sns.load_dataset('tips'))
tips_df

2. 데이터 정보 확인

print("데이터 기본 정보:")
print(tips_df.glimpse())
print(tips_df.describe())
print("데이터 기본 정보:")
print(tips_df.glimpse())
print(tips_df.describe())
데이터 기본 정보:
Rows: 244
Columns: 7
$ total_bill <f64> 16.99, 10.34, 21.01, 23.68, 24.59, 25.29, 8.77, 26.88, 15.04, 14.78
$ tip        <f64> 1.01, 1.66, 3.5, 3.31, 3.61, 4.71, 2.0, 3.12, 1.96, 3.23
$ sex        <cat> Female, Male, Male, Male, Female, Male, Male, Male, Male, Male
$ smoker     <cat> No, No, No, No, No, No, No, No, No, No
$ day        <cat> Sun, Sun, Sun, Sun, Sun, Sun, Sun, Sun, Sun, Sun
$ time       <cat> Dinner, Dinner, Dinner, Dinner, Dinner, Dinner, Dinner, Dinner, Dinner, Dinner
$ size       <i64> 2, 3, 3, 2, 4, 4, 2, 4, 2, 2

None
shape: (9, 8)
┌────────────┬────────────┬──────────┬──────┬────────┬──────┬──────┬──────────┐
│ statistic  ┆ total_bill ┆ tip      ┆ sex  ┆ smoker ┆ day  ┆ time ┆ size     │
│ ---        ┆ ---        ┆ ---      ┆ ---  ┆ ---    ┆ ---  ┆ ---  ┆ ---      │
│ str        ┆ f64        ┆ f64      ┆ str  ┆ str    ┆ str  ┆ str  ┆ f64      │
╞════════════╪════════════╪══════════╪══════╪════════╪══════╪══════╪══════════╡
│ count      ┆ 244.0      ┆ 244.0    ┆ 244  ┆ 244    ┆ 244  ┆ 244  ┆ 244.0    │
│ null_count ┆ 0.0        ┆ 0.0      ┆ 0    ┆ 0      ┆ 0    ┆ 0    ┆ 0.0      │
│ mean       ┆ 19.785943  ┆ 2.998279 ┆ null ┆ null   ┆ null ┆ null ┆ 2.569672 │
│ std        ┆ 8.902412   ┆ 1.383638 ┆ null ┆ null   ┆ null ┆ null ┆ 0.9511   │
│ min        ┆ 3.07       ┆ 1.0      ┆ null ┆ null   ┆ null ┆ null ┆ 1.0      │
│ 25%        ┆ 13.37      ┆ 2.0      ┆ null ┆ null   ┆ null ┆ null ┆ 2.0      │
│ 50%        ┆ 17.81      ┆ 2.92     ┆ null ┆ null   ┆ null ┆ null ┆ 2.0      │
│ 75%        ┆ 24.08      ┆ 3.55     ┆ null ┆ null   ┆ null ┆ null ┆ 3.0      │
│ max        ┆ 50.81      ┆ 10.0     ┆ null ┆ null   ┆ null ┆ null ┆ 6.0      │
└────────────┴────────────┴──────────┴──────┴────────┴──────┴──────┴──────────┘
데이터 기본 정보:
Rows: 244
Columns: 7
$ total_bill <f64> 16.99, 10.34, 21.01, 23.68, 24.59, 25.29, 8.77, 26.88, 15.04, 14.78
$ tip        <f64> 1.01, 1.66, 3.5, 3.31, 3.61, 4.71, 2.0, 3.12, 1.96, 3.23
$ sex        <cat> Female, Male, Male, Male, Female, Male, Male, Male, Male, Male
$ smoker     <cat> No, No, No, No, No, No, No, No, No, No
$ day        <cat> Sun, Sun, Sun, Sun, Sun, Sun, Sun, Sun, Sun, Sun
$ time       <cat> Dinner, Dinner, Dinner, Dinner, Dinner, Dinner, Dinner, Dinner, Dinner, Dinner
$ size       <i64> 2, 3, 3, 2, 4, 4, 2, 4, 2, 2

None
shape: (9, 8)
┌────────────┬────────────┬──────────┬──────┬────────┬──────┬──────┬──────────┐
│ statistic  ┆ total_bill ┆ tip      ┆ sex  ┆ smoker ┆ day  ┆ time ┆ size     │
│ ---        ┆ ---        ┆ ---      ┆ ---  ┆ ---    ┆ ---  ┆ ---  ┆ ---      │
│ str        ┆ f64        ┆ f64      ┆ str  ┆ str    ┆ str  ┆ str  ┆ f64      │
╞════════════╪════════════╪══════════╪══════╪════════╪══════╪══════╪══════════╡
│ count      ┆ 244.0      ┆ 244.0    ┆ 244  ┆ 244    ┆ 244  ┆ 244  ┆ 244.0    │
│ null_count ┆ 0.0        ┆ 0.0      ┆ 0    ┆ 0      ┆ 0    ┆ 0    ┆ 0.0      │
│ mean       ┆ 19.785943  ┆ 2.998279 ┆ null ┆ null   ┆ null ┆ null ┆ 2.569672 │
│ std        ┆ 8.902412   ┆ 1.383638 ┆ null ┆ null   ┆ null ┆ null ┆ 0.9511   │
│ min        ┆ 3.07       ┆ 1.0      ┆ null ┆ null   ┆ null ┆ null ┆ 1.0      │
│ 25%        ┆ 13.37      ┆ 2.0      ┆ null ┆ null   ┆ null ┆ null ┆ 2.0      │
│ 50%        ┆ 17.81      ┆ 2.92     ┆ null ┆ null   ┆ null ┆ null ┆ 2.0      │
│ 75%        ┆ 24.08      ┆ 3.55     ┆ null ┆ null   ┆ null ┆ null ┆ 3.0      │
│ max        ┆ 50.81      ┆ 10.0     ┆ null ┆ null   ┆ null ┆ null ┆ 6.0      │
└────────────┴────────────┴──────────┴──────┴────────┴──────┴──────┴──────────┘
print(tips_df.shape)
print(tips_df.shape)
(244, 7)
(244, 7)

3 데이터 전처리

3.1 결측값 확인
print("결측치 개수:")
print(tips_df.null_count())
print("결측치 개수:")
print(tips_df.null_count())
결측치 개수:
shape: (1, 7)
┌────────────┬─────┬─────┬────────┬─────┬──────┬──────┐
│ total_bill ┆ tip ┆ sex ┆ smoker ┆ day ┆ time ┆ size │
│ ---        ┆ --- ┆ --- ┆ ---    ┆ --- ┆ ---  ┆ ---  │
│ u32        ┆ u32 ┆ u32 ┆ u32    ┆ u32 ┆ u32  ┆ u32  │
╞════════════╪═════╪═════╪════════╪═════╪══════╪══════╡
│ 0          ┆ 0   ┆ 0   ┆ 0      ┆ 0   ┆ 0    ┆ 0    │
└────────────┴─────┴─────┴────────┴─────┴──────┴──────┘
결측치 개수:
shape: (1, 7)
┌────────────┬─────┬─────┬────────┬─────┬──────┬──────┐
│ total_bill ┆ tip ┆ sex ┆ smoker ┆ day ┆ time ┆ size │
│ ---        ┆ --- ┆ --- ┆ ---    ┆ --- ┆ ---  ┆ ---  │
│ u32        ┆ u32 ┆ u32 ┆ u32    ┆ u32 ┆ u32  ┆ u32  │
╞════════════╪═════╪═════╪════════╪═════╪══════╪══════╡
│ 0          ┆ 0   ┆ 0   ┆ 0      ┆ 0   ┆ 0    ┆ 0    │
└────────────┴─────┴─────┴────────┴─────┴──────┴──────┘

4. 요일별 팁 분석

day_analysis = (
    tips_df.group_by('day')
    .agg([
        pl.col('tip').mean().alias('평균_팁'),
        pl.col('tip').sum().alias('총_팁'),
        pl.col('total_bill').mean().alias('평균_계산서'),
        pl.count().alias('방문_건수')
    ])
    .sort('평균_팁', descending=True)
)
print("요일별 팁 분석:")
print(day_analysis)
day_analysis = (
    tips_df.group_by('day')
    .agg([
        pl.col('tip').mean().alias('평균_팁'),
        pl.col('tip').sum().alias('총_팁'),
        pl.col('total_bill').mean().alias('평균_계산서'),
        pl.count().alias('방문_건수')
    ])
    .sort('평균_팁', descending=True)
)
print("요일별 팁 분석:")
print(day_analysis)
요일별 팁 분석:
shape: (4, 5)
┌──────┬──────────┬────────┬─────────────┬───────────┐
│ day  ┆ 평균_팁  ┆ 총_팁  ┆ 평균_계산서 ┆ 방문_건수 │
│ ---  ┆ ---      ┆ ---    ┆ ---         ┆ ---       │
│ cat  ┆ f64      ┆ f64    ┆ f64         ┆ u32       │
╞══════╪══════════╪════════╪═════════════╪═══════════╡
│ Sun  ┆ 3.255132 ┆ 247.39 ┆ 21.41       ┆ 76        │
│ Sat  ┆ 2.993103 ┆ 260.4  ┆ 20.441379   ┆ 87        │
│ Thur ┆ 2.771452 ┆ 171.83 ┆ 17.682742   ┆ 62        │
│ Fri  ┆ 2.734737 ┆ 51.96  ┆ 17.151579   ┆ 19        │
└──────┴──────────┴────────┴─────────────┴───────────┘
요일별 팁 분석:
shape: (4, 5)
┌──────┬──────────┬────────┬─────────────┬───────────┐
│ day  ┆ 평균_팁  ┆ 총_팁  ┆ 평균_계산서 ┆ 방문_건수 │
│ ---  ┆ ---      ┆ ---    ┆ ---         ┆ ---       │
│ cat  ┆ f64      ┆ f64    ┆ f64         ┆ u32       │
╞══════╪══════════╪════════╪═════════════╪═══════════╡
│ Sun  ┆ 3.255132 ┆ 247.39 ┆ 21.41       ┆ 76        │
│ Sat  ┆ 2.993103 ┆ 260.4  ┆ 20.441379   ┆ 87        │
│ Thur ┆ 2.771452 ┆ 171.83 ┆ 17.682742   ┆ 62        │
│ Fri  ┆ 2.734737 ┆ 51.96  ┆ 17.151579   ┆ 19        │
└──────┴──────────┴────────┴─────────────┴───────────┘
# 그래프 크기 설정
plt.figure(figsize=(12, 6))
 
# 막대 그래프와 선 그래프를 결합하여 표시
ax1 = plt.gca()
ax2 = ax1.twinx()
 
# 막대 그래프: 방문 건수와 총 팁
x = range(len(day_analysis))
width = 0.35
 
ax1.bar([i-width/2 for i in x], day_analysis['방문_건수'],
       width, color='lightblue', label='방문 건수')
ax2.bar([i+width/2 for i in x], day_analysis['총_팁'],
       width, color='lightgreen', label='총 팁($)')
 
# 평균 팁 선 그래프
ax1.plot(x, day_analysis['평균_팁'], 'ro-', linewidth=2, label='평균 팁($)')
# 평균 계산서 선 그래프
ax1.plot(x, day_analysis['평균_계산서'], 'mo-', linewidth=2, label='평균 계산서($)')
 
# 그래프 꾸미기
plt.title('요일별 팁 분석', pad=15, size=15)
ax1.set_xlabel('요일', size=12)
ax1.set_ylabel('방문 건수 / 금액($)', size=12)
 
# x축 레이블 설정
plt.xticks(x, day_analysis['day'])
 
# 데이터 레이블 표시
for i in x:
   # 방문 건수
   ax1.text(i-width/2, day_analysis['방문_건수'][i],
            f"{day_analysis['방문_건수'][i]}건",
            ha='center', va='bottom')
   # 총 팁
   ax2.text(i+width/2, day_analysis['총_팁'][i],
            f"${day_analysis['총_팁'][i]:.1f}",
            ha='center', va='bottom')
   # 평균 팁
   ax1.text(i, day_analysis['평균_팁'][i],
            f"${day_analysis['평균_팁'][i]:.2f}",
            ha='right', va='bottom')
   # 평균 계산서
   ax1.text(i, day_analysis['평균_계산서'][i],
            f"${day_analysis['평균_계산서'][i]:.2f}",
            ha='left', va='bottom')
 
# 범례 표시
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper right')
 
plt.tight_layout()
plt.show()
# 그래프 크기 설정
plt.figure(figsize=(12, 6))
 
# 막대 그래프와 선 그래프를 결합하여 표시
ax1 = plt.gca()
ax2 = ax1.twinx()
 
# 막대 그래프: 방문 건수와 총 팁
x = range(len(day_analysis))
width = 0.35
 
ax1.bar([i-width/2 for i in x], day_analysis['방문_건수'],
       width, color='lightblue', label='방문 건수')
ax2.bar([i+width/2 for i in x], day_analysis['총_팁'],
       width, color='lightgreen', label='총 팁($)')
 
# 평균 팁 선 그래프
ax1.plot(x, day_analysis['평균_팁'], 'ro-', linewidth=2, label='평균 팁($)')
# 평균 계산서 선 그래프
ax1.plot(x, day_analysis['평균_계산서'], 'mo-', linewidth=2, label='평균 계산서($)')
 
# 그래프 꾸미기
plt.title('요일별 팁 분석', pad=15, size=15)
ax1.set_xlabel('요일', size=12)
ax1.set_ylabel('방문 건수 / 금액($)', size=12)
 
# x축 레이블 설정
plt.xticks(x, day_analysis['day'])
 
# 데이터 레이블 표시
for i in x:
   # 방문 건수
   ax1.text(i-width/2, day_analysis['방문_건수'][i],
            f"{day_analysis['방문_건수'][i]}건",
            ha='center', va='bottom')
   # 총 팁
   ax2.text(i+width/2, day_analysis['총_팁'][i],
            f"${day_analysis['총_팁'][i]:.1f}",
            ha='center', va='bottom')
   # 평균 팁
   ax1.text(i, day_analysis['평균_팁'][i],
            f"${day_analysis['평균_팁'][i]:.2f}",
            ha='right', va='bottom')
   # 평균 계산서
   ax1.text(i, day_analysis['평균_계산서'][i],
            f"${day_analysis['평균_계산서'][i]:.2f}",
            ha='left', va='bottom')
 
# 범례 표시
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper right')
 
plt.tight_layout()
plt.show()

5. 시간대별 분석

time_analysis = (
    tips_df.group_by(['time', 'day'])
    .agg([
        pl.col('tip').mean().alias('평균_팁'),
        pl.col('total_bill').mean().alias('평균_계산서'),
        pl.col('size').mean().alias('평균_인원'),
        pl.count().alias('방문_건수')
    ])
    .sort(['time', 'day'])
)
print("시간대별 분석:")
print(time_analysis)
time_analysis = (
    tips_df.group_by(['time', 'day'])
    .agg([
        pl.col('tip').mean().alias('평균_팁'),
        pl.col('total_bill').mean().alias('평균_계산서'),
        pl.col('size').mean().alias('평균_인원'),
        pl.count().alias('방문_건수')
    ])
    .sort(['time', 'day'])
)
print("시간대별 분석:")
print(time_analysis)
시간대별 분석:
shape: (6, 6)
┌────────┬──────┬──────────┬─────────────┬───────────┬───────────┐
│ time   ┆ day  ┆ 평균_팁  ┆ 평균_계산서 ┆ 평균_인원 ┆ 방문_건수 │
│ ---    ┆ ---  ┆ ---      ┆ ---         ┆ ---       ┆ ---       │
│ cat    ┆ cat  ┆ f64      ┆ f64         ┆ f64       ┆ u32       │
╞════════╪══════╪══════════╪═════════════╪═══════════╪═══════════╡
│ Lunch  ┆ Thur ┆ 2.767705 ┆ 17.664754   ┆ 2.459016  ┆ 61        │
│ Lunch  ┆ Fri  ┆ 2.382857 ┆ 12.845714   ┆ 2.0       ┆ 7         │
│ Dinner ┆ Thur ┆ 3.0      ┆ 18.78       ┆ 2.0       ┆ 1         │
│ Dinner ┆ Fri  ┆ 2.94     ┆ 19.663333   ┆ 2.166667  ┆ 12        │
│ Dinner ┆ Sat  ┆ 2.993103 ┆ 20.441379   ┆ 2.517241  ┆ 87        │
│ Dinner ┆ Sun  ┆ 3.255132 ┆ 21.41       ┆ 2.842105  ┆ 76        │
└────────┴──────┴──────────┴─────────────┴───────────┴───────────┘
시간대별 분석:
shape: (6, 6)
┌────────┬──────┬──────────┬─────────────┬───────────┬───────────┐
│ time   ┆ day  ┆ 평균_팁  ┆ 평균_계산서 ┆ 평균_인원 ┆ 방문_건수 │
│ ---    ┆ ---  ┆ ---      ┆ ---         ┆ ---       ┆ ---       │
│ cat    ┆ cat  ┆ f64      ┆ f64         ┆ f64       ┆ u32       │
╞════════╪══════╪══════════╪═════════════╪═══════════╪═══════════╡
│ Lunch  ┆ Thur ┆ 2.767705 ┆ 17.664754   ┆ 2.459016  ┆ 61        │
│ Lunch  ┆ Fri  ┆ 2.382857 ┆ 12.845714   ┆ 2.0       ┆ 7         │
│ Dinner ┆ Thur ┆ 3.0      ┆ 18.78       ┆ 2.0       ┆ 1         │
│ Dinner ┆ Fri  ┆ 2.94     ┆ 19.663333   ┆ 2.166667  ┆ 12        │
│ Dinner ┆ Sat  ┆ 2.993103 ┆ 20.441379   ┆ 2.517241  ┆ 87        │
│ Dinner ┆ Sun  ┆ 3.255132 ┆ 21.41       ┆ 2.842105  ┆ 76        │
└────────┴──────┴──────────┴─────────────┴───────────┴───────────┘
import numpy as np
 
# 그래프 크기 설정
plt.figure(figsize=(15, 6))
 
# 서브플롯 생성
plt.subplot(1, 2, 1)
 
# 데이터를 numpy 배열로 변환
visit_counts = time_analysis['방문_건수'].to_numpy()
avg_bills = time_analysis['평균_계산서'].to_numpy()
avg_tips = time_analysis['평균_팁'].to_numpy()
avg_people = time_analysis['평균_인원'].to_numpy()
 
# 첫 번째 그래프: 시간대별 방문 건수와 평균 계산서
width = 0.35
x = np.arange(len(time_analysis))
 
# 막대 그래프 생성
plt.bar(x - width/2, visit_counts, width, label='방문 건수', color='lightblue')
plt.bar(x + width/2, avg_bills, width, label='평균 계산서($)', color='lightgreen')
 
# 그래프 꾸미기
plt.title('시간대별 방문 건수와 평균 계산서', pad=15)
plt.xlabel('시간대/요일')
labels = [f"{row[0]}\n{row[1]}" for row in time_analysis.iter_rows()]
plt.xticks(x, labels, rotation=45)
plt.legend()
 
# 데이터 레이블 추가
for i in range(len(x)):
    plt.text(i - width/2, visit_counts[i],
             f"{visit_counts[i]}건",
             ha='center', va='bottom')
    plt.text(i + width/2, avg_bills[i],
             f"${avg_bills[i]:.1f}",
             ha='center', va='bottom')
 
# 두 번째 그래프: 시간대별 평균 팁과 평균 인원
plt.subplot(1, 2, 2)
 
# 막대 그래프와 선 그래프 결합
ax = plt.gca()
ax2 = ax.twinx()
 
# 막대 그래프: 평균 팁
bars = ax.bar(x, avg_tips, width, label='평균 팁($)', color='salmon')
 
# 선 그래프: 평균 인원
line = ax2.plot(x, avg_people, 'bo-', label='평균 인원', linewidth=2)
 
# 그래프 꾸미기
plt.title('시간대별 평균 팁과 평균 인원', pad=15)
ax.set_xlabel('시간대/요일')
ax.set_ylabel('평균 팁($)')
ax2.set_ylabel('평균 인원(명)')
plt.xticks(x, labels, rotation=45)
 
# 데이터 레이블 추가
for i in range(len(x)):
    ax.text(i, avg_tips[i],
            f"${avg_tips[i]:.2f}",
            ha='center', va='bottom')
    ax2.text(i, avg_people[i],
             f"{avg_people[i]:.1f}명",
             ha='center', va='bottom', color='blue')
 
# 범례 통합
lines1, labels1 = ax.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax.legend(lines1 + lines2, labels1 + labels2, loc='upper right')
 
plt.tight_layout()
plt.show()
import numpy as np
 
# 그래프 크기 설정
plt.figure(figsize=(15, 6))
 
# 서브플롯 생성
plt.subplot(1, 2, 1)
 
# 데이터를 numpy 배열로 변환
visit_counts = time_analysis['방문_건수'].to_numpy()
avg_bills = time_analysis['평균_계산서'].to_numpy()
avg_tips = time_analysis['평균_팁'].to_numpy()
avg_people = time_analysis['평균_인원'].to_numpy()
 
# 첫 번째 그래프: 시간대별 방문 건수와 평균 계산서
width = 0.35
x = np.arange(len(time_analysis))
 
# 막대 그래프 생성
plt.bar(x - width/2, visit_counts, width, label='방문 건수', color='lightblue')
plt.bar(x + width/2, avg_bills, width, label='평균 계산서($)', color='lightgreen')
 
# 그래프 꾸미기
plt.title('시간대별 방문 건수와 평균 계산서', pad=15)
plt.xlabel('시간대/요일')
labels = [f"{row[0]}\n{row[1]}" for row in time_analysis.iter_rows()]
plt.xticks(x, labels, rotation=45)
plt.legend()
 
# 데이터 레이블 추가
for i in range(len(x)):
    plt.text(i - width/2, visit_counts[i],
             f"{visit_counts[i]}건",
             ha='center', va='bottom')
    plt.text(i + width/2, avg_bills[i],
             f"${avg_bills[i]:.1f}",
             ha='center', va='bottom')
 
# 두 번째 그래프: 시간대별 평균 팁과 평균 인원
plt.subplot(1, 2, 2)
 
# 막대 그래프와 선 그래프 결합
ax = plt.gca()
ax2 = ax.twinx()
 
# 막대 그래프: 평균 팁
bars = ax.bar(x, avg_tips, width, label='평균 팁($)', color='salmon')
 
# 선 그래프: 평균 인원
line = ax2.plot(x, avg_people, 'bo-', label='평균 인원', linewidth=2)
 
# 그래프 꾸미기
plt.title('시간대별 평균 팁과 평균 인원', pad=15)
ax.set_xlabel('시간대/요일')
ax.set_ylabel('평균 팁($)')
ax2.set_ylabel('평균 인원(명)')
plt.xticks(x, labels, rotation=45)
 
# 데이터 레이블 추가
for i in range(len(x)):
    ax.text(i, avg_tips[i],
            f"${avg_tips[i]:.2f}",
            ha='center', va='bottom')
    ax2.text(i, avg_people[i],
             f"{avg_people[i]:.1f}명",
             ha='center', va='bottom', color='blue')
 
# 범례 통합
lines1, labels1 = ax.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax.legend(lines1 + lines2, labels1 + labels2, loc='upper right')
 
plt.tight_layout()
plt.show()

6. 팁 비율 계산 및 분석

tips_with_pct = (
    tips_df.with_columns([
        (pl.col('tip') / pl.col('total_bill') * 100).alias('tip_percentage')
    ])
)
 
tip_pct_analysis = (
    tips_with_pct.group_by(['sex', 'smoker'])
    .agg([
        pl.col('tip_percentage').mean().alias('평균_팁_비율'),
        pl.col('tip').mean().alias('평균_팁'),
        pl.count().alias('방문_건수')
    ])
    .sort('평균_팁_비율', descending=True)
)
print("성별/흡연여부별 팁 비율 분석:")
print(tip_pct_analysis)
tips_with_pct = (
    tips_df.with_columns([
        (pl.col('tip') / pl.col('total_bill') * 100).alias('tip_percentage')
    ])
)
 
tip_pct_analysis = (
    tips_with_pct.group_by(['sex', 'smoker'])
    .agg([
        pl.col('tip_percentage').mean().alias('평균_팁_비율'),
        pl.col('tip').mean().alias('평균_팁'),
        pl.count().alias('방문_건수')
    ])
    .sort('평균_팁_비율', descending=True)
)
print("성별/흡연여부별 팁 비율 분석:")
print(tip_pct_analysis)
성별/흡연여부별 팁 비율 분석:
shape: (4, 5)
┌────────┬────────┬──────────────┬──────────┬───────────┐
│ sex    ┆ smoker ┆ 평균_팁_비율 ┆ 평균_팁  ┆ 방문_건수 │
│ ---    ┆ ---    ┆ ---          ┆ ---      ┆ ---       │
│ cat    ┆ cat    ┆ f64          ┆ f64      ┆ u32       │
╞════════╪════════╪══════════════╪══════════╪═══════════╡
│ Female ┆ Yes    ┆ 18.215035    ┆ 2.931515 ┆ 33        │
│ Male   ┆ No     ┆ 16.066872    ┆ 3.113402 ┆ 97        │
│ Female ┆ No     ┆ 15.692097    ┆ 2.773519 ┆ 54        │
│ Male   ┆ Yes    ┆ 15.277118    ┆ 3.051167 ┆ 60        │
└────────┴────────┴──────────────┴──────────┴───────────┘
성별/흡연여부별 팁 비율 분석:
shape: (4, 5)
┌────────┬────────┬──────────────┬──────────┬───────────┐
│ sex    ┆ smoker ┆ 평균_팁_비율 ┆ 평균_팁  ┆ 방문_건수 │
│ ---    ┆ ---    ┆ ---          ┆ ---      ┆ ---       │
│ cat    ┆ cat    ┆ f64          ┆ f64      ┆ u32       │
╞════════╪════════╪══════════════╪══════════╪═══════════╡
│ Female ┆ Yes    ┆ 18.215035    ┆ 2.931515 ┆ 33        │
│ Male   ┆ No     ┆ 16.066872    ┆ 3.113402 ┆ 97        │
│ Female ┆ No     ┆ 15.692097    ┆ 2.773519 ┆ 54        │
│ Male   ┆ Yes    ┆ 15.277118    ┆ 3.051167 ┆ 60        │
└────────┴────────┴──────────────┴──────────┴───────────┘
# 그래프 크기 설정
plt.figure(figsize=(12, 6))
 
# 데이터 준비
x = np.arange(len(tip_pct_analysis))
width = 0.35
 
# 막대 그래프와 선 그래프를 결합하여 표시
ax1 = plt.gca()
ax2 = ax1.twinx()
 
# 막대 그래프: 방문 건수
bars1 = ax1.bar(x - width/2, tip_pct_analysis['방문_건수'].to_numpy(),
               width, label='방문 건수', color='lightblue')
 
# 막대 그래프: 평균 팁
bars2 = ax1.bar(x + width/2, tip_pct_analysis['평균_팁'].to_numpy(),
               width, label='평균 팁($)', color='lightgreen')
 
# 선 그래프: 평균 팁 비율
line = ax2.plot(x, tip_pct_analysis['평균_팁_비율'].to_numpy(),
               'ro-', linewidth=2, label='평균 팁 비율(%)')
 
# 그래프 꾸미기
plt.title('성별/흡연여부별 팁 분석', pad=15, size=15)
ax1.set_xlabel('성별/흡연여부', size=12)
ax1.set_ylabel('방문 건수 / 평균 팁($)', size=12)
ax2.set_ylabel('평균 팁 비율(%)', size=12)
 
# x축 레이블 설정
labels = [f"{row[0]}\n{row[1]}" for row in tip_pct_analysis.iter_rows()]
plt.xticks(x, labels)
 
# 데이터 레이블 표시
for i in range(len(x)):
   # 방문 건수
   ax1.text(i - width/2, tip_pct_analysis['방문_건수'].to_numpy()[i],
            f"{tip_pct_analysis['방문_건수'].to_numpy()[i]}건",
            ha='center', va='bottom')
   # 평균 팁
   ax1.text(i + width/2, tip_pct_analysis['평균_팁'].to_numpy()[i],
            f"${tip_pct_analysis['평균_팁'].to_numpy()[i]:.2f}",
            ha='center', va='bottom')
   # 평균 팁 비율
   ax2.text(i, tip_pct_analysis['평균_팁_비율'].to_numpy()[i],
            f"{tip_pct_analysis['평균_팁_비율'].to_numpy()[i]:.1f}%",
            ha='center', va='bottom')
 
# 범례 통합
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper right')
 
plt.tight_layout()
plt.show()
# 그래프 크기 설정
plt.figure(figsize=(12, 6))
 
# 데이터 준비
x = np.arange(len(tip_pct_analysis))
width = 0.35
 
# 막대 그래프와 선 그래프를 결합하여 표시
ax1 = plt.gca()
ax2 = ax1.twinx()
 
# 막대 그래프: 방문 건수
bars1 = ax1.bar(x - width/2, tip_pct_analysis['방문_건수'].to_numpy(),
               width, label='방문 건수', color='lightblue')
 
# 막대 그래프: 평균 팁
bars2 = ax1.bar(x + width/2, tip_pct_analysis['평균_팁'].to_numpy(),
               width, label='평균 팁($)', color='lightgreen')
 
# 선 그래프: 평균 팁 비율
line = ax2.plot(x, tip_pct_analysis['평균_팁_비율'].to_numpy(),
               'ro-', linewidth=2, label='평균 팁 비율(%)')
 
# 그래프 꾸미기
plt.title('성별/흡연여부별 팁 분석', pad=15, size=15)
ax1.set_xlabel('성별/흡연여부', size=12)
ax1.set_ylabel('방문 건수 / 평균 팁($)', size=12)
ax2.set_ylabel('평균 팁 비율(%)', size=12)
 
# x축 레이블 설정
labels = [f"{row[0]}\n{row[1]}" for row in tip_pct_analysis.iter_rows()]
plt.xticks(x, labels)
 
# 데이터 레이블 표시
for i in range(len(x)):
   # 방문 건수
   ax1.text(i - width/2, tip_pct_analysis['방문_건수'].to_numpy()[i],
            f"{tip_pct_analysis['방문_건수'].to_numpy()[i]}건",
            ha='center', va='bottom')
   # 평균 팁
   ax1.text(i + width/2, tip_pct_analysis['평균_팁'].to_numpy()[i],
            f"${tip_pct_analysis['평균_팁'].to_numpy()[i]:.2f}",
            ha='center', va='bottom')
   # 평균 팁 비율
   ax2.text(i, tip_pct_analysis['평균_팁_비율'].to_numpy()[i],
            f"{tip_pct_analysis['평균_팁_비율'].to_numpy()[i]:.1f}%",
            ha='center', va='bottom')
 
# 범례 통합
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper right')
 
plt.tight_layout()
plt.show()

7. 그룹 크기별 분석

size_analysis = (
    tips_df.group_by('size')
    .agg([
        pl.col('tip').mean().alias('평균_팁'),
        pl.col('total_bill').mean().alias('평균_계산서'),
        pl.col('tip').sum().alias('총_팁'),
        pl.count().alias('방문_건수')
    ])
    .sort('size')
)
print("그룹 크기별 분석:")
print(size_analysis)
size_analysis = (
    tips_df.group_by('size')
    .agg([
        pl.col('tip').mean().alias('평균_팁'),
        pl.col('total_bill').mean().alias('평균_계산서'),
        pl.col('tip').sum().alias('총_팁'),
        pl.count().alias('방문_건수')
    ])
    .sort('size')
)
print("그룹 크기별 분석:")
print(size_analysis)
그룹 크기별 분석:
shape: (6, 5)
┌──────┬──────────┬─────────────┬────────┬───────────┐
│ size ┆ 평균_팁  ┆ 평균_계산서 ┆ 총_팁  ┆ 방문_건수 │
│ ---  ┆ ---      ┆ ---         ┆ ---    ┆ ---       │
│ i64  ┆ f64      ┆ f64         ┆ f64    ┆ u32       │
╞══════╪══════════╪═════════════╪════════╪═══════════╡
│ 1    ┆ 1.4375   ┆ 7.2425      ┆ 5.75   ┆ 4         │
│ 2    ┆ 2.582308 ┆ 16.448013   ┆ 402.84 ┆ 156       │
│ 3    ┆ 3.393158 ┆ 23.277632   ┆ 128.94 ┆ 38        │
│ 4    ┆ 4.135405 ┆ 28.613514   ┆ 153.01 ┆ 37        │
│ 5    ┆ 4.028    ┆ 30.068      ┆ 20.14  ┆ 5         │
│ 6    ┆ 5.225    ┆ 34.83       ┆ 20.9   ┆ 4         │
└──────┴──────────┴─────────────┴────────┴───────────┘
그룹 크기별 분석:
shape: (6, 5)
┌──────┬──────────┬─────────────┬────────┬───────────┐
│ size ┆ 평균_팁  ┆ 평균_계산서 ┆ 총_팁  ┆ 방문_건수 │
│ ---  ┆ ---      ┆ ---         ┆ ---    ┆ ---       │
│ i64  ┆ f64      ┆ f64         ┆ f64    ┆ u32       │
╞══════╪══════════╪═════════════╪════════╪═══════════╡
│ 1    ┆ 1.4375   ┆ 7.2425      ┆ 5.75   ┆ 4         │
│ 2    ┆ 2.582308 ┆ 16.448013   ┆ 402.84 ┆ 156       │
│ 3    ┆ 3.393158 ┆ 23.277632   ┆ 128.94 ┆ 38        │
│ 4    ┆ 4.135405 ┆ 28.613514   ┆ 153.01 ┆ 37        │
│ 5    ┆ 4.028    ┆ 30.068      ┆ 20.14  ┆ 5         │
│ 6    ┆ 5.225    ┆ 34.83       ┆ 20.9   ┆ 4         │
└──────┴──────────┴─────────────┴────────┴───────────┘
# 그래프 크기 설정
plt.figure(figsize=(12, 6))
 
# 막대 그래프와 선 그래프를 결합하여 표시
ax1 = plt.gca()
ax2 = ax1.twinx()
 
# 데이터 준비
x = np.arange(len(size_analysis))
width = 0.35
 
# 막대 그래프: 방문 건수
bars1 = ax1.bar(x - width/2, size_analysis['방문_건수'].to_numpy(),
               width, label='방문 건수', color='lightblue')
 
# 막대 그래프: 평균 계산서
bars2 = ax2.bar(x + width/2, size_analysis['평균_계산서'].to_numpy(),
               width, label='평균 계산서($)', color='lightgreen')
 
# 선 그래프: 평균 팁
line = ax2.plot(x, size_analysis['평균_팁'].to_numpy(),
               'ro-', linewidth=2, label='평균 팁($)')
 
# 그래프 꾸미기
plt.title('그룹 크기별 분석', pad=15, size=15)
ax1.set_xlabel('그룹 크기(명)', size=12)
ax1.set_ylabel('방문 건수', size=12)
ax2.set_ylabel('금액($)', size=12)
 
# x축 레이블 설정
plt.xticks(x, size_analysis['size'].to_numpy())
 
# 데이터 레이블 표시
for i in range(len(x)):
   # 방문 건수
   ax1.text(i - width/2, size_analysis['방문_건수'].to_numpy()[i],
            f"{size_analysis['방문_건수'].to_numpy()[i]}건",
            ha='center', va='bottom')
   # 평균 계산서
   ax2.text(i + width/2, size_analysis['평균_계산서'].to_numpy()[i],
            f"${size_analysis['평균_계산서'].to_numpy()[i]:.1f}",
            ha='center', va='bottom')
   # 평균 팁
   ax2.text(i, size_analysis['평균_팁'].to_numpy()[i],
            f"${size_analysis['평균_팁'].to_numpy()[i]:.2f}",
            ha='center', va='bottom', color='red')
 
# 범례 통합
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')
 
plt.tight_layout()
plt.show()
# 그래프 크기 설정
plt.figure(figsize=(12, 6))
 
# 막대 그래프와 선 그래프를 결합하여 표시
ax1 = plt.gca()
ax2 = ax1.twinx()
 
# 데이터 준비
x = np.arange(len(size_analysis))
width = 0.35
 
# 막대 그래프: 방문 건수
bars1 = ax1.bar(x - width/2, size_analysis['방문_건수'].to_numpy(),
               width, label='방문 건수', color='lightblue')
 
# 막대 그래프: 평균 계산서
bars2 = ax2.bar(x + width/2, size_analysis['평균_계산서'].to_numpy(),
               width, label='평균 계산서($)', color='lightgreen')
 
# 선 그래프: 평균 팁
line = ax2.plot(x, size_analysis['평균_팁'].to_numpy(),
               'ro-', linewidth=2, label='평균 팁($)')
 
# 그래프 꾸미기
plt.title('그룹 크기별 분석', pad=15, size=15)
ax1.set_xlabel('그룹 크기(명)', size=12)
ax1.set_ylabel('방문 건수', size=12)
ax2.set_ylabel('금액($)', size=12)
 
# x축 레이블 설정
plt.xticks(x, size_analysis['size'].to_numpy())
 
# 데이터 레이블 표시
for i in range(len(x)):
   # 방문 건수
   ax1.text(i - width/2, size_analysis['방문_건수'].to_numpy()[i],
            f"{size_analysis['방문_건수'].to_numpy()[i]}건",
            ha='center', va='bottom')
   # 평균 계산서
   ax2.text(i + width/2, size_analysis['평균_계산서'].to_numpy()[i],
            f"${size_analysis['평균_계산서'].to_numpy()[i]:.1f}",
            ha='center', va='bottom')
   # 평균 팁
   ax2.text(i, size_analysis['평균_팁'].to_numpy()[i],
            f"${size_analysis['평균_팁'].to_numpy()[i]:.2f}",
            ha='center', va='bottom', color='red')
 
# 범례 통합
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')
 
plt.tight_layout()
plt.show()

8. 상관관계 분석

correlations = tips_df.select([
    pl.corr('total_bill', 'tip').alias('계산서_팁_상관계수'),
    pl.corr('size', 'tip').alias('인원_팁_상관계수'),
    pl.corr('size', 'total_bill').alias('인원_계산서_상관계수')
])
print("변수간 상관관계:")
print(correlations)
correlations = tips_df.select([
    pl.corr('total_bill', 'tip').alias('계산서_팁_상관계수'),
    pl.corr('size', 'tip').alias('인원_팁_상관계수'),
    pl.corr('size', 'total_bill').alias('인원_계산서_상관계수')
])
print("변수간 상관관계:")
print(correlations)
변수간 상관관계:
shape: (1, 3)
┌────────────────────┬──────────────────┬──────────────────────┐
│ 계산서_팁_상관계수 ┆ 인원_팁_상관계수 ┆ 인원_계산서_상관계수 │
│ ---                ┆ ---              ┆ ---                  │
│ f64                ┆ f64              ┆ f64                  │
╞════════════════════╪══════════════════╪══════════════════════╡
│ 0.675734           ┆ 0.489299         ┆ 0.598315             │
└────────────────────┴──────────────────┴──────────────────────┘
변수간 상관관계:
shape: (1, 3)
┌────────────────────┬──────────────────┬──────────────────────┐
│ 계산서_팁_상관계수 ┆ 인원_팁_상관계수 ┆ 인원_계산서_상관계수 │
│ ---                ┆ ---              ┆ ---                  │
│ f64                ┆ f64              ┆ f64                  │
╞════════════════════╪══════════════════╪══════════════════════╡
│ 0.675734           ┆ 0.489299         ┆ 0.598315             │
└────────────────────┴──────────────────┴──────────────────────┘
# 한글 폰트 설정
plt.rc('font', family='NanumGothic')
plt.rcParams['axes.unicode_minus'] = False
 
# 그래프 크기 설정
plt.figure(figsize=(8, 6))
 
# 상관계수 행렬 생성
corr_matrix = np.array([
    [1.0, correlations['계산서_팁_상관계수'][0], correlations['인원_계산서_상관계수'][0]],
    [correlations['계산서_팁_상관계수'][0], 1.0, correlations['인원_팁_상관계수'][0]],
    [correlations['인원_계산서_상관계수'][0], correlations['인원_팁_상관계수'][0], 1.0]
])
 
# 변수 이름
variables = ['계산서', '팁', '인원']
 
# 히트맵 생성
sns.heatmap(corr_matrix,
            annot=True,  # 값 표시
            fmt='.3f',   # 소수점 3자리
            cmap='RdYlBu_r',  # 색상 맵
            xticklabels=variables,
            yticklabels=variables,
            vmin=-1, vmax=1,  # 상관계수 범위
            center=0)  # 중앙값
 
plt.title('변수간 상관관계 히트맵', pad=20)
 
# 레이아웃 조정
plt.tight_layout()
plt.show()
# 한글 폰트 설정
plt.rc('font', family='NanumGothic')
plt.rcParams['axes.unicode_minus'] = False
 
# 그래프 크기 설정
plt.figure(figsize=(8, 6))
 
# 상관계수 행렬 생성
corr_matrix = np.array([
    [1.0, correlations['계산서_팁_상관계수'][0], correlations['인원_계산서_상관계수'][0]],
    [correlations['계산서_팁_상관계수'][0], 1.0, correlations['인원_팁_상관계수'][0]],
    [correlations['인원_계산서_상관계수'][0], correlations['인원_팁_상관계수'][0], 1.0]
])
 
# 변수 이름
variables = ['계산서', '팁', '인원']
 
# 히트맵 생성
sns.heatmap(corr_matrix,
            annot=True,  # 값 표시
            fmt='.3f',   # 소수점 3자리
            cmap='RdYlBu_r',  # 색상 맵
            xticklabels=variables,
            yticklabels=variables,
            vmin=-1, vmax=1,  # 상관계수 범위
            center=0)  # 중앙값
 
plt.title('변수간 상관관계 히트맵', pad=20)
 
# 레이아웃 조정
plt.tight_layout()
plt.show()

9. 요약 통계

summary_stats = {
    '총_방문_건수': tips_df.shape[0],
    '평균_팁': round(tips_df['tip'].mean(),2),
    '중앙값_팁': tips_df['tip'].median(),
    '최대_팁': tips_df['tip'].max(),
    '평균_계산서': round(tips_df['total_bill'].mean(),2),
    '평균_인원': round(tips_df['size'].mean(),2),
    '주말_방문_비율': round((tips_df.filter(pl.col('day').is_in(['Sat', 'Sun'])).shape[0] / tips_df.shape[0] * 100),2)
}
print("전체 요약 통계:")
print(summary_stats)
 
tips_df.with_columns([
    pl.col('total_bill')
    .cut(
        [0, 10, 20, 30, 40],  # 6개 breaks = 5개 구간
        labels=['0', '1-10', '10-20', '20-30', '30-40', '40+']  # 5개 labels
    )
    .alias('bill_range')
])
summary_stats = {
    '총_방문_건수': tips_df.shape[0],
    '평균_팁': round(tips_df['tip'].mean(),2),
    '중앙값_팁': tips_df['tip'].median(),
    '최대_팁': tips_df['tip'].max(),
    '평균_계산서': round(tips_df['total_bill'].mean(),2),
    '평균_인원': round(tips_df['size'].mean(),2),
    '주말_방문_비율': round((tips_df.filter(pl.col('day').is_in(['Sat', 'Sun'])).shape[0] / tips_df.shape[0] * 100),2)
}
print("전체 요약 통계:")
print(summary_stats)
 
tips_df.with_columns([
    pl.col('total_bill')
    .cut(
        [0, 10, 20, 30, 40],  # 6개 breaks = 5개 구간
        labels=['0', '1-10', '10-20', '20-30', '30-40', '40+']  # 5개 labels
    )
    .alias('bill_range')
])
전체 요약 통계:
{'총_방문_건수': 244, '평균_팁': 3.0, '중앙값_팁': 2.9, '최대_팁': 10.0, '평균_계산서': 19.79, '평균_인원': 2.57, '주말_방문_비율': 66.8}
전체 요약 통계:
{'총_방문_건수': 244, '평균_팁': 3.0, '중앙값_팁': 2.9, '최대_팁': 10.0, '평균_계산서': 19.79, '평균_인원': 2.57, '주말_방문_비율': 66.8}
{"packages":["numpy","pandas","matplotlib","lxml"]}
4.2 타이타닉 데이터 분석4.4 Iris 데이터 분석