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)
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}