티스토리 뷰


Untitled10

지난 블로그: [서울시 먹거리 분석] - 1월 치킨 판매업종 이용 통화량 분석
https://jfun.tistory.com/82

이번에는 지난 블로그에 이어서 1월 치킨 판매 업종 통화량을 여러 각도로 보도록 해보자.

1. Data 확인

먼저 Data에 대한 전반적인 확인을 해보자.

In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
In [2]:
data = pd.read_csv('CALL_CHICKEN_01MONTH.csv')
In [3]:
data.head()
Out[3]:
기준일 요일 성별 연령대 시도 시군구 읍면동 업종 통화건수
0 20190101 20대 서울특별시 강남구 도곡동 치킨 5
1 20190101 30대 서울특별시 강남구 삼성동 치킨 36
2 20190101 10대 서울특별시 강남구 대치동 치킨 5
3 20190101 40대 서울특별시 강남구 대치동 치킨 5
4 20190101 40대 서울특별시 강남구 일원동 치킨 5

모든 날짜가 나타나 있는지 확인하자

In [33]:
d2=data['기준일'].unique()
d2, len(d2)
Out[33]:
(array([20190101, 20190102, 20190103, 20190104, 20190105, 20190106,
        20190107, 20190108, 20190109, 20190110, 20190111, 20190112,
        20190113, 20190114, 20190115, 20190116, 20190117, 20190118,
        20190119, 20190120, 20190121, 20190122, 20190123, 20190124,
        20190125, 20190126, 20190127, 20190128, 20190129, 20190130,
        20190131], dtype=int64), 31)

len(d2)가 31개이므로 빠진 날짜는 없다.

날짜를 숫자열이 아닌 날짜열로 바꿔보자

In [6]:
data.dtypes
Out[6]:
기준일      int64
요일      object
성별      object
연령대     object
시도      object
시군구     object
읍면동     object
업종      object
통화건수     int64
dtype: object
In [7]:
pd.to_datetime(d2,format='%Y%m%d')
Out[7]:
DatetimeIndex(['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04',
               '2019-01-05', '2019-01-06', '2019-01-07', '2019-01-08',
               '2019-01-09', '2019-01-10', '2019-01-11', '2019-01-12',
               '2019-01-13', '2019-01-14', '2019-01-15', '2019-01-16',
               '2019-01-17', '2019-01-18', '2019-01-19', '2019-01-20',
               '2019-01-21', '2019-01-22', '2019-01-23', '2019-01-24',
               '2019-01-25', '2019-01-26', '2019-01-27', '2019-01-28',
               '2019-01-29', '2019-01-30', '2019-01-31'],
              dtype='datetime64[ns]', freq=None)

대부분의 날짜 형식은 datetime을 이용하면 날짜열로 바꿔줄수 있다.
제대로 안되는경우 문자열로 바꿔준 다음 날짜열로 바꿔보던가, 아니면 format을 이용해본다.

In [8]:
d3 = d2.astype('float')

2. 빠진 정보가 없는지 확인해 보자.

null값 판단방법1

In [9]:
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 29850 entries, 0 to 29849
Data columns (total 9 columns):
기준일     29850 non-null int64
요일      29850 non-null object
성별      29850 non-null object
연령대     29850 non-null object
시도      29850 non-null object
시군구     29850 non-null object
읍면동     29850 non-null object
업종      29850 non-null object
통화건수    29850 non-null int64
dtypes: int64(2), object(7)
memory usage: 2.0+ MB
  • RangeIndex: 29850 entries, 0 to 29849
    0부터 29849까지 총 29850개의 데이터가 있음을 의미
  • 모든 데이터가 29850개 이머 non-null이므로 데이터가 빠짐 없이 존재함을 알 수 있다.

null값 판단방법2

In [10]:
d1=data.isnull()
d1.head()
Out[10]:
기준일 요일 성별 연령대 시도 시군구 읍면동 업종 통화건수
0 False False False False False False False False False
1 False False False False False False False False False
2 False False False False False False False False False
3 False False False False False False False False False
4 False False False False False False False False False

df.isnull()을 하면 모든 데이터에 대해서 null값일 경우 True, 아니면 False로 처리한다.
반면 df.notnull()을 하면 반대로 처리한다.

In [11]:
d1.sum()
Out[11]:
기준일     0
요일      0
성별      0
연령대     0
시도      0
시군구     0
읍면동     0
업종      0
통화건수    0
dtype: int64

위에서 bull값으로 처리한 데이터를 열(column)별로 더하는 작업이다. True=1, False=0을 의미한다.
더했을때 값이 0이 나오므로 이를 통해서도 null값이 없음을 알 수 있다.

3.어떻게 분석을 해볼까? 도메인 지식!

이제 이 데이터를 어떻게 다룰지 방향을 잡아보자. 데이터를 다룰때는 도메인 지식을 가지고 있어야지만 데이터에 의미를 부여할 수 있다. 우리가 알고 있는 약간의 지식을 활용하여 질문을 던져보자.

  1. 통화건수에 요일은 영향을 미칠까?
    금요일이나 토요일에 가장 많은 주문을 할 것 같다.

  2. 연령에 따라 통화 건수의 차이가 클까?
    금전적으로 여유가 있는 30대 40대가 더 많은 주문을 할 것 같다.

  3. 스포츠 경기나 중요 행사등이 영향을 미칠까?
    1월에 있었던 아시안게임의 축구경기가 영향을 미쳤을 것 같다.

4.분석을 위해 Data를 구축해 보자

Groupby
https://rfriend.tistory.com/383
집단별 크기는 grouped.size(), 집단별 합계는 grouped.sum(), 집단별 평균은 grouped.mean() 을 사용

In [12]:
from PIL import Image
img = Image.open('Groupby.jpg')
size=(500,500) 
img.thumbnail(size) # 불러온 이미지를 사이즈에 맞춰 조절
img
Out[12]:

이제 Data를 group by를 이용하여 요약해 보자.
요일은 보기 좋게 순서대로 나오도록 설정하자.
다음은 groupby의 구조가 딕셔너리라는 점을 이용해서 for문을 짜봤다.

In [13]:
week = data['통화건수'].groupby(data['요일'])
W = week.sum()
week_s = {}
for w in ['월','화','수','목','금','토','일']:
    week_s[w] = W[w]
week_s
Out[13]:
{'월': 38808,
 '화': 59152,
 '수': 55211,
 '목': 55768,
 '금': 63117,
 '토': 64817,
 '일': 58460}

인덱서를 사용해 나타내보자.
loc : 라벨값 기반의 2차원 인덱싱
iloc : 순서를 나타내는 정수 기반의 2차원 인덱싱

loc인덱서를 이용해 나타내 보았다.
여기서는 이게 베스트 인듯.
loc 인덱서를 사용하려면 df.loc[행 인덱스, 열 인덱스]와 같은 형태로 사용한다.
https://datascienceschool.net/view-notebook/704731b41f794b8ea00768f5b0904512/

In [14]:
week = data['통화건수'].groupby(data['요일'])
W = week.sum()
W.loc[['월','화','수','목','금','토','일']]
Out[14]:
요일
월    38808
화    59152
수    55211
목    55768
금    63117
토    64817
일    58460
Name: 통화건수, dtype: int64

책에서 보고 따라한건데 ix인덱서는 loc 인덱서와 iloc 인덱서로 대체 되었나보다.

In [15]:
week = data['통화건수'].groupby(data['요일'])
W = week.sum()
W.ix[['월','화','수','목','금','토','일']]
C:\Users\whanh\AppData\Local\Continuum\anaconda3\lib\site-packages\ipykernel_launcher.py:3: DeprecationWarning: 
.ix is deprecated. Please use
.loc for label based indexing or
.iloc for positional indexing

See the documentation here:
http://pandas.pydata.org/pandas-docs/stable/indexing.html#ix-indexer-is-deprecated
  This is separate from the ipykernel package so we can avoid doing imports until
Out[15]:
요일
월    38808
화    59152
수    55211
목    55768
금    63117
토    64817
일    58460
Name: 통화건수, dtype: int64

연령대별로 요약해보자

In [16]:
age = data['통화건수'].groupby(data['연령대'])
age.sum()
Out[16]:
연령대
10대       26681
20대       65140
30대       95924
40대      122028
50대       56655
60대이상     28905
Name: 통화건수, dtype: int64

피벗테이블을 이용해 요일과 연령대 정보를 통합하여 통화건수 정보를 추출해 보았다.

In [17]:
data1=data[['요일','연령대','통화건수']]
data1.head()
Out[17]:
요일 연령대 통화건수
0 20대 5
1 30대 36
2 10대 5
3 40대 5
4 40대 5
In [18]:
data1=data.pivot_table(values='통화건수',index='요일',columns='연령대', aggfunc=sum, margins=True).loc[['월','화','수','목','금','토','일']]
data1
Out[18]:
연령대 10대 20대 30대 40대 50대 60대이상 All
요일
3009 7002 9297 11069 5390 3041 38808
4147 10095 14282 17828 8518 4282 59152
4108 9556 13151 16200 8003 4193 55211
3963 9227 13228 17162 7993 4195 55768
4155 9779 15479 20609 8812 4283 63117
3896 10008 15959 20798 9428 4728 64817
3403 9473 14528 18362 8511 4183 58460

순서를 세기 위해 'All' 컬럼을 삭제하자.

In [19]:
data2 = data1.drop('All',axis=1)
data2
Out[19]:
연령대 10대 20대 30대 40대 50대 60대이상
요일
3009 7002 9297 11069 5390 3041
4147 10095 14282 17828 8518 4282
4108 9556 13151 16200 8003 4193
3963 9227 13228 17162 7993 4195
4155 9779 15479 20609 8812 4283
3896 10008 15959 20798 9428 4728
3403 9473 14528 18362 8511 4183
In [20]:
data2.idxmax(axis=0)
Out[20]:
연령대
10대      금
20대      화
30대      토
40대      토
50대      토
60대이상    토
dtype: object
In [21]:
data2.idxmax(axis=1)
Out[21]:
요일
월    40대
화    40대
수    40대
목    40대
금    40대
토    40대
일    40대
dtype: object

이 정보를 통해 40대가 가장 많이 주문 했음을, 그리고 토요일에 가장 많이 주문 했음을 알 수 있다.

한눈에 보기 좋게 전체 데이터를 나열해보자.

In [22]:
data3=np.array(data2)
np.sort(data3) , len(data3)*6
Out[22]:
(array([[ 3009,  3041,  5390,  7002,  9297, 11069],
        [ 4147,  4282,  8518, 10095, 14282, 17828],
        [ 4108,  4193,  8003,  9556, 13151, 16200],
        [ 3963,  4195,  7993,  9227, 13228, 17162],
        [ 4155,  4283,  8812,  9779, 15479, 20609],
        [ 3896,  4728,  9428, 10008, 15959, 20798],
        [ 3403,  4183,  8511,  9473, 14528, 18362]], dtype=int64), 42)
In [23]:
I=[]
labels1 = ['10대','20대','30대','40대','50대','60대이상']
labels2 = ['월','화','수','목','금','토','일']
for i in range(5):
    for j in range(6):
        I.append([data3[j,i], labels1[i], labels2[j]])
    
np.array(I)
data4 = pd.DataFrame(I)

data4.rename(columns = {data4.columns[0] : '총 통화건수',
                        data4.columns[1] : '연령대',
                        data4.columns[2] : '요일'}, inplace = True)
data4.sort_values('총 통화건수', ascending=False).head(15)
Out[23]:
총 통화건수 연령대 요일
23 20798 40대
22 20609 40대
19 17828 40대
21 17162 40대
20 16200 40대
17 15959 30대
16 15479 30대
13 14282 30대
15 13228 30대
14 13151 30대
18 11069 40대
7 10095 20대
11 10008 20대
10 9779 20대
8 9556 20대

40대 다음으로 30대 20대 순으로 주문량이 많았음을 한눈에 알아볼 수 있다.

30대 40대의 치킨주문량이 많은 이유는 금전적으로 여유가 있기 때문인것 같다.
그리고 사회활동이 왕성한 30대보다 40대 치킨 주문량이 많은것에 대해 의아하게 생각할 수 있는데, 40대의 경우 자녀들이 부모님의 핸드폰으로 치킨을 주문하는 경우가 있기 때문인 것 같다.

아시안컵 대한민국 축구 일정에 따른 주문건수 분석

  • 1차전
    대한민국:필리핀
    20190107 (월) 오후 10:30
  • 2차전
    대한민국:키르기스스탄
    20190112 (토) 오전 01:00
  • 3차전
    대한민국:중국
    20190116 (수) 오후 10:30
  • 16강
    대한민국:바레인
    20190122 (화) 오후 10:00
  • 8강
    대한민국:카타르
    20190125 (금) 오후 10:00

신기하게도 모든 축구경기 요일이 다르기 때문에, 각 축구경기가 있던 날의 주문량과 각 요일의 평균을 비교해보면 뻔하면서도 재미있는 결과를 알 수 있을 것 같다.

위 데이터를 이용하여 DataFrame을 만들어보자.

In [24]:
Asia = {'경기일':[20190107,20190112,20190116,20190122 ,20190125 ],
      '경기국가':['대한민국:필리핀', '대한민국:키르기스스탄','대한민국:중국','대한민국:바레인','대한민국:카타르'],
       '요일':['월','토','수','화','금']}
Asia_df = pd.DataFrame(Asia)
Asia_df
Out[24]:
경기일 경기국가 요일
0 20190107 대한민국:필리핀
1 20190112 대한민국:키르기스스탄
2 20190116 대한민국:중국
3 20190122 대한민국:바레인
4 20190125 대한민국:카타르

전체 데이터에서 해당 날짜 데이터만 가져오자

In [26]:
year = Asia_df['경기일']
data['기준일'].isin(year)
data_soccer = data[data['기준일'].isin(year)]
data_soccer.head(10)
Out[26]:
기준일 요일 성별 연령대 시도 시군구 읍면동 업종 통화건수
5761 20190107 30대 서울특별시 강남구 삼성동 치킨 23
5762 20190107 60대이상 서울특별시 강남구 역삼동 치킨 6
5763 20190107 50대 서울특별시 강남구 수서동 치킨 5
5764 20190107 20대 서울특별시 강남구 대치동 치킨 5
5765 20190107 40대 서울특별시 강남구 일원동 치킨 5
5766 20190107 40대 서울특별시 강남구 삼성동 치킨 66
5767 20190107 10대 서울특별시 강남구 삼성동 치킨 14
5768 20190107 20대 서울특별시 강남구 삼성동 치킨 14
5769 20190107 30대 서울특별시 강남구 대치동 치킨 5
5770 20190107 20대 서울특별시 강남구 신사동 치킨 5
In [27]:
data_soccer_G = data_soccer['통화건수'].groupby(data_soccer['기준일'])
data_soccer_G.sum()
Out[27]:
기준일
20190107    10481
20190112    16388
20190116    14101
20190122    14037
20190125    19690
Name: 통화건수, dtype: int64
In [28]:
I=[]
for i in np.array(data_soccer_G.sum()):
    I.append(i)
Asia_df['주문량']=I
Asia_df
Out[28]:
경기일 경기국가 요일 주문량
0 20190107 대한민국:필리핀 10481
1 20190112 대한민국:키르기스스탄 16388
2 20190116 대한민국:중국 14101
3 20190122 대한민국:바레인 14037
4 20190125 대한민국:카타르 19690
In [29]:
week = data['통화건수'].groupby(data['요일'])
W2 = week.sum()
W3=W2.loc[['월','토','수','화','금']]

J=[]
for i in np.array(W3):
    J.append(i)
J
Out[29]:
[38808, 64817, 55211, 59152, 63117]

평균을 구하기 위해 한달간 요일별로 몇 일이 있는지 구해보자.

In [31]:
data_z=data.drop_duplicates(['기준일'])
data_z.head(5)
Out[31]:
기준일 요일 성별 연령대 시도 시군구 읍면동 업종 통화건수
0 20190101 20대 서울특별시 강남구 도곡동 치킨 5
965 20190102 10대 서울특별시 강남구 세곡동 치킨 5
1849 20190103 10대 서울특별시 강남구 논현동 치킨 5
2784 20190104 60대이상 서울특별시 강남구 논현동 치킨 5
3787 20190105 40대 서울특별시 강남구 신사동 치킨 5
In [32]:
data_y=data_z['기준일'].groupby(data_z['요일'])
data_y.count()
Out[32]:
요일
금    4
목    5
수    5
월    4
일    4
토    4
화    5
Name: 기준일, dtype: int64

1월은 월요일, 금요일, 토요일 4번, 화요일, 수요일 5번 있었으므로 각각 나눠주자.

In [30]:
Asia_df['평균주문량']=[38808/4, 64817/4, 55211/5, 59152/5, 63117/4]
Asia_df
Out[30]:
경기일 경기국가 요일 주문량 평균주문량
0 20190107 대한민국:필리핀 10481 9702.00
1 20190112 대한민국:키르기스스탄 16388 16204.25
2 20190116 대한민국:중국 14101 11042.20
3 20190122 대한민국:바레인 14037 11830.40
4 20190125 대한민국:카타르 19690 15779.25

처음 두 경기는 평균 주문량보다 조금 더 많이 주문받은 정도 였지만, 16강의 명운이 달린 3번째 경기부터는 치킨주문량이 대폭 늘었으며, 그 후 16강 그리고 8강으로 더 높은 경기를 할수록 사람들이 기대감에 더 많은 시청을 하게 되고 그로인해 더 많은 치킨을 주문받은 것으로 보인다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함