[python] 소상공인시장진흥공단 상가업소정보로 프랜차이즈 입점분석 (4)

    [이전 글]

    소상공인시장진흥공단 상가업소정보로 프랜차이즈 입점분석 (3)

     

    [python] 소상공인시장진흥공단 상가업소정보로 프랜차이즈 입점분석 (3)

    소상공인시장진흥공단 상가업소정보로 스타벅스, 이디야 위치 분석하기 이번 실습에서는 이디야와 스타벅스의 매장입지의 차이에 대해 파악하는 과정을 다룬다. 다음 기사에서 제시된 시각화

    imstatdust.tistory.com

     


    구별 브랜드별 점포수 

    groupby와 pivot_table로 구별 스타벅스 이디야 매장 수 구하기

     

    groupby로 구별 매장 수 구하기

    df_cafe_vs = df_cafe.groupby(["시군구명", "브랜드명"])["상호명"].count()
    df_cafe_vs.head()

    # 인덱스 컬럼 만들기
    df_cafe_vs = df_cafe_vs.reset_index()
    df_cafe_vs.head()

    # groupby '시군구명', '브랜드명' 으로 갯수 세기
    df_cafe_vs.columns = ['구', '브랜드명', '매장수']
    df_cafe_vs.head()

     

    pivot_table로 구별 매장 수 구하기

    pivot = pd.pivot_table(data=df_cafe,
                          index=["시군구명", "브랜드명"],
                          values="상호명", aggfunc="count")
    pivot.head()

    # 특정 구 데이터만 가져와서 보기
    
    pivot.loc["강남구"]

     

    막대그래프로 시각화하기

    plt.figure(figsize=(15,4))
    sns.barplot(data=df_cafe_vs, x="구", y="매장수", hue="브랜드명")

    # barplot 정렬하기
    plt.figure(figsize=(15, 4))
    sns.barplot(data=df_cafe_vs.sort_values("매장수", ascending=False), x="구", y="매장수", hue="브랜드명")

    group = df_cafe.groupby(["시군구명", "브랜드명"])["상호명"].count()
    group.plot.bar(figsize=(15, 4))

    group.unstack().plot.bar(figsize=(15, 4))

    unstack? : 인덱스 값을 컬럼으로 올려주는 역할을 하는 함수, 인덱스 level별로 컬럼을 올려준다. level 설정을 하지 않으면 제일 높은 level의 인덱스부터 하나씩 올린다. 

    https://pandas.pydata.org/docs/user_guide/reshaping.html

     

    Reshaping and pivot tables — pandas 1.5.3 documentation

    But suppose we wish to do time series operations with the variables. A better representation would be where the columns are the unique variables and an index of dates identifies individual observations. To reshape the data into this form, we use the DataFr

    pandas.pydata.org

    https://wikidocs.net/158413

     

    17-03 언피벗화, 행의 열로 변환 (unstack)

    ####DataFrame.unstack(level=- 1, fill_value=None) ##개요 `unstack` 메서드는 행을 언피벗하여 하위 열로 변환하는 메서드입니다. ※…

    wikidocs.net

    https://seong6496.tistory.com/241

     

    [Pandas] 데이터프레임 재구조화하기(Stack,Unstack)

    pivot과 비슷하게 Series, DataFrame을 기준점에 맞게 변경하는 stack, unstack 함수 사용 방법입니다. 보통 한 묶음으로 stack, unstack을 쓰는데 그 이유는 stack은 컬럼을 인덱스로 가져오는 것이고 unstack은

    seong6496.tistory.com

     

    Folium으로 지도 활용하기 

    #지도의 중심 지정하기 위해 위도와 경도의 평균을 구해준다.
    import folium
    
    lat = df_cafe["위도"].mean()
    long = df_cafe["경도"].mean()
    lat, long
    (37.5429213982126, 126.9887885123524)

     

    스타벅스 이디야 카페 매장 전체 분포

    m = folium.Map([lat, long], zoom_start=12, tiles="Stamen Toner")
    
    for i in df_cafe.index:
        sub_lat = df_cafe.loc[i, "위도"]
        sub_long = df_cafe.loc[i, "경도"]
        
        title = f"{df_cafe.loc[i, '상호명']} - {df_cafe.loc[i, '도로명주소']}"
        
        color = "green"
        if df_cafe.loc[i, "브랜드명"] == "이디야":
            color = "blue"
        
        folium.CircleMarker([sub_lat, sub_long],
                            radius=3,
                            color=color,
                              tooltip=title).add_to(m)
    m

     

     

    choropleth를 위한 GeoJSON 파일로드

    - 구별로 매장 수를 표현하기 위해 GeoJSON 파일로드 : https://github.com/southkorea/seoul-maps

     

    # 서울의 행정구역 경계를 GeoJSON으로 표현한 파일
    # 이 파일을 불러와 구별 스타벅스와 이디야의 매장수를 표현한다.
    geo_path = 'C:/Users/yobin/Downloads/seoul_municipalities_geo_simple.json'
    
    import json
    geo_json = json.load(open(geo_path, encoding="utf-8"))

     

    스타벅스 매장 분포

    df_star = df_cafe_vs[df_cafe_vs["브랜드명"] == "스타벅스"].copy()
    df_star.head()

    # geo_json 에서 구 이름 가져오기
    
    geo_json["features"][0]['properties']['name']

    '강동구'

     

    # df_cafe_starbucks 로 스타벅스 매장 수 구하기
    
    m = folium.Map([lat, long])
    
    folium.Choropleth(
        geo_data=geo_json,
        name='choropleth',
        data=df_star,
        columns=['구', '매장수'],
        key_on='feature.properties.name',
        fill_color='YlGn',
        fill_opacity=0.7,
        line_opacity=0.2,
        legend_name='스타벅스 매장수'
    ).add_to(m)
    
    m


     

    이디야 매장 분포

    df_ediya = df_cafe_vs[df_cafe_vs["브랜드명"] == "이디야"].copy()
    df_ediya.head()

     

    m = folium.Map([lat, long], titles='stamen toner')
    
    folium.Choropleth(
        geo_data=geo_json,
        name='choropleth',
        data=df_ediya,
        columns=['구', '매장수'],
        key_on='feature.properties.name',
        fill_color='Blues',
        fill_opacity=0.7,
        line_opacity=0.2,
        legend_name='이디야 매장수'
    ).add_to(m)
    
    
    for i in df_cafe.index:
        sub_lat = df_cafe.loc[i, "위도"]
        sub_long = df_cafe.loc[i, "경도"]
        
        title = f"{df_cafe.loc[i, '상호명']} - {df_cafe.loc[i, '도로명주소']}"
        
        color = "green"
        if df_cafe.loc[i, "브랜드명"] == "이디야":
            color = "blue"
        
        folium.CircleMarker([sub_lat, sub_long],
                            radius=3,
                            color=color,
                              tooltip=title).add_to(m)
        
    m

     

     

    매장수 크기를 반영해 CircleMaker 만들기

    # df_vs 변수에 구별 브랜드명을 pivot하여 스타벅스와 이디야 매장을 비교할 수 있는 형태로 만들어준다.
    # ["스타벅스", "이디야"] 로 컬럼명을 변경해주고 
    # 스타벅스와 이디야의 매장을 비교한 값을 "매장수비교" 컬럼에 담아준다. 
    
    
    df_vs = df_cafe_vs.pivot(index="구", columns="브랜드명", values="매장수")
    df_vs["매장수비교"] = df_vs["스타벅스"] -  df_vs["이디야"] > 0
    df_vs.head()

     

    # 간단한 함수를 사용해서 스타벅스가 이디야보다 매장수가 많을 때 1을 출력하도록 한다.
    df_vs["매장수비교"] = df_vs["매장수비교"].astype(float)
    df_vs.head()

    # 구를 컬럼명으로 사용하기 위해 reset_index 를 사용한다. 
    # 데이터 프레임을 df_vs 에 저장
    
    df_vs = df_vs.reset_index()
    df_vs.head()

     

    choropleth로 매장수의 많고 적음에 따라 표현하기

    # 스타벅스 매장 수 구하기
    # CircleMarker의 radius 지정시 int 타입일 때 다음과 같은 타입오류가 나서 float type 으로 변경이 필요
    
    m1 = folium.Map([lat, long], titles='stamen toner')
    
    folium.Choropleth(
        geo_data=geo_json,
        name='choropleth',
        data=df_vs,
        columns=['구', '매장수비교'],
        key_on='feature.properties.name',
        fill_color='BuGn',
        fill_opacity=0.7,
        line_opacity=0.2,
        legend_name='매장수 비교'
    ).add_to(m1)
    
    m1

     

     

    df_gu_mean = df_cafe.pivot_table(index="시군구명", values=["경도", "위도"], aggfunc="mean")
    df_gu_mean = df_gu_mean.reset_index()
    df_gu_mean.head()

     

    df_vs = df_vs.merge(df_gu_mean, how='inner', left_on="구", right_on="시군구명")
    df_vs.head()

    # 구별로 CircleMarker를 표현하기 위해서는 각 구의 위경도 값을 구해야 한다.
    # 구별 위도와 경도를 가져와 평균 값을 구해서 사용
    # 특정 구의 위경도의 평균을 구한다.
    
    for i in df_vs.index:
        sub_long = df_vs.loc[i, "경도"]
        sub_lat = df_vs.loc[i, "위도"]
        
        print(df_vs.loc[i, "구"], sub_lat, sub_long)
    강남구 37.50574379723648 127.04612924851483
    강동구 37.540316128928005 127.13541705768309
    강북구 37.63114579912596 127.02289728220342
    강서구 37.555966339807725 126.83788319929005
    관악구 37.482054429288624 126.93521011850085
    광진구 37.543769718110475 127.08329747837425
    구로구 37.49406074774298 126.87745596750014
    금천구 37.46928692765211 126.89219622133886
    노원구 37.64239330513539 127.06717137772726
    도봉구 37.66576544822702 127.04047354226729
    동대문구 37.580700635471146 127.0549281321253
    동작구 37.49570035386574 126.94890217041826
    마포구 37.55548154197543 126.92300493503947
    서대문구 37.566284229288875 126.93762476470604
    서초구 37.493010911046724 127.01402160112261
    성동구 37.55457943854072 127.03635911128876
    성북구 37.59886024576221 127.02565170180027
    송파구 37.5011799146096 127.1141353230951
    양천구 37.52891847594385 126.86196683493063
    영등포구 37.520781009585264 126.91390000535674
    용산구 37.53468952777027 126.98251254628539
    은평구 37.61406806596294 126.92041650466945
    종로구 37.57615434804085 126.98723628325016
    중구 37.56289726978086 126.986573350736
    중랑구 37.596057768601725 127.08732220351888

     

    신문기사와 유사하게 매장수에 따라 원의 크기를 다르게 그리기

     

    [비즈&빅데이터]스타벅스 '쏠림' vs 이디야 '분산'

    스타벅스와 이디야는 해외브랜드와 토종브랜드를 대표하는 양대 커피 전문점이다. 1999년 이대1호점으로 국내에 상륙한 스타벅스는 신세계 이마트와 미국 스타벅스 본사(스타벅스커피인터내셔

    news.bizwatch.co.kr

     

        cafes = ["스타벅스", "이디야"]
        for cafe in cafes:
            print(cafe)

    스타벅스

    이디야

     

    df_vs.head(1)

     

    np.sqrt(50)
    7.0710678118654755

     

    # 아래의 for문을 활용해서  스타벅스, 이디야로 매장수를 반영해 그린다.
    # CircleMarker 의 radius 크기를 구해 원의 크기를 다르게 표현
    # 또, 경도에 특정 숫자를 더해 두 개의 원이 겹치지 않게 그린다.
    
    m = folium.Map([lat, long], zoom_start=11, tiles='stamen toner')
    
    folium.Choropleth(
        geo_data=geo_json,
        name='choropleth',
        data=df_vs,
        columns=['구', '매장수비교'],
        key_on='feature.properties.name',
        fill_color='BuGn',
        fill_opacity=0.7,
        line_opacity=0.2,
        legend_name='매장수 비교'
    ).add_to(m)
    
    
    for i in df_vs.index:
        sub_long = df_vs.loc[i, "경도"]
        sub_lat = df_vs.loc[i, "위도"]
        
        cafes = ["스타벅스", "이디야"]
        for cafe in cafes:
            cafe_count = df_vs.loc[i, cafe]
            
            gu = df_vs.loc[i, "구"]
            tooltip = f"{gu} {cafe} : {cafe_count}"
            
            radius = np.sqrt(cafe_count) * 3
            
            if cafe == "이디야":
                color = "blue"
                sub_long = sub_long + 0.01
            else:
                color = "green"
                
                
            folium.CircleMarker([sub_lat, sub_long],
                                radius=radius,
                                color=color,
                                fill=True,
                                tooltip=tooltip,
                               ).add_to(m)
            
    m

     

    댓글