Toy Project
MongoDB에 데이터 저장 및 데이터 분석
JasonHan
2024. 5. 6. 00:01
몽고 DB에 데이터 저장하기
여행/데이터 카테고리에 해당하는 인허가 데이터 수집 데이터 분석
- 데이터 확인
import pandas as pd
import os
base_path = 'C:/Users/Jason/Downloads/output/essential_csv'
csv_files = os.listdir(base_path)
common_columns = ['개방자치단체코드', '관리번호', '인허가일자', '인허가취소일자', '영업상태코드', '영업상태명', '상세영업상태코드', '상세영업상태명', '폐업일자', '휴업시작일자', '휴업종료일자', '재개업일자',
'전화번호', '소재지면적', '소재지우편번호', '지번주소', '도로명주소', '도로명우편번호', '사업장명', '최종수정일자', '데이터갱신구분', '데이터갱신일자', '업태구분명', '좌표정보(X)', '좌표정보(Y)']
differ_dict = {}
for csv_f in csv_files:
try:
df = pd.read_csv(os.path.join(base_path, csv_f), encoding='euc-kr')
except UnicodeDecodeError:
try:
df = pd.read_csv(os.path.join(base_path, csv_f), encoding='utf-8')
except UnicodeDecodeError:
df = pd.read_csv(os.path.join(base_path, csv_f), encoding='cp949')
print(csv_f)
print(df[common_columns].info())
for i in list(df.columns):
if i not in common_columns:
if i not in differ_dict:
differ_dict[i] = 1
else:
differ_dict[i] += 1
differ_dict
공통 컬럼
개방자치단체코드, 관리번호, 인허가일자, 인허가취소일자, 영업상태코드, 영업상태명, 상세영업상태코드, 상세영업상태명, 폐업일자, 휴업시작일자, 휴업종료일자, 재개업일자, 전화번호, 소재지면적, 소재지우편번호, 지번주소, 도로명주소, 도로명우편번호, 사업장명, 최종수정일자, 데이터갱신구분, 데이터갱신일자, 업태구분명, 좌표정보(X), 좌표정보(Y)
- 공통 컬럼 - Nan 값 컬럼
- 인허가취소일자, 휴업시작일자, 휴업종료일자, 재개업일자
- 공통 컬럼 - 일부 Nan 값 컬럼
- 전화번호, 소재지면적, 소재지우편번호, 도로명우편번호, 업태구분명
- 공통 컬럼 분석
- 다른 정보 데이터와 연동 가능성 있는 데이터
- 개방자치단체코드, 관리번호, 영업상태코드, 상세영업상태코드
- 실질적인 장소 데이터
- 영업상태명, 지번주소, 도로명주소, 사업장명, 좌표정보(X), 좌표정보(Y), 전화번호, 업태구분명
- 데이터 최신 화 등 상태 확인 용 데이터
- 최종수정일자, 데이터갱신구분, 데이터갱신일자
- 기타 활용 데이터
- 인허가일자, 상세영업상태, 폐업일자, 소재지면적, 소재지우편번호, 도로명우편번호
- 다른 정보 데이터와 연동 가능성 있는 데이터
기타 컬럼
- 공통 1개 : 점포구분명, 승려수, 신도수, 창립연대, 유래연혁, 지정취소, 지정취소일자, 지정취소사유, 전통사찰명
- 공통 2개 : 건물지상층수, 건물지하층수, 사용시작지상층, 사용끝지상층, 사용시작지하층, 사용끝지하층, 한실수, 양실수, 욕실수, 발한실여부, 조건부허가신고사유, 조건부허가시작일자, 조건부허가종료일자, 세탁기수, 회수건조수, 침대수
- 공통 3개 : 공사립구분명, 보험가입여부코드, 지도자수, 건축물동수, 건축물연면적, 회원모집총인원, 세부업종명, 법인명, 통로너비, 조명시설조도, 노래방실수, 청소년실수, 비상계단여부, 비상구여부, 자동환기여부, 청소년실여부, 특수조명여부, 방음시설여부, 비디오재생기명, 조명시설유무, 음향시설여부, 편의시설여부, 소방시설여부, 총게임기수, 기존게임업외업종명, 제공게임물명, 공연장형태구분명, 품목명, 최초등록시점
- 공통 4개 : 영업장주변구분명, 등급구분명, 급수시설구분명, 총인원, 본사종업원수, 공장사무직종업원수, 공장판매직종업원수, 공장생산직종업원수, 보증액, 월세액, 시설총규모, 전통업소지정번호, 전통업소주된음식, 홈페이지
- 공통 6개 : 보험기관명, 객실수, 건축연면적, 영문상호명, 영문상호주소, 선박총톤수, 선박척수, 선박제원, 무대면적, 기념품종류, 회의실별동시수용인원, 놀이기구수내역, 놀이시설수, 방송시설유무, 발전시설유무, 의무실유무, 안내소유무, 기획여행보험시작일자, 기획여행보험종료일자, 자본금, 보험시작일자, 보험종료일자, 부대시설내역, 시설규모, 위생업태명, 남성종사자수, 여성종사자수, 건물소유구분명, 다중이용업소여부
- 공통 8개 : 좌석수
- 공통 9개 : 문화사업자구분명, 지역구분명, 총층수, 주변환경명, 제작취급품목내용, 건물용도명, 지상층수, 지하층수, 시설면적
- 공통 12개 : 문화체육업종명
⇒ 일부 필요한 데이터는 Bold 표시하였다.
결론적으로, 대체로 필요 없는 데이터가 많으나 NoSQL에 저장할 것이므로, 굳이 공통이 아닌 데이터에 대해서 컬럼 수를 맞추거나 데이터를 잘라낼 필요는 없다!
MongoDB에 데이터 입력하기
폐업 된 장소 데이터는 제외
- .폐업 데이터를 제외하니 아래 두 장소 데이터의 row수가 0 개가 되어 제외했다.
- 서울시_노원구_일반야영장업_인허가_정보.csv, 서울시_노원구_종합체육시설업_인허가_정보.csv
- 폐업 장소를 제외한 데이터 입력 및 입력 시간을 기록하기 위한 ‘insertdt’ 컬럼 추가
from pymongo import MongoClient
import pandas as pd
import os, datetime
import json
with open('~/test_credential/mongo_info.json') as file:
data = json.load(file)
# MongoDB 서버 IP 주소
HOST = data['server_ip']
# MongoDB 포트 번호
PORT = data['server_port']
# 사용자 이름
USERNAME = data['user_id']
# 비밀번호
PASSWORD = data['user_pw']
# 데이터베이스 이름
DATABASE = 'admin'
# MongoDB 연결 문자열
uri = f"mongodb://{USERNAME}:{PASSWORD}@{HOST}:{PORT}/{DATABASE}"
# 데이터베이스 명
selected_db = 'place_info'
# 컬렉션 명
selected_collection = 'shop'
# MongoDB에 연결
client = MongoClient(uri)
# 데이터베이스와 컬렉션 선택
db = client[selected_db]
collection = db[selected_collection]
base_path = '~/output/essential_csv'
csv_files = os.listdir(base_path)
# CSV 파일 순회
for csv_f in csv_files:
# CSV 파일을 읽어서 DataFrame으로 변환
try:
df = pd.read_csv(os.path.join(base_path, csv_f), encoding='euc-kr')
except UnicodeDecodeError:
try:
df = pd.read_csv(os.path.join(base_path, csv_f), encoding='utf-8')
except UnicodeDecodeError:
df = pd.read_csv(os.path.join(base_path, csv_f), encoding='cp949')
# 영업상태명이 폐업인 데이터는 제외
df = df[df['영업상태명'] != '폐업']
print(csv_f, len(df))
# DataFrame이 비어있으면 다음 CSV 파일로 넘어감
if len(df) == 0:
continue
# DataFrame에 "insertdt" 컬럼 추가
df['insertdt'] = datetime.datetime.now()
# DataFrame을 딕셔너리 리스트로 변환
data = df.to_dict(orient='records')
# 데이터를 MongoDB에 삽입
collection.insert_many(data)
- 데이터 입력 확인

데이터 전처리 및 DB 입력 결과
- 총 4622개의 장소 데이터가 추가되었다.
- 노원구 전체에서 여행, 데이트 등의 활동과 관련 있는 데이터로는 모수가 너무 부족하다.
업태 종류
- 전체 데이터 중 어떤 업태 종류가 있는지 확인
한식 : 1538, nan : 592, 기타 : 496, 호프/통닭 : 470, 분식 : 315, 일식 : 198, 제과점영업 : 155, 경양식 : 146, 중국식 : 139, 통닭(치킨) : 94, 감성주점 : 62, 식육(숯불구이) : 55, 기타식품판매업 : 51, 단란주점 : 37, 외국음식전문점(인도,태국등) : 36, 까페 : 35, 패스트푸드 : 27, 횟집 : 20, 여관업 : 19, 김밥(도시락) : 15, 정종/대포집/소주방 : 15, 뷔페식 : 14, 라이브카페 : 13, 패밀리레스트랑 : 11, 공동탕업 : 8, 그 밖의 대규모점포 : 8, 공동탕업+찜질시설서비스영업 : 8, 구분없음 : 7, 키즈카페 : 5, 찜질시설서비스영업 : 4, 냉면집 : 4, 일반호텔 : 4, 여인숙업 : 4, 대형마트 : 3, 백화점 : 3, 복합쇼핑몰 : 3, 쇼핑센터 : 2, 복어취급 : 2, 관광호텔 : 1, 목욕장업 : 기타 : 1, 탕류(보신용) : 1, 시장 : 1
- 업태 조회 소스코드
pipeline = [
{"$group": {"_id": "$업태구분명", "count": {"$sum": 1}}},
{"$sort": {"count": -1}}
]
result = collection.aggregate(pipeline)
for doc in result:
print(doc["_id"], doc["count"])
- Nan 데이터인 600건 가량을 제외하고 대부분 식당이 차지하고 있다. 그 중 한식집, 치킨집(호프집), 분식집이 가장 많은 것으로 확인된다.
건물 지상/하 층 수
- 데이터 중 건물 지상 층 수 데이터 집계
- None : 4573, nan : 34, 0층 : 6, 8층 : 3, 6층 : 2, 2층 : 2, 5층 : 1, 1층 : 1
- 데이터 중 건물 지하 층 수 데이터 집계
- None : 4573, nan : 34, 1층 : 9, 0층 : 6
- 생각보다 의미 없는 데이터가 너무 많다.
결론
- 장소 데이터의 연관성 분석보다는 초기 데이터 수집 및 기능 개발 가능성을 보는 것이므로, 교통 관련 데이터 등 추가 데이터 수집을 바로 진행한다.
- 다음 스텝은 추가 데이터 수집 후 교통, 루트, 장소 등을 지도에 표현하고, 루트를 짜는 알고리즘을 개발하는 것에 초점을 둔다.