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 값 컬럼
    • 전화번호, 소재지면적, 소재지우편번호, 도로명우편번호, 업태구분명
  • 공통 컬럼 분석
    1. 다른 정보 데이터와 연동 가능성 있는 데이터
      • 개방자치단체코드, 관리번호, 영업상태코드, 상세영업상태코드
    2. 실질적인 장소 데이터
      • 영업상태명, 지번주소, 도로명주소, 사업장명, 좌표정보(X), 좌표정보(Y), 전화번호, 업태구분명
    3. 데이터 최신 화 등 상태 확인 용 데이터
      • 최종수정일자, 데이터갱신구분, 데이터갱신일자
    4. 기타 활용 데이터
      • 인허가일자, 상세영업상태, 폐업일자, 소재지면적, 소재지우편번호, 도로명우편번호

기타 컬럼

  • 공통 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)

 

  • 데이터 입력 확인

MongoDB Compass로 데이터 입력 확인

 


데이터 전처리 및 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
  • 생각보다 의미 없는 데이터가 너무 많다.

결론

  • 장소 데이터의 연관성 분석보다는 초기 데이터 수집 및 기능 개발 가능성을 보는 것이므로, 교통 관련 데이터 등 추가 데이터 수집을 바로 진행한다.
  • 다음 스텝은 추가 데이터 수집 후 교통, 루트, 장소 등을 지도에 표현하고, 루트를 짜는 알고리즘을 개발하는 것에 초점을 둔다.