오늘 배운 내용을 카페 예제 데이터로 문제를 내고 풀어봤다.
답은 노트북에 작성한 풀이를 바탕으로 정리했다.
강남·홍대·종로 지점의 메뉴별 가격, 판매량, 평점을 담은 예제다. 실제 매출 자료는 아니다.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data = {
"지점": ["강남", "강남", "강남", "홍대", "홍대", "홍대",
"종로", "종로", "종로", "종로"],
"메뉴": ["아메리카노", "라떼", "케이크", "아메리카노", "라떼",
"케이크", "아메리카노", "라떼", "케이크", "아메리카노"],
"가격": [4500, 5500, 7000, 4500, 5500, 7000, 4500, 5500, 7000, 4500],
"판매량": [120, 80, 30, 150, 60, 45, 90, 100, 25, 110],
"평점": [4.5, 4.2, 4.8, 4.7, 3.9, 4.6, 4.1, np.nan, 4.9, 4.3]
}
df = pd.DataFrame(data)
문제 — 행·열 개수, 컬럼 이름, 각 컬럼의 자료형을 확인하고 처음 5개 행을 출력하기.
풀이
print(df.shape)
print(list(df.columns))
for column in df.columns:
print(f"{column}: {df[column].dtype}")
print(df.head())
문제 — 메뉴 컬럼을 Series로 가져와 타입을 확인하고, 지점·메뉴·판매량 세 컬럼을 함께 선택하기.
풀이
print(df["메뉴"])
print(type(df["메뉴"]))
print(df[["지점", "메뉴", "판매량"]])
문제 — 판매량이 100 이상인 행을 찾고, 그중 아메리카노만 추출하기.
풀이
print(df[df["판매량"] >= 100])
print(df[
(df["판매량"] >= 100)
& (df["메뉴"] == "아메리카노")
])
문제 — 가격과 판매량으로 매출 컬럼을 만들고, 매출이 가장 높은 행의 지점·메뉴·매출을 출력하기.
풀이
df["매출"] = df["판매량"] * df["가격"]
print(df.loc[df["매출"].idxmax(), ["지점", "메뉴", "매출"]])
문제 — 지점별 총매출, 메뉴별 평균 판매량, 지점별 데이터 개수 구하기.
풀이
df.groupby("지점")[["매출"]].sum()
df.groupby("메뉴")["판매량"].mean()
df.groupby("지점").size()
문제 — 평점에 결측값이 몇 개 있는지 확인하기.
처음 작성한 풀이
df["평점"].isna().sum()
# 1
문제 — 평점이 없으면 평가 없음, 4.5 이상이면 우수, 나머지는 보통으로 분류하기.
풀이
def 평가(a):
if pd.isna(a):
return "평가 없음"
return "우수" if a >= 4.5 else "보통"
df["평가"] = df["평점"].apply(평가)
문제 — std()를 바로 사용하지 않고 판매량의 평균, 편차, 편차 제곱, 분산, 표준편차 구하기.
풀이 — 노트북의 계산식을 변수로 나눠 정리했다.
mean = df["판매량"].mean()
deviation = df["판매량"] - mean
squared_deviation = deviation ** 2
variance = squared_deviation.mean()
standard_deviation = variance ** 0.5
print(mean)
print(deviation)
print(squared_deviation)
print(variance)
print(standard_deviation)
문제 — 지점별 총매출, 판매량 분포, 가격과 판매량을 각각 막대그래프·히스토그램·산점도로 그리기.
풀이
plt.rcParams["font.family"] = "Malgun Gothic"
plt.rcParams["axes.unicode_minus"] = False
branch_sales = df.groupby("지점")["매출"].sum()
fig = plt.figure(figsize=(15, 4))
ax1 = fig.add_subplot(1, 3, 1)
ax1.bar(branch_sales.index, branch_sales.values)
ax1.set_title("지점별 총 매출")
ax1.set_xlabel("지점")
ax1.set_ylabel("매출")
ax2 = fig.add_subplot(1, 3, 2)
ax2.hist(df["판매량"], bins=5)
ax2.set_title("판매량 분포")
ax2.set_xlabel("판매량")
ax2.set_ylabel("빈도")
ax3 = fig.add_subplot(1, 3, 3)
ax3.scatter(df["가격"], df["판매량"])
ax3.set_title("가격과 판매량")
ax3.set_xlabel("가격")
ax3.set_ylabel("판매량")
plt.tight_layout()
plt.show()
문제 — 각 지점에서 매출이 가장 높은 메뉴를 하나씩 찾기.
작성한 풀이
max_i = df.groupby("지점")["매출"].idxmax()
print(df.loc[max_i][["지점", "매출", "메뉴"]])
종로 지점에 아메리카노가 둘으로
문제 의도에 따라 답 변경 필요
메뉴별 합계 기준으로 보완할 답
menu_sales = df.groupby(["지점", "메뉴"])["매출"].sum()
menu_sales = menu_sales.reset_index()
max_i = menu_sales.groupby("지점")["매출"].idxmax()
result = menu_sales.loc[max_i, ["지점", "메뉴", "매출"]]
print(result)
결측값을 세는 문제에서는 무엇을 세는지, 최대 매출을 찾는 문제에서는 한 행과 메뉴별 합계 중 무엇을 비교하는지가 중요했다. 결과가 나오는 데서 끝내지 않고 문제에서 요구한 기준과 맞는지 다시 확인해야겠다.