7. 커피프랜차이즈 이점 전략

2024. 12. 23. 13:40LLM(Large Language Model)의 기초

1. 커피프랜차이즈 데이터 가져오기 및 import 하기

import time
import re # 정규식 패턴
import pandas as pd
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup

 

예 1)

import time
import re # 정규식(Regular Expression) 처리를 위한 모듈
import pandas as pd
from selenium import webdriver # Selenium WebDriver 사용
from selenium.webdriver import ActionChains # 복잡한 마우스 동작 등을 처리하기 위한 모듈
from selenium.webdriver.common.by import By # 요소를 찾을 때 사용하는 Selector를 위한 모듈
from selenium.webdriver.support.ui import WebDriverWait # 특정 조건이 만족될 때까지 기다리는 데 사용
from selenium.webdriver.support import expected_conditions as EC # WebDriverWait 조건 정의
from bs4 import BeautifulSoup # HTML 파싱 및 데이터 추출을 위한 모듈

def fetch_starbucks():
    # Starbucks 홈페이지 URL
    starbucks_url = 'https://www.starbucks.co.kr/index.do'
    driver = webdriver.Chrome() # 크롬 드라이버 실행
    driver.maximize_window() # 브라우저 창 최대화
    driver.get(starbucks_url) # Starbucks 홈페이지 접속
    time.sleep(1) # 페이지 로딩을 위해 1초 대기

    # ActionChains(): 마우스와 키보드 조작을 위한 객체
    action = ActionChains(driver)
    
    # "매장 찾기" 메뉴로 이동
    first_tag = driver.find_element(By.CSS_SELECTOR, '#gnb > div > nav > div > ul > li.gnb_nav03') # 상위 메뉴 선택
    second_tag = driver.find_element(By.CSS_SELECTOR, '#gnb > div > nav > div > ul > li.gnb_nav03 > div > div > div > ul:nth-child(1) > li:nth-child(3) > a') # 하위 메뉴 "매장 찾기" 선택
    action.move_to_element(first_tag).move_to_element(second_tag).click().perform() # 메뉴를 클릭하여 실행

    # "서울" 지역 선택 버튼을 기다렸다가 클릭
    seoul_tag = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable(
            (By.CSS_SELECTOR, '#container > div > form > fieldset > div > section > article.find_store_cont > article > article:nth-child(4) > div.loca_step1 > div.loca_step1_cont > ul > li:nth-child(1) > a')
        ))
    seoul_tag.click() # "서울" 버튼 클릭

    # 데이터를 저장할 리스트 초기화
    store_list = [] # 매장 이름 리스트
    addr_list = [] # 매장 주소 리스트
    lat_list = [] # 매장 위도 리스트
    lng_list = [] # 매장 경도 리스트

    # 구(gugun) 선택 버튼 로딩 대기
    WebDriverWait(driver, 5).until(EC.presence_of_all_elements_located((By.CLASS_NAME, 'set_gugun_cd_btn')))
    gu_elements = driver.find_elements(By.CLASS_NAME, 'set_gugun_cd_btn') # 구 선택 버튼들 가져오기

    # 첫 번째 구(gugun) 버튼 클릭
    WebDriverWait(driver, 5).until(
        EC.element_to_be_clickable(
            (By.CSS_SELECTOR, '#mCSB_2_container > ul > li:nth-child(1) > a')
        ))
    gu_elements[0].click() # 첫 번째 구(gugun) 클릭

    # 매장 리스트 로딩 대기
    WebDriverWait(driver, 5).until(EC.presence_of_all_elements_located((By.CLASS_NAME, 'quickResultLstCon')))

    # 페이지 소스 HTML 가져오기
    req = driver.page_source
    soup = BeautifulSoup(req, 'html.parser') # BeautifulSoup으로 HTML 파싱
    stores = soup.find('ul', 'quickSearchResultBoxSidoGugun').find_all('li') # 매장 정보가 있는 `<li>` 태그 가져오기

    # 매장 정보 추출 및 리스트에 저장
    for store in stores:
        store_name = store.find('strong').text # 매장 이름 추출
        store_addr = store.find('p').text # 매장 주소 추출
        store_addr = re.sub(r'\d{4}-\d{4}$', '', store_addr).strip() # 주소에서 전화번호 제거
        store_lat = store['data-lat'] # 위도 추출
        store_lng = store['data-long'] # 경도 추출
        store_list.append(store_name) # 리스트에 매장 이름 추가
        addr_list.append(store_addr) # 리스트에 주소 추가
        lat_list.append(store_lat) # 리스트에 위도 추가
        lng_list.append(store_lng) # 리스트에 경도 추가

    # 데이터프레임 생성
    df = pd.DataFrame({
        'store' : store_list, # 매장 이름
        'addr' : addr_list, # 매장 주소
        'lat' : lat_list, # 매장 위도
        'lng' : lng_list # 매장 경도
    })

    driver.quit() # 드라이버 종료
    return df # 데이터프레임 반환

 

starbucks_df = fetch_starbucks()
starbucks_df

-->

 

2.엑셀 파일 추출하기

starbucks_df.to_csv('starbucks_seoul.csv', index=False, encoding='utf-8-sig') #엑셀 파일로 추출

 

starbucks_seoul.zip
0.02MB

 

현재까지는 Jupyter Notebook으로 추출해봤습니다. 

 

이제부터는 collab으로 하겠습니다.

 

1. 스타벅스 파일을 import 해줍니다.

import pandas as pd

df_starbugs = pd.read_csv('/content/drive/MyDrive/KDT 시즌 4/10. 데이터분석/Data/starbucks_seoul.csv')
df_starbugs

-->

 

2.

예시 1) 

# 데이터프레임(df_starbugs)의 열 이름 변경 및 인덱스 초기화
#store, addr, lat, lng -->'지점명', '지점주소', '지점위도', '지점경도' 로 바뀜
df_starbugs = df_starbugs.set_axis(['지점명', '지점주소', '지점위도', '지점경도'], axis=1).reset_index(drop=True)

# 결과 출력
df_starbugs

 

예시 2)

#기존에 만들었던 소상공인 데이터를 불러옵니다.
df = pd.read_csv('/content/drive/MyDrive/KDT 시즌 4/10. 데이터분석/Data/소상공인시장진흥공단_상가(상권)정보_서울_202409.csv', low_memory=False)
df

-->

 

예시 3)

#이디야, 올리브영, 컴포즈커피, 빽다방, 메가커피, 메가엠지씨 shop으로 선언
shop = ['이디야', '올리브영', '컴포즈커피', '빽다방', '메가커피', '메가엠지씨']

 

예시 4)

df.info() #정보를 보여줌
-->
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 466022 entries, 0 to 466021
Data columns (total 39 columns):
 #   Column     Non-Null Count   Dtype  
---  ------     --------------   -----  
 0   상가업소번호     466022 non-null  object 
 1   상호명        466022 non-null  object 
 2   지점명        11406 non-null   object 
 3   상권업종대분류코드  466022 non-null  object 
 4   상권업종대분류명   466022 non-null  object 
 5   상권업종중분류코드  466022 non-null  object 
 6   상권업종중분류명   466022 non-null  object 
 7   상권업종소분류코드  466022 non-null  object 
 8   상권업종소분류명   466022 non-null  object 
 9   표준산업분류코드   465931 non-null  object 
 10  표준산업분류명    465931 non-null  object 
 11  시도코드       466022 non-null  int64  
 12  시도명        466022 non-null  object 
 13  시군구코드      466022 non-null  int64  
 14  시군구명       466022 non-null  object 
 15  행정동코드      466022 non-null  int64  
 16  행정동명       466022 non-null  object 
 17  법정동코드      466022 non-null  int64  
 18  법정동명       466022 non-null  object 
 19  지번코드       466022 non-null  int64  
 20  대지구분코드     466022 non-null  int64  
 21  대지구분명      466022 non-null  object 
 22  지번본번지      466022 non-null  int64  
 23  지번부번지      389662 non-null  float64
 24  지번주소       466022 non-null  object 
 25  도로명코드      465993 non-null  float64
 26  도로명        466022 non-null  object 
 27  건물본번지      465992 non-null  float64
 28  건물부번지      61598 non-null   float64
 29  건물관리번호     465993 non-null  object 
 30  건물명        221552 non-null  object 
 31  도로명주소      466022 non-null  object 
 32  구우편번호      466022 non-null  int64  
 33  신우편번호      466022 non-null  int64  
 34  동정보        0 non-null       float64
 35  층정보        322768 non-null  object 
 36  호정보        0 non-null       float64
 37  경도         466022 non-null  float64
 38  위도         466022 non-null  float64
dtypes: float64(8), int64(9), object(22)
memory usage: 138.7+ MB

 

예시 5)

# 메가커피(메가엠지씨) 데이터 필터링
# contains(): 특정 문자열 포함 여부에 따라 True, False를 반환
df[df['상호명'].str.contains('메가엠지씨', case=False, na=False)]

-->

 

예시 6)

#df 데이터프레임에서 '상호명' 열의 값이 '메가커피'라는 문자열을 포함하는 행(row)만 필터링하여 반환
df[df['상호명'].str.contains('메가커피', case=False, na=False)]

-->

 

예시 7)

#데이터프레임 df에서 '상호명' 열의 값 중 '메가커피' 또는 '메가엠지씨'라는 문자열을 포함하는 행(row)만 필터링하여 반환
df[df['상호명'].str.contains('메가커피|메가엠지씨', case=False, na=False)]

-->

 

예시 8)

df_shop = df.copy() #df_shop에 복사해줍니다.

 

예시 9)

#shop = ['이디야', '올리브영', '컴포즈커피', '빽다방', '메가커피', '메가엠지씨']
# shop = [이디야|올리브영|컴포즈커피|빽다방|메가커피|메가엠지씨]
# extract() : 특정 문자열을 포함하고 있으면 그 문자열을 반환하고, 포함하지 않으면 NaN을 반환
df_shop['상호명'] = df_shop['상호명'].str.extract('({})'.format('|'.join(shop)))
df_shop['상호명']

 

예시 10)

#df_shop[df_shop['상호명'],notna()]['상호명']
# '상호명' 열에서 결측값이 아닌 값만 선택
df_shop[df_shop['상호명'].notna()]['상호명']

-->

 

예시 11)

df_shop.info()
-->
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 466022 entries, 0 to 466021
Data columns (total 39 columns):
 #   Column     Non-Null Count   Dtype  
---  ------     --------------   -----  
 0   상가업소번호     466022 non-null  object 
 1   상호명        2179 non-null    object 
 2   지점명        11406 non-null   object 
 3   상권업종대분류코드  466022 non-null  object 
 4   상권업종대분류명   466022 non-null  object 
 5   상권업종중분류코드  466022 non-null  object 
 6   상권업종중분류명   466022 non-null  object 
 7   상권업종소분류코드  466022 non-null  object 
 8   상권업종소분류명   466022 non-null  object 
 9   표준산업분류코드   465931 non-null  object 
 10  표준산업분류명    465931 non-null  object 
 11  시도코드       466022 non-null  int64  
 12  시도명        466022 non-null  object 
 13  시군구코드      466022 non-null  int64  
 14  시군구명       466022 non-null  object 
 15  행정동코드      466022 non-null  int64  
 16  행정동명       466022 non-null  object 
 17  법정동코드      466022 non-null  int64  
 18  법정동명       466022 non-null  object 
 19  지번코드       466022 non-null  int64  
 20  대지구분코드     466022 non-null  int64  
 21  대지구분명      466022 non-null  object 
 22  지번본번지      466022 non-null  int64  
 23  지번부번지      389662 non-null  float64
 24  지번주소       466022 non-null  object 
 25  도로명코드      465993 non-null  float64
 26  도로명        466022 non-null  object 
 27  건물본번지      465992 non-null  float64
 28  건물부번지      61598 non-null   float64
 29  건물관리번호     465993 non-null  object 
 30  건물명        221552 non-null  object 
 31  도로명주소      466022 non-null  object 
 32  구우편번호      466022 non-null  int64  
 33  신우편번호      466022 non-null  int64  
 34  동정보        0 non-null       float64
 35  층정보        322768 non-null  object 
 36  호정보        0 non-null       float64
 37  경도         466022 non-null  float64
 38  위도         466022 non-null  float64
dtypes: float64(8), int64(9), object(22)
memory usage: 138.7+ MB

 

예시 12)

#데이터프레임 df_shop에서 '상호명' 열에 결측값(NaN)이 있는 행을 제거하고, 특정 열(0, 1, 14, 37, 38번째 열)만 선택한 후, 인덱스를 초기화하여 정리된 데이터프레임을 반환
df_shop = df_shop.dropna(subset=['상호명']).iloc[:, [0, 1, 14, 37, 38]].reset_index(drop=True)
df_shop

-->

 

예시 13)

# 상호명에서 '메가엠지씨' 를 '메가커피'로 변경
df_shop['상호명'] = df_shop['상호명'].str.replace('메가엠지씨', '메가커피', regex=False)
df_shop

-->

 

예시 14)

#상호명에 메가엠지씨가 포함하는지 확인
df_shop[df_shop['상호명'].str.contains('메가엠지씨', na=False)]

-->

 

예시 15)

print(df_shop.shape) # (2179, 5)
print(df_starbugs.shape) # (630, 4)

 

예시 16)

df_shop.head()

-->

 

예시 17)

df_starbugs.head()

-->

 

예시 18)

# 두 데이터프레임(df_shop, df_starbugs)을 교차 조인(cross join)하여 모든 조합 생성
df_cross = df_shop.merge(df_starbugs, how='cross')

# 결과 출력
df_cross

-->

 

 

하버사인 공식
* Haversine 공식은 구체(구면) 위의 두 점(위도와 경도로 표시됨) 사이의 최단 거리(대원 거리, great-circle distance)를 계산하는 방법입니다. 
* 이 공식은 GPS 좌표(위도와 경도)를 활용하여 지구 표면 위의 거리 계산에 널리 사용됩니다.
>

 

1. haversine 설치

#haversine 설치
!pip install haversine

 

2. haversine import 해준다

from haversine import haversine

 

예시 1)

from haversine import haversine

# 각 매장의 위치와 스타벅스 지점 간의 거리 계산
df_cross['거리'] = df_cross.apply(
    lambda x: haversine(
        [x['위도'], x['경도']],        # 매장의 위도와 경도
        [x['지점위도'], x['지점경도']], # 스타벅스 지점의 위도와 경도
        unit='m'                      # 결과 단위: 미터(m)
    ),
    axis=1  # 행 단위로 함수 적용
)

# 결과 출력
df_cross

-->

 

예시 2)

# 개별 매장과 스타벅스와의 최소 거리
df_dis = df_cross.groupby(['상호명'])['거리'].min().reset_index()
df_dis

 

예시 3)

# 각 프랜차이즈별 스타벅스와의 평균 거리
df_cross.groupby('상호명')['거리'].mean()
728x90
LIST

'LLM(Large Language Model)의 기초' 카테고리의 다른 글

6.서울시 공공자전거 실시간 대여정보  (0) 2024.12.23
5. 상권_데이터셋  (6) 2024.12.19
Matplotlib  (4) 2024.12.19
4. Online Retail 데이터셋  (1) 2024.12.18
판다스(Pandas) 2  (4) 2024.12.18