본문 바로가기
Analysis Project

빵가게 장바구니 데이터 분석(Apriori 알고리즘)

by rubyda 2021. 2. 4.
728x90

데이터 설명

한 빵가게의 장바구니 데이터 입니다. 데이터는 2507개 이며 4개의 컬럼으로 구성되어 있습니다. 각 컬럼별 의미는 다음과 같습니다. 데이터는 캐글 데이터를 사용하였습니다.

 

  • Transaction: 각 주문에 대한 고유한 값입니다.

  • Item: 제품의 종류 즉 제품명을 의미합니다.

  • date_time: 구매날짜와 시간대를 의미합니다.

  • period_day: 구매 시간대를 카테고리 형태로 표현하였습니다('morning', 'afternoon', 'evening', 'night')

  • weekday_weekend: 주문한 날이 평일인지 주말인지를 의미합니다.

분석 방법

✔️ EDA

탐색적 데이터 분석을 통해 빵가게 구매의 특징들을 알아봅니다.

 

✔️ Apriori 알고리즘을 사용한 연관분석 진행

연관분석의 대표적인 알고리즘 중 하나인 Apriori을 사용해서 연관분석을 진행합니다. 분석 결과를 해석하며 어떠한 상품들이 연관지어 많이 판매되는지 알 수 있습니다.

 

분석 진행

[데이터 살펴보기]

data.info()

msno.bar(df=data.iloc[:, :], figsize=(16,8),color=(0.1, 0.6, 0.8))

결측값은 존재하지 않습니다.

 

print('빵가게에서는 총 {}개의 다른 품목들을 판매하고 있습니다.'.format(len(data['Item'].unique())))

print('총 고유값은 {}개로 구성되어 있습니다.'.format(data['Transaction'].nunique()))

[데이터 전처리]

날짜와 시간 데이터를 보면 범위가 크게 잡혀있는것으로 보입니다. 전처리를 통해 좀 더 세부적으로 쪼개도록 하겠습니다.

 

data.date_time

day = []
for dt in data.date_time:
    day_num = datetime.datetime.strptime(dt.split(' ')[0], '%d-%m-%Y').weekday() # 시간을 문자 형태로 출력후 요일은 숫자로 반환
    day.append(calendar.day_name[day_num]) #요일로 변환

먼저 요일을 출력하기 위해 문자형태로 변환 후 숫자로 변환한후에 요일로 변환하여 줍니다. calender.day_name을 사용하면 숫자로된 요일을 글자로 표현하여 줍니다.

 

예시로 출력해보면 다음과 같습니다.

 

# 날짜 시간 상세하게 분리하기
data['date'] = pd.to_datetime(data['date_time']).dt.date
data['time'] = pd.to_datetime(data['date_time']).dt.time
data['day'] = day
data['month'] = pd.to_datetime(data['date_time']).dt.month
data['hour'] = pd.to_datetime(data['date_time']).dt.hour
In [70]:
# 숫자로된 월데이터를 텍스트로 변환
data['month'] = data['month'].replace((1,2,3,4,5,6,7,8,9,10,11,12),  ('January','February','March','April','May','June','July','August',
                                          'September','October','November','December'))

다음 코드를 사용해서 날짜와 시간을 세부적으로 분리하여 줍니다. 월데이터도 마찬가지로 다음과 같이 텍스트 형태로 변화하여 줍니다. 이렇게 텍스트로 변환을 해주는 이유는 나중에 EDA를 할때 시각화하는 과정에서 더욱 쉽게 보게 하기 위해서 입니다.

 

data.drop(['date_time'], axis=1, inplace=True)
data.rename(columns={'weekday_weekend': 'day_type'}, inplace=True)
data.head()

최종적으로 전처리된 데이터는 다음과 같습니다. 

 

[EDA]

Q. 빵가게에서 가장 많이 팔리는 제품들은 무엇일까?

plt.figure(figsize=(14, 7))
sns.barplot(x=data.Item.value_counts().head(20).index, y=data.Item.value_counts().head(20))
plt.xticks(rotation=45)
plt.ylabel('Counts')
plt.title('Top 25 Items', fontsize=15,color='black')
plt.show()

 

예상했던 결과가 나왔습니다. 주로 커피가 가장 많이 팔립니다. 다음으로는 빵, 티, 케이크 등이 있었습니다.

 

Q. 가장 주문량이 많은 월, 요일, 시간대는 언제일까?

 

fig = plt.figure(figsize=(12, 15), constrained_layout=True) # subplot 간격 조절
gs = gridspec.GridSpec(nrows=3, ncols=1, figure=fig)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[2, 0])

sns.barplot(x='month', y='Transaction', data=month_count, ax=ax1)
ax1.set_ylabel('Count')
ax1.set_title('Month', fontsize=20)

sns.barplot(x='day', y='Transaction', data=day_count, ax=ax2)
ax2.set_ylabel('day of the week')
ax2.set_title('Day of the week', fontsize=20)

sns.barplot(x='Transaction', y='hour', data=hour_count,orient='h', ax=ax3)
ax3.set_xlabel('Hour')
ax3.set_title('hour', fontsize=20)
plt.show()

  • 월에서는 1월, 3월, 11월에서 높은 구매율을 보였습니다.

  • 요일에서는 주로 토요일에 구매율이 높았습니다.

  • 시간대에서는 주로 오전, 점심시간에 구매율이 높았습니다.

시간대를 분석을 해보면서 시간대별로 구매한 폼목의 차이가 있는지 궁금증이 생겼습니다. 시간대별로 차이가 있는지 추가적으로 분석을 해봤습니다.

 

Q. 시간대별로 구매하는 제품은 차이가 있을까?

plt.figure(figsize=(16,8))
for i,j in enumerate(period):
    plt.subplot(2,2,i+1)
    df1 = data_period[data_period.period_day==j].head(10)
    sns.barplot(data=df1, y=df1.Item, x=df1.Transaction)
    plt.xlabel('')
    plt.ylabel('')
    plt.title('Top 10 items in "{}"'.format(j), size=13)

plt.show()

아침, 오후, 저녁에는 주로 커피와 빵을 가장 많이 구매한다는 결과가 나왔습니다.

하지만 밤에는 다른 결과가 나왔습니다. 밤에는 커피와 빵보다는 비건 제품을 많이 구매했고, 핫초코도 구매율이 높았습니다.

 

[장바구니 연관 분석]

연관분석 알고리즘 중 하니인 Apriori 사용을 위해서는 다음 패키지 설치가 필요합니다.

 

from mlxtend.frequent_patterns import association_rules, apriori

 

장바구니 분석을 하려면 다음과 같이 하나의 행렬을 만들어야 합니다. 이 행렬은 각 트랜잭션에 항목이 있는지 여부를 나타내는 행렬입니다.

 

 

다음 표를 만드는 과정은 따로 코드를 첨부하지 않았습니다. 밑에 전체코드 링크를 첨부했기 때문에 궁금하신 분들은 전체 코드를 보시면 됩니다.

 

이제 Apriori를 사용할 수 있는 준비가 완료되었습니다.

 

freq_item = apriori(basket, min_support = 0.01,use_colnames = True)
freq_item

apriori는 연관분석에 사용되는 함수입니다. 여기서 최소 지지도 값을 0.01로 설정을 하였습니다.

0.01의 의미는 총 9465건의 거래 중에서 최소한 94건의 거래 해당 항목을 고려했을 때만 해당 항목이 존재해야 한다는 것을 의미합니다.

이제 규칙을 만들도록 하겠습니다.

 

rules = association_rules(freq_item, metric = "lift", min_threshold = 1)
rules.sort_values('confidence', ascending = False, inplace = True)
rules

 

우리는 association_rules 함수를 사용해서 규칙을 생성할 수 있습니다. 규칙이 많기 때문에 일부만 캡처를 하여 첨부하였습니다.

 

신뢰도를 기준으로 정렬을 해봤습니다. 상위권에는 다음과 같은 규칙들이 있었습니다.

  • 토스트 → 커피

  • 스패니쉬 브런치 → 커피

  • 메디아루나 → 커피

  • 페이스트리 → 커피

다음 규칙들은 lift가 1보다 크기 때문에 양의 상관관계가 있다고 할 수 있습니다. 어떻게 보면 커피를 가장 많이 구매하기 때문에 이러한 결과가 당연할수도 있다는 생각이 듭니다.

 

추가적으로 (커피,차) -> 케이크 의 규칙이 lift 값이 가장 높은 결과가 나왔습니다. 이 부분을 해석하자면 커피, 차, 케이크를 모두 함께 구매할 확률이 케이크만 구매하는 확률보다 1.94배 정도 높다고 해석할 수 있습니다.

 

보통 카페에서는 커피 구매량이 상대적으로 높습니다. 그래서 다음과 같은 결과가 어떻게 보면 당연하다는 생각이 듭니다. 그 커피에 관한 확률이 높기 때문에 다른 규칙들이 영향을 받을수 있습니다. 따라서 이러한 경우 상대적으로 높은 값들을 제거하고 분석을 해보면다면 좀 더 흥미로운 인사이트를 발견할 수 있을것이라고 생각됩니다.

 

 

 

이 글에서는 모든 코드가 첨부되어 있지 않습니다. 전체 코드를 보기 원하시는 분은 아래 깃 링크에서 확인하실 수 있습니다. 감사합니당 ㅎㅎ

 

코드 링크

github.com/jaaaamj0711/kaggle_study/blob/master/The%20Bread%20Basket%20Analysis/The_Bread_Basket_Analysis.ipynb

 

jaaaamj0711/kaggle_study

Kaggle data를 공부하는 공간입니다. Contribute to jaaaamj0711/kaggle_study development by creating an account on GitHub.

github.com