Skip to content

Instantly share code, notes, and snippets.

@QuantTraderEd
Last active December 10, 2017 11:12
Show Gist options
  • Save QuantTraderEd/55716c633343ceeca426 to your computer and use it in GitHub Desktop.
Save QuantTraderEd/55716c633343ceeca426 to your computer and use it in GitHub Desktop.
Burger Index (py2.7)
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 26 11:10:09 2015
@author: ASSA
"""
import urllib
import urllib2
import json
import pandas as pd
import numpy as np
import bs4
import matplotlib
# check pkg version
pd.__version__
np.__version__
matplotlib.__version__
# read information of bgk store location from web
response = urllib2.urlopen('http://www.burgerking.co.kr/api/store/searchmap/empty/?areacd=')
bgk_data = json.loads(response.read().decode('utf-8'))
bgk_tbl = pd.DataFrame(bgk_data)
# subtract address information
bgk_locs = pd.DataFrame(bgk_tbl['NewAddr'].apply(lambda v: v.split()[:2]).tolist(),columns=('d1', 'd2'))
# check up the name of city
bgk_locs['d1'].unique()
# change unique name from proxy names
d1_aliases = """서울시:서울특별시 충남:충청남도 강원:강원도 경기:경기도 충북:충청북도 경남:경상남도 경북:경상북도
전남:전라남도 전북:전라북도 제주도:제주특별자치도 제주:제주특별자치도 대전시:대전광역시 대구시:대구광역시 인천시:인천광역시
광주시:광주광역시 울산시:울산광역시"""
d1_aliases = unicode(d1_aliases)
d1_aliases = dict(aliasset.split(':') for aliasset in d1_aliases.split())
bgk_locs['d1'] = bgk_locs['d1'].apply(lambda v: d1_aliases.get(v, v))
#check d1
bgk_locs['d1'].unique()
# why 수원시 exist ??
# correct 수원시 -> 경기도
# correct 송도과학로 -> 인천시 연수구
bgk_locs[bgk_locs['d1'] == unicode('수원시')]
# change 101, 129 row
bgk_locs.iloc[101] = [unicode('경기도'), unicode('수원시')]
bgk_locs.iloc[129] = [unicode('인천광역시'), unicode('연수구')]
#check d2
bgk_locs['d2'].unique()
B = bgk_locs.apply(lambda r: r['d1'] + ' ' + r['d2'], axis=1).value_counts()
# McDonald data from web
MCDONALDS_URL = 'http://www.mcdonalds.co.kr/www/kor/findus/district.do?sSearch_yn=Y&skey=2&pageIndex={page}&skeyword={location}'
def search_mcdonalds_stores_one_page(location, page):
response = urllib2.urlopen(
MCDONALDS_URL.format(location=urllib2.quote(location.encode('utf-8')), page=page))
mcd_data = response.read().decode('utf-8')
soup = bs4.BeautifulSoup(mcd_data)
ret = []
for storetag in soup.findAll('dl', attrs={'class': 'clearFix'}):
storename = storetag.findAll('a')[0].contents[-1].strip()
storeaddr = storetag.findAll('dd', attrs={'class': 'road'})[0].contents[0].split(']')[1]
storeaddr_district = storeaddr.split()[:2]
ret.append([storename] + storeaddr_district)
return pd.DataFrame(ret, columns=('store', 'd1', 'd2')) if ret else None
# 여러 페이지를 쭉 찾아서 안 나올 때 까지 합친다.
def search_mcdonalds_stores(location):
from itertools import count
found = []
for pg in count():
foundinpage = search_mcdonalds_stores_one_page(location, pg+1)
if foundinpage is None:
break
found.append(foundinpage)
return pd.concat(found)
# 지역 테스트
search_mcdonalds_stores('전라북도').head()
# 전체 지역 검색
found = []
for distr in bgk_locs['d1'].unique():
found.append(search_mcdonalds_stores(distr))
mcd_tbl = pd.concat(found)
# 중복확인
mcd_tbl['store'].value_counts().head()
#중복제거
mcd_tbl = mcd_tbl.drop_duplicates(cols=['store'])
# Mcd 매장 갯수 확인
M = mcd_tbl.apply(lambda r: r['d1'] + ' ' + r['d2'], axis=1).value_counts()
M.head()
# Start KFC
kfc_dists = "강원 경기 경남 경북 광주 대구 대전 부산 서울 울산 인천 전남 전북 제주 충남 충북".split()
KFC_DISTSEARCH_URL = 'http://www.kfckorea.com/store/store_addr_search.asp?addr_div=gugun&sido={location}'
def kfc_search_subdists(location):
response = urllib2.urlopen(
KFC_DISTSEARCH_URL.format(location=urllib2.quote(location.encode('utf-8'))))
kfc_data = response.read().decode('utf-8')
soup = bs4.BeautifulSoup(kfc_data)
return list(filter(None, [tag.attrs['value'] for tag in soup.findAll('option')]))
kfc_alldist = [(d, subd) for d in kfc_dists for subd in kfc_search_subdists(d)]
kfc_alldist[:5], len(kfc_alldist)
# JSON return
KFC_STORESEARCH_URL = ('http://www.kfckorea.com/store/store_search.asp?sales_24_yn_=&'
'sales_wifi_yn_=&sales_order_group_yn_=&sales_park_yn_=&sales_subway_yn_=&'
'sales_mart_in_yn_=&searchFlag=0&addr_div1={div1}&addr_div2={div2}&keyword=')
def kfc_search_stores_in_dist(d1, d2):
response = urllib2.urlopen(
KFC_STORESEARCH_URL.format(div1=urllib2.quote(d1.encode('utf-8')),
div2=urllib2.quote(d2.encode('utf-8'))))
return json.loads(response.read().decode('utf-8'))['store']
found = []
for d1, d2 in kfc_alldist:
found.extend(kfc_search_stores_in_dist(d1, d2))
kfc_tbl = pd.DataFrame(found)
# Counting store number @ province
kfc_locs = pd.DataFrame(kfc_tbl['old_addr1'].apply(
lambda v: v.replace(' ', ' ').replace(' ', ' ').replace('광주 광역', '광주광역').split()[:2]).tolist(),
columns=('d1', 'd2'))
kfc_locs['d1'].unique()
d1_aliases = """서울시:서울특별시 충남:충청남도 강원:강원도 경기:경기도 충북:충청북도 경남:경상남도 경북:경상북도
전남:전라남도 전북:전라북도 제주도:제주특별자치도 제주:제주특별자치도 대전시:대전광역시 대구시:대구광역시 인천시:인천광역시
광주시:광주광역시 울산시:울산광역시 광주:광주광역시 대구:대구광역시 대전:대전광역시 부산:부산광역시 부산시:부산광역시
인천:인천광역시 서울:서울특별시 울산:울산광역시"""
d1_aliases = unicode(d1_aliases)
d1_aliases = dict(aliasset.split(':') for aliasset in d1_aliases.split())
kfc_locs['d1'] = kfc_locs['d1'].apply(lambda v: d1_aliases.get(v, v))
kfc_locs['d1'].unique()
kfc_locs['d2'].unique()
K = kfc_locs.apply(lambda r: r['d1'] + ' ' + r['d2'], axis=1).value_counts()
# integrate all data
BMK = pd.DataFrame({'B': B, 'M': M, 'K': K}).fillna(0)
BMK['total'] = BMK.sum(axis=1)
BMK = BMK.sort('total', ascending=False)
BMK.head(10)
from matplotlib import pyplot as plt
from matplotlib import rcParams, style
style.use('ggplot')
rcParams['font.size'] = 12
plt.figure(figsize=(4, 3))
BMK.sum(axis=0).iloc[:3].plot(kind='bar')
# 본격 분석1 (브랜드별 매장수 상관관계 분석)
import scipy.stats
fig = plt.figure(figsize=(9, 3))
def plot_nstores(b1, b2, label1, label2):
plt.scatter(BMK[b1] + np.random.random(len(BMK)),
BMK[b2] + np.random.random(len(BMK)),
edgecolor='none', alpha=0.75, s=6, c='black')
plt.xlim(-1, 15)
plt.ylim(-1, 15)
plt.xlabel(label1)
plt.ylabel(label2)
r = scipy.stats.pearsonr(BMK[b1], BMK[b2])
plt.annotate('r={:.3f}'.format(r[0]), (10, 12.5))
ax = fig.add_subplot(1, 3, 1)
plot_nstores('B', 'M', 'Burger King', "McDonald's")
ax = fig.add_subplot(1, 3, 2)
plot_nstores('B', 'K', 'Burger King', 'KFC')
ax = fig.add_subplot(1, 3, 3)
plot_nstores('M', 'K', "McDonald's", 'KFC')
plt.tight_layout()
# 본격 분석2 (누적 매장수 분석)
plt.figure(figsize=(4, 3))
for col, label in [('B', 'Burger King'), ('K', 'KFC'), ('M', "McDonald's")]:
cumulv = np.cumsum(sorted(BMK[col], reverse=True)) / BMK[col].sum()
plt.plot(cumulv, label='{} ({})'.format(label, int(BMK[col].sum())))
plt.legend(loc='best')
plt.xlabel('Number of districts (si/gun/gu)')
plt.ylabel('Cumulative fraction')
plt.tight_layout()
# Get Lotteria Data from Web
LOTTERIA_URL = 'http://www.lotteria.com/Shop/Shop_Ajax.asp'
LOTTERIA_VALUES = {
'Page': 1, 'PageSize': 2000, 'BlockSize': 2000,
'SearchArea1': '', 'SearchArea2': '', 'SearchType': "TEXT",
'SearchText': '', 'SearchIs24H': '', 'SearchIsWifi': '',
'SearchIsDT': '', 'SearchIsHomeService': '', 'SearchIsGroupOrder': '',
'SearchIsEvent': ''}
LOTTERIA_HEADERS = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:12.0) Gecko/20100101',
'Host': 'www.lotteria.com',
'Accept': 'text/html, */*; q=0.01',
'Accept-Language': 'en-us,en;q=0.5',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With': 'XMLHttpRequest',
'Referer': 'http://www.lotteria.com/Shop/Shop_List.asp?Page=1&PageSize=2000&BlockSize=2000&Se'
'archArea1=&SearchArea2=&SearchType=TEXT&SearchText=&SearchIs24H=&SearchIsWifi=&Se'
'archIsDT=&SearchIsHomeService=&SearchIsGroupOrder=&SearchIsEvent=',
}
postdata = urllib.urlencode(LOTTERIA_VALUES).encode('utf-8')
req = urllib2.Request(LOTTERIA_URL, postdata, LOTTERIA_HEADERS)
response = urllib2.urlopen(req)
ltr_data = response.read().decode('utf-8')
soup = bs4.BeautifulSoup(ltr_data)
found = []
for tag in soup.findAll('tr', {'class': 'shopSearch'}):
subtag = [tag.findAll('td', {'style': 'padding-right:10px;'}
)[i].contents[0].contents[0]
for i in (0, 1)]
found.append([subtag[0]] + subtag[1].replace('광주 광역', '광주광역').split()[:2])
ltr_tbl = pd.DataFrame(found, columns=('storename', 'd1', 'd2'))
ltr_tbl.head()
ltr_tbl['d1'].unique()
# 청북 -> 충청북도
d1_aliases = """강원:강원도 충북:충청북도 부산:부산광역시 경기:경기도 전남:전라남도 경북:경상북도
대구:대구광역시 서울:서울특별시 세종:세종특별자치시 경남:경상남도 충남:충청남도 대전:대전광역시
울산:울산광역시 제주:제주특별자치도 인천:인천광역시 전북:전라북도 광주:광주광역시 대전시:대전광역시
충남시:충청남도 청북:충청북도"""
d1_aliases = unicode(d1_aliases)
d1_aliases = dict(aliasset.split(':') for aliasset in d1_aliases.split())
ltr_tbl['d1'] = ltr_tbl['d1'].apply(lambda v: d1_aliases.get(v, v))
ltr_tbl['d1'].unique()
# distinct name check >_<
ltr_tbl['d2'].unique()
# distingt un split distinct name
d2_aliases = """나주시금천면:나주시 장성군장성읍:장성군 고흥군고흥읍:고흥군 기장군정관면:기장군
창녕군남지읍:창녕군 임실군임실읍:임실군 원주시지정면:원주시 진구:부산진구 논산시연무읍:논산시"""
d2_aliases = unicode(d2_aliases)
d2_aliases = dict(aliasset.split(':') for aliasset in d2_aliases.split())
ltr_tbl['d2'] = ltr_tbl['d2'].apply(lambda v: d2_aliases.get(v, v))
ltr_tbl['d2'].unique()
# there are a lot of store so here are some error for address name and then re check!!
ltr_tbl[ltr_tbl['d2'].apply(lambda v: v[-1] not in '시군구')]
d2_aliases = """연기면:세종시 금남면:세종시 조치원읍:세종시 아산신:아산시 구로:구로구
종로2가:종로구"""
d2_aliases = unicode(d2_aliases)
d2_aliases = dict(aliasset.split(':') for aliasset in d2_aliases.split())
ltr_tbl['d2'] = ltr_tbl['d2'].apply(lambda v: d2_aliases.get(v, v))
ltr_tbl['d2'].unique()
# Finally, we can get a count of store each place
L = ltr_tbl.apply(lambda r: r['d1'] + ' ' + r['d2'], axis=1).value_counts()
L.head()
# one more last, match list to wiki data
distr_latlon = pd.read_table('lonlat.txt')
#distr_latlon.index = distr_latlon.apply(lambda r: r['d1'] + ' ' + r['d2'], axis=1) # what encoding is index string ??
distr_latlon.index = distr_latlon.apply(lambda r: (r['d1'] + ' ' + r['d2']).decode('utf-8'), axis=1)
distr_latlon['d1'] = distr_latlon.apply(lambda r: r['d1'].decode('utf-8'), axis=1)
distr_latlon['d2'] = distr_latlon.apply(lambda r: r['d2'].decode('utf-8'), axis=1)
bgt = pd.DataFrame({'B': B, 'M': M, 'K': K, 'L': L}).fillna(0)
bgt = pd.merge(distr_latlon, bgt, how='outer', left_index=True, right_index=True) # index is unicode, so that can not matching
bgt.head()
# check nan
bgt[np.isnan(bgt['area'])]
# correct area name
bgidx_cols = ['B', 'K', 'L', 'M']
bgt.loc[unicode('경기도 여주시'), bgidx_cols] += bgt.loc[unicode('경기도 여주군'), bgidx_cols]
bgt.loc[unicode('울산광역시 울주군'), bgidx_cols] += bgt.loc[unicode('울산광역시 을주군'), bgidx_cols]
bgt.loc[unicode('충청남도 천안시'), bgidx_cols] += bgt.loc[unicode('충청북도 천안시'), bgidx_cols]
bgt.loc[unicode('충청북도 청주시'), bgidx_cols] += bgt.loc[unicode('충청북도 청원군'), bgidx_cols] # 2014년 7월 1일 통합.
bgt = bgt[~np.isnan(bgt['area'])].fillna(0)
# calc the buger index moment!!
# check the Lotteria count
bgt[(bgt['L'] == 0) & (bgt['B'] + bgt['M'] + bgt['K'] > 0)]
bgt[bgt['L'] == 0]
# real real calc buger index
bgt['BMK'] = bgt['B'] + bgt['M'] + bgt['K']
bgt['BgIdx'] = bgt['BMK'] / bgt['L']
bgt = bgt.sort('BgIdx', ascending=False)
bgt.head(10)
# compare L vs BMK
rcParams['font.family'] = 'NanumGothic'
plt.figure(figsize=(5, 5))
r = lambda: np.random.random(len(bgt))
plt.scatter(bgt['L'] + r(), bgt['BMK'] + r(), s=6, c='black', edgecolor='none', alpha=0.6)
plt.xlabel('Lotteria')
plt.ylabel('BurKing+Mac+KFC')
plt.xlim(0, 45)
plt.ylim(0, 45)
plt.gca().set_aspect(1)
# draw trendline
trendfun = np.poly1d(np.polyfit(bgt['L'], bgt['BMK'], 1))
trendx = np.linspace(0, 45, 2)
plt.plot(trendx, trendfun(trendx))
# mark anormal point
tolabel = bgt[(bgt['L'] > 17) | (bgt['BMK'] >= 14)]
for idx, row in tolabel.iterrows():
label_name = idx.split()[1][:-1]
plt.annotate(label_name, (row['L'], row['BMK']))
# ready to mapping
def short_distr(name):
wide, narrow = name.split()
if narrow.endswith(unicode('구')):
return wide[:2] + (narrow[:-1] if len(narrow) > 2 else narrow)
elif narrow == unicode('고성군'): # 고성군은 강원도, 경상남도에 있다.
result = '고성({})'.format({unicode('강원도'): unicode('강원'), unicode('경상남도'): unicode('경남')}[wide])
return unicode(result)
else:
return narrow[:-1]
bgt['shortname'] = list(map(short_distr, bgt.index))
bgt.head()
# load block map data
blockpositions = pd.read_csv('blockmap-positions.csv', names=range(15))
for i in xrange(len(blockpositions)):
for j in xrange(len(blockpositions.columns)):
if type(blockpositions.iloc[i][j]) == str:
test_text = blockpositions.iloc[i][j]
blockpositions.loc[i,j] = test_text.decode('utf-8')
blockpositions.head()
# x,y coordinate date + burger data
flatrows = []
for y, colcities in blockpositions.iterrows():
for x, city in colcities.iteritems():
if isinstance(city, unicode):
flatrows.append((x, y, city))
blockpositions_tbl = pd.DataFrame(flatrows, columns=('x', 'y', 'city')).set_index('city').sort_index()
bgtb = pd.merge(bgt, blockpositions_tbl, how='left', left_on='shortname', right_index=True)
bgtb.head()
# check missing pos x
bgtb[bgtb['x'].apply(np.isnan)]
from matplotlib import rcParams
from matplotlib import cm, colors, _cm
rcParams['font.family'] = 'NanumBarunGothic'
bgtb['BgIdx'] = bgtb['BgIdx'].fillna(0)
bgtb.index = bgtb.apply(lambda r: str(r['d1'] + ' ' + r['d2']), axis=1)
bgtb['shortname'] = bgtb.apply(lambda r: str(r['shortname']), axis=1)
# draw border line
BORDER_LINES = [
[(3, 2), (5, 2), (5, 3), (9, 3), (9, 1)], # 인천
[(2, 5), (3, 5), (3, 4), (8, 4), (8, 7), (7, 7), (7, 9), (4, 9), (4, 7), (1, 7)], # 서울
[(1, 6), (1, 9), (3, 9), (3, 10), (8, 10), (8, 9),
(9, 9), (9, 8), (10, 8), (10, 5), (9, 5), (9, 3)], # 경기도
[(9, 12), (9, 10), (8, 10)], # 강원도
[(10, 5), (11, 5), (11, 4), (12, 4), (12, 5), (13, 5),
(13, 4), (14, 4), (14, 2)], # 충청남도
[(11, 5), (12, 5), (12, 6), (15, 6), (15, 7), (13, 7),
(13, 8), (11, 8), (11, 9), (10, 9), (10, 8)], # 충청북도
[(14, 4), (15, 4), (15, 6)], # 대전시
[(14, 7), (14, 9), (13, 9), (13, 11), (13, 13)], # 경상북도
[(14, 8), (16, 8), (16, 10), (15, 10),
(15, 11), (14, 11), (14, 12), (13, 12)], # 대구시
[(15, 11), (16, 11), (16, 13)], # 울산시
[(17, 1), (17, 3), (18, 3), (18, 6), (15, 6)], # 전라북도
[(19, 2), (19, 4), (21, 4), (21, 3), (22, 3), (22, 2), (19, 2)], # 광주시
[(18, 5), (20, 5), (20, 6)], # 전라남도
[(16, 9), (18, 9), (18, 8), (19, 8), (19, 9), (20, 9), (20, 10)], # 부산시
]
def draw_blockcolormap(tbl, datacol, vmin, vmax, whitelabelmin, cmapname, gamma, datalabel, dataticks):
cmap = colors.LinearSegmentedColormap(cmapname + 'custom',
getattr(_cm, '_{}_data'.format(cmapname)), gamma=gamma)
cmap.set_bad('white', 1.)
mapdata = tbl.pivot(index='y', columns='x', values=datacol)
masked_mapdata = np.ma.masked_where(np.isnan(mapdata), mapdata)
plt.figure(figsize=(9, 16))
plt.pcolor(masked_mapdata, vmin=vmin, vmax=vmax, cmap=cmap,
edgecolor='#aaaaaa', linewidth=0.5)
# 지역 이름 표시
for idx, row in tbl.iterrows():
annocolor = 'white' if row[datacol] > whitelabelmin else 'black'
# 광역시는 구 이름이 겹치는 경우가 많아서 시단위 이름도 같이 표시한다. (중구, 서구)
if row['d1'].endswith(str('시')) and not row['d1'].startswith(str('세종')):
dispname = '{}\n{}'.format(row['d1'][:2], row['d2'][:-1])
if len(row['d2']) <= 2:
dispname += row['d2'][-1]
else:
dispname = row['d2'][:-1]
# 서대문구, 서귀포시 같이 이름이 3자 이상인 경우에 작은 글자로 표시한다.
if len(dispname.splitlines()[-1]) >= 3:
fontsize, linespacing = 12, 1.2
else:
fontsize, linespacing = 14, 1.03
plt.annotate(dispname, (row['x']+0.5, row['y']+0.5), weight='bold',
fontsize=fontsize, ha='center', va='center', color=annocolor,
linespacing=linespacing)
# 시도 경계 그린다.
for path in BORDER_LINES:
ys, xs = zip(*path)
plt.plot(xs, ys, c='black', lw=2)
plt.gca().invert_yaxis()
plt.gca().set_aspect(1)
plt.axis('off')
cb = plt.colorbar(shrink=.1, aspect=10)
cb.set_label(datalabel)
cb.set_ticks(dataticks)
plt.tight_layout()
draw_blockcolormap(bgtb, 'BgIdx', 0, 3, 1.42, 'Blues', 0.75, '버거지수', np.arange(0, 3.1, 0.5))
plt.savefig('bmap-burgerindex.pdf')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment