7. 커피프랜차이즈 이점 전략
2024. 12. 23. 13:40ㆍLLM(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') #엑셀 파일로 추출
현재까지는 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 |