working_helen
[애플리케이션] streamlit 웹 구현 본문
1. 웹 구현
1) 사이드바 만들기
2) predict 함수
3) get_info 함수
4) 기타
2. 폐업 여부 예측 과정
3. 느낀점
1. 웹 구현
1) 사이드바 만들기
st.selectbox => 선택한 option에 따라 3가지 웹 화면 중 하나 실행
- '폐업 예측 서비스' : 생성한 예측 모델을 이용해 폐업 여부를 예측해주는 서비스 화면
- '지역별 특성' : 모델에 사용된 feature들의 행정동별 시각화를 보여주는 화면
- '예측 모델 설명' : 사용된 예측 모델에 대한 설명을 제시하는 화면
2) predict(gu, dong, lat, long) 함수
: 개업 카페 위치의 자치구명, 행정동명, 위도, 경도를 입력하면 폐업 여부를 예측해주는 함수
- encoder_info + dong_info + map_info 3가지 통합하여 input_df 생성
- 생성했던 xgboost 예측 모델을 불러와 (predict_model) 모델 실행, 예측 결과 '영업' 혹은 '폐업' 제시
feature value 출력 | st.table | 예측 모델이 사용한 input data의 feature Value를 보여줌 |
feature variable 설명 | st.expander | 예측 모델이 사용한 feature variable에 대한 설명을 제시 |
행정동 encoder | st.table | 입력한 자치구 행정도의 encoder 값 제시 |
변수중요도 출력 | st.image | 예측 모델의 변수 중요도 그래프 출력, 예측에 사용된 주요 변수가 무엇인지 확인 |
3) get_info 함수
: 모델에 필요한 input 정보를 얻는 함수
- 1단계 위경도 정보 > 확인 > 2단계 자치구 행정동 정보 > 확인 과정으로 이루어짐
- 정보가 올바르게 입력되었을 경우 버튼을 눌렸을때 predict()함수 실행, 그렇지 않으면 error 발생 경고문 출력
개업 위치 위경도 입력 | st.text_input | 위경도 숫자 입력을 string으로 받음 |
개업 위치 자치구 행정동 입력 | st.text_input | '자치구 행정동' 형태의 string 입력값 |
'폐업여부 예측하기' 클릭 버튼 | st.button |
4) 기타
streamlit 구현 기능 참고 사이트 : https://docs.streamlit.io/
streamlit 이모지 참고 사이트 : https://streamlit-emoji-shortcodes-streamlit-app-gwckff.streamlit.app/
2. 폐업 여부 예측 과정
data_df : 자치구 행정동별 정보 (train data set에서 자치구 행정동마다 1개씩만 남긴 상태)
encoding : ['시군구명', '행정동명'] encoder 정보
step 1. 입력값으로 시군구명, 행정동명, 위도, 경도 입력
step 2. 입력값을 모델의 input 형태로 변환
총 22개의 feature로 이루어진 input dataframe 생성
- encoder_info : '시군구명', '행정동명' encoder 정보 => ['행정동명_0', '행정동명_1', '행정동명_2', '행정동명_3', '행정동명_4', '행정동명_5', '행정동명_6', '행정동명_7', '행정동명_8']
- dong_info : 행정동별로 같은 값을 가지는 동별 정보 => ['소득분위', '가구수', '3년 생존율', '최근 10년 기준 평균영업기간', '임대시세', '유동인구', '방범지수']
- map_info : 개별 위치에 따른 지도 기반 정보 => ['반경500_카페개수', '반경500_지하철역개수', '반경500_정류장개수', '반경500_공공기관개수', '반경1000_대학개수']
- input_df : 위 3개의 list 합쳐서 만든 최종 input용 dataframe
step 3. input_df로 모델 실행, 예측값 얻기
최종 예측 모델 predict_model (xgboost) 불러온 후, predict_model.predict(input_df)[0]로 결과 예측
Jupyter Notebook
입력값 받기
#입력값
gu = "관악구"
dong = "신사동"
lat = 37.479461
long = 126.953032
자치구 행정동 => encoder 정보 추출¶
encoder_info = encoding.loc[(encoding["시군구명"] == gu) & (encoding["행정동명"] == dong), '행정동명_0':].to_numpy()[0]
encoder_info
array([0, 0, 0, 1, 0, 1, 0, 1, 0], dtype=int64)
자치구 행정동 => 동별 정보 추출¶
# data_df와 encoding merge
merge_df = pd.merge(encoding, data_df, on = ['행정동명_0', '행정동명_1', '행정동명_2', '행정동명_3', '행정동명_4', '행정동명_5', '행정동명_6', '행정동명_7', '행정동명_8'])
merge_df.info()
# 입력값에 해당하는 정보 뽑아내기
dong_info = merge_df.loc[(merge_df["시군구명"] == gu) & (merge_df["행정동명"] == dong),
['소득분위', '가구수', '3년 생존율', '최근 10년 기준 평균영업기간', '임대시세', '유동인구', '방범지수','상권활성화지수']].to_numpy()[0]
dong_info
array([ 1.85551981, -0.89213693, -0.13017572, -0.49217481, 1.27760308,
-0.5013057 , 0.99650417, 0.91009757])
위경도 => 개별 위치 정보 추출¶
카페 = pd.read_csv(path+'/데이터 전처리/2단계 폐영업_크롤링_최종.csv').iloc[:, 1:]
store_latitude = list(카페["위도"])
store_longitude = list(카페["경도"])
반경500_카페개수=0
for index in range(20886):
distance = haversine((lat, long), (store_latitude[index], store_longitude[index]), unit='m')
if 0 < distance and distance <= 500:
반경500_카페개수+=1
반경500_카페개수
반경500_지하철역개수
지하철 = pd.read_csv(path+'/데이터 전처리/지도기반 데이터/서울지하철_위경도.csv').iloc[:, 1:]
반경500_지하철역개수=0
sub_latitude = list(지하철["위도"])
sub_longitude = list(지하철["경도"])
for index in range(269):
distance = haversine((lat, long), (sub_latitude[index], sub_longitude[index]), unit='m')
if 0 < distance and distance <= 500:
반경500_지하철역개수+=1
반경500_지하철역개수
버스 = pd.read_csv(path + '/데이터 전처리/지도기반 데이터/서울시 버스정류소 위치정보.csv')
버스.rename(columns={'X좌표': '경도', 'Y좌표': '위도'}, inplace=True)
버스 = bus[['위도','경도']]
반경500_정류장개수=0
bus_latitude = list(버스["위도"])
bus_longitude = list(버스["경도"])
for index in range(12566):
distance = haversine((lat, long), (bus_latitude[index], bus_longitude[index]), unit='m')
if 0 < distance and distance <= 500:
반경500_정류장개수+=1
반경500_정류장개수
반경500_공공기관개수
공공기관 = pd.read_csv(path + '/데이터 전처리/지도기반 데이터/공공기관 위경도.csv').iloc[:, 1:]
반경500_공공기관개수=0
build_latitude = list(공공기관["위도"])
build_longitude = list(공공기관["경도"])
for index in range(130):
distance = haversine((lat, long), (build_latitude[index], build_longitude[index]), unit='m')
if 0 < distance and distance <= 500:
반경500_공공기관개수+=1
반경500_공공기관개수
대학 = pd.read_csv(path + '/데이터 전처리/지도기반 데이터/대학 위경도.csv').iloc[:, 1:]
반경1000_대학개수=0
univ_latitude = list(대학["위도"])
univ_longitude = list(대학["경도"])
for index in range(44):
distance = haversine((lat, long), (univ_latitude[index], univ_longitude[index]), unit='m')
if 0 < distance and distance <= 1000:
반경1000_대학개수+=1
반경1000_대학개수
map_info = [반경500_카페개수, 반경500_지하철역개수, 반경500_정류장개수, 반경500_공공기관개수, 반경1000_대학개수]
input data 꼴로 변환 : 총 22개의 feature
print(encoder_info)
print(dong_info)
print(map_info)
[0 0 0 1 0 1 0 1 0]
[ 1.85551981 -0.89213693 -0.13017572 -0.49217481 1.27760308 -0.5013057
0.99650417 0.91009757]
[121, 1, 28, 0, 0]
input_df = pd.concat([pd.DataFrame(dong_info).T, pd.DataFrame(map_info).T, pd.DataFrame(encoder_info).T], axis=1)
input_df.columns = ['소득분위', '가구수', '3년 생존율', '최근 10년 기준 평균영업기간', '임대시세', '유동인구', '방범지수', '상권활성화지수',
'반경500_카페개수', '반경500_지하철역개수', '반경500_정류장개수', '반경500_공공기관개수', '반경1000_대학개수',
'행정동명_0', '행정동명_1', '행정동명_2', '행정동명_3', '행정동명_4', '행정동명_5', '행정동명_6', '행정동명_7', '행정동명_8']
input_df
소득분위 | 가구수 | 3년 생존율 | 최근 10년 기준 평균영업기간 | 임대시세 | 유동인구 | 방범지수 | 상권활성화지수 | 반경500_카페개수 | 반경500_지하철역개수 | ... | 반경1000_대학개수 | 행정동명_0 | 행정동명_1 | 행정동명_2 | 행정동명_3 | 행정동명_4 | 행정동명_5 | 행정동명_6 | 행정동명_7 | 행정동명_8 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1.85552 | -0.892137 | -0.130176 | -0.492175 | 1.277603 | -0.501306 | 0.996504 | 0.910098 | 121 | 1 | ... | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
1 rows × 22 columns
predict_model = xgb.XGBClassifier()
predict_model.load_model(path + '/모델링/xgb_model_4')
predict_model.predict(input_df)[0]
0
3. 느낀점
항상 분석 프로젝트를 하면서 웹이나 앱 화면으로 구현해보고 싶다는 마음이 있었고, 향후 발전 과제로 서비스 구축까지 이어지면 좋겠다는 말을 많이 했었다. streamlit의 기본적인 기능만 사용하긴 했지만 이렇게 서비스 화면을 구축해본 첫 경험이라 매우 뿌듯했고, streamlit를 잘 사용한다면 앞으로 많은 활용성 높은 결과물을 낼 수 있을 것이라는 기대감이 들었다. 분석 혹은 모델 생성으로 그쳤던 이전까지의 결과물들을 한층 더 발전시킬 수 있는 기술을 습득하게 되었다고 느낌이 들었고, 내가 구현할 수 있는 것들의 범위가 확장된, 내 스킬의 스펙트럼이 더 넓어진 느낌을 받을 수 있었다.
✅ 향후 streamlit을 적극적으로 활용해 분석에서 그치지 않고 서비스까지 구현할 수 있는 프로젝트로 해나갈 수 있을 것이란 기대감, 기술 스택의 스펙트럼이 넓어진 느낌을 받았다. 또한 streamlit에서 제공하는 수많은 다른 기능들을 통해 더 정교하게 다양한 기능이 있는 웹을 구축해보고 싶다는 동기부여를 받았다.
[streamlit 학습에 참고한 유튜브 동영상]
'TAVE > 뿌스팅 project' 카테고리의 다른 글
[데이터 수집] 주소 -> 위도/경도 전환 (0) | 2023.08.23 |
---|---|
[모델링] 예측 모델 모델링 및 성능 평가 (0) | 2023.08.07 |
[데이터 전처리] 설명변수 PCA (0) | 2023.08.07 |
[데이터 전처리] Encoding 인코딩 (0) | 2023.08.07 |
[데이터 전처리] EDA 및 변수 선택 (0) | 2023.08.07 |