{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# **MDX 데이터 분석하기**\n", "https://pypi.org/project/mdict-utils/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **1 레시피 SQlite 데이터 불러오기**\n", "작업한 내용을 대상으로 중분류 내용 추가하기\n", "- 법률, 식품, 자동차 등 중분류 내용이 당장은 필요가 없어 보인다.\n", "- 작업을 진행하면서 필요하면 추가하기" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(908,\n", " '가오리조림 가오리찜 가자미야채탕 가자미찜 가지냉채 가지불고기 가지선 가지오징어냉채 가지조림 가지회 각색두부전골 각색버섯덮밥 간장 갈비구이 갈비구이찜 갈비찜 갈비탕 감자가자미구이 감자갈비탕 감자고로케 감자그라땡 감자대구오븐구이 감자두부조림 감자막튀김 감자맑은국 감자밥 감자베이컨볶음 감자보트샐러드 감자볶음 감자볶음밥 감자볶음밥치즈구이 감자부침 감자새우그라땡 감')" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 레시피 데이터베이스 불러오기\n", "from muyong.nlp import mdx_to_df\n", "df = mdx_to_df('backup/recipe.db')\n", "menus = df.entry.values.tolist()\n", "len(menus), \" \".join(menus)[:200]" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(88636, 10574)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "food_recipes = df.paraphrase.values.tolist()\n", "result = []\n", "import re\n", "for _ in food_recipes:\n", " result += re.findall(\"[가-힣]+\", _)\n", "len(result), len(list(set(result)))" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9514" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from konlpy.tag import Hannanum, Okt, Mecab, Komoran\n", "food_text = \" \".join(list(set(result)))\n", "food_tokens = Mecab().nouns(food_text)\n", "len(food_tokens)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2626" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from nltk import Text\n", "food_tokens_text = Text(food_tokens)\n", "food_nouns = [_[0] for _ in food_tokens_text.vocab().most_common()]\n", "len(food_nouns)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **2 식재료 관련 데이터 찾기**\n", "[전은경 맛을 표현하는 단어 (2003)](https://m.blog.naver.com/PostView.nhn?blogId=seongho0805&logNo=150048557298&proxyReferer=https%3A%2F%2Fwww.google.com%2F)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "import pickle\n", "with open('data/nerDict.pk', 'rb') as handle:\n", " nerDict = pickle.load(handle)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[('명사', ['1', '몹시 가문 여름 하늘.']), ('명사', ['2', '몹시 가문 날씨.\\r\\n'])],\n", " [('명사',\n", " ['1', '겨울의 차가운 하늘.', '¶ 뿌옇게 흐렸던 한천에서 희끗희끗 눈발이 날리기 시작했다.≪이원규, 훈장과 굴레≫']),\n", " ('명사', ['2', ' =한절02.\\r\\n'])],\n", " [('명사', ['명사', '찬물이 솟는 샘.\\r\\n'])],\n", " [('명사', ['명사', '땀을 흘리며 헐떡거림.', '한천-하다01(汗喘--) [한ː---]']),\n", " ('동사', ['동사', '땀을 흘리며 헐떡거리다.\\r\\n'])],\n", " [('명사', ['명사', ' =우무01. ‘우무01’, ‘우뭇가사리’로 순화.\\r\\n'])],\n", " [('명사', ['명사', '『인명』', '‘이재04’의 호.\\r\\n'])]]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "query = \"한천\" # 원문 내용의 확인\n", "q_data = nerDict[nerDict.Text == query].Data.values.tolist()\n", "q_data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# **메뉴 데이터 N-Gram 분석**\n", "\n", "## **1 N-Gram 데이터**\n", "**itemIndexTemp** 를 활용하며 고유단어 찾기" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "689" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 명사 추출사전 데이터 호출\n", "with open(\"data/nouns_tokens.txt\", \"r\") as f:\n", " valid_token = f.read()\n", "valid_token = valid_token.split(\",\")\n", "len(valid_token)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(2880, '청경채겉절이 봉추찜닭 버섯파프리카잡채 매콤돈사태찜 날치알참치야채비빔밥')" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 분석할 메뉴데이터 호출\n", "import pandas as pd # 분석을 의뢰할 메뉴 데이터 [list]\n", "menus_muyong = pd.read_csv('data/menu_muyong.csv', encoding='ms949')\n", "menus_muyong = menus_muyong.dropna(subset=['메인1', '메인2'])\n", "menus_muyong = menus_muyong.fillna('') # NaN 값을 지운다\n", "tokens = [] # DataFrame 에서 Token List 추출\n", "for _ in menus_muyong.columns[4:]:\n", " tokens += menus_muyong[_].values.tolist()\n", "\n", "import re\n", "from nltk import Text\n", "menus_muyong = re.findall(r\"[가-힣]+\", \" \".join(tokens))\n", "menus_muyong = list(set(menus_muyong))\n", "len(menus_muyong), \" \".join(menus_muyong[:5])" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "원본내용: 수제하트맛살계란전\n" ] }, { "data": { "text/plain": [ "['맛살', '계란', '전']" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 메뉴 명사추출기\n", "menu_token = menus_muyong[1828]\n", "print(\"원본내용:\", menu_token)\n", "from muyong.nlp import food_nouns\n", "food_nouns(menu_token, valid_token)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **2 만개의 레시피 활용**\n", "긴 제목에서 레시피만 추출/ 나머지 구분하기" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['호불호 없는 토마토파스타는 역시 ~! 토마토냉파스타 ★',\n", " '달콤 촉촉 달걀 푸딩 만들기, 만드는 법 ( 부드러운 달걀 요리 기본 원리 )',\n", " '손이가요 손이가~~자꾸 손이 가는 [가지전]']" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "menus_man = pd.read_csv(\"data/menu_1000recipe.csv\", sep=\"|\")\n", "menus_man = menus_man.fillna('')\n", "menus_man = menus_man.Menu.values.tolist()\n", "menus_man[:3]" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "원본내용: 아이볶음밥 김치볶음밥 카레가루를 넣어봐요!\n" ] }, { "data": { "text/plain": [ "['볶음밥', '김치', '카레']" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 메뉴 명사추출기\n", "menu_token = menus_man[4528]\n", "print(\"원본내용:\", menu_token)\n", "from muyong.nlp import food_nouns\n", "food_nouns(menu_token, valid_token)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

\n", "# **Naver API 로 Unique Token 묶음 분석**\n", "메뉴의 이름들 중 대표성 높은 메뉴들 찾기" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **1 레시피 데이터 특징찾기**\n", "잡일보단 **머신러닝 분석** 으로 우선 **모델** 만들기 (30일 발표용)\n", "1. 구내식당은 대략 **2,300 개로** 추출 된다\n", "1. 만개의 레시피는 50,000개로 특징이 추출\n", "1. 우선은 **2,300 개** 로 **모델 사이트를 우선 만들어서 9월초 시연모델** 만들기" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2880 2336\n", "file saved\n", "CPU times: user 658 ms, sys: 4.43 ms, total: 663 ms\n", "Wall time: 662 ms\n" ] } ], "source": [ "%%time\n", "# # 10,000 개 레시피 분석\n", "# result = [\"_\".join(sorted(food_nouns(menu, valid_token))) \n", "# for menu in menus_man \n", "# if \"_\".join(sorted(food_nouns(menu, valid_token)))]\n", "\n", "# result = list(sorted(set(result)))\n", "# print(len(menus_man), len(result))\n", "# with open(\"backup/menus_unique_tokens_10000.txt\", 'w') as f:\n", "# f.write(\",\".join(result))\n", "# print(\"file saved\")\n", "\n", "# Muyong 레시피 분석\n", "result = [\"_\".join(sorted(food_nouns(menu, valid_token))) \n", " for menu in menus_muyong \n", " if \"_\".join(sorted(food_nouns(menu, valid_token)))]\n", "\n", "result = list(sorted(set(result)))\n", "print(len(menus_muyong), len(result))\n", "with open(\"backup/menus_unique_tokens_muyong.txt\", 'w') as f:\n", " f.write(\",\".join(result))\n", "print(\"file saved\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **2 Sqlite3 Open API 수집 결과 확인하기**\n", "특징을 대상으로 네이버 블로그 데이터 대상 수집하기\n", "1. 저장결과를 Sqlite3 로 저장하기\n", "1. 안정적인 작업을 수행하도록 잘 구성하기" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " title data\n", "6 가쓰오국_어묵_유부 []\n", "7 가쓰오국_유부 []\n", "8 가쓰오국_유부_팽이 []\n", "136 감자_미트볼_알감_자미_조림 []\n", "1209 돈육_불고기_육간장 []\n", "1362 떡_물부추_해물 []\n", "1587 무침_물부추_콩나물 []\n", "1666 물부추_전_해물 []\n", "2209 오징어탕_탕수 []\n", "CPU times: user 14.1 s, sys: 1.97 s, total: 16.1 s\n", "Wall time: 17.9 s\n" ] } ], "source": [ "%%time\n", "import os, sqlite3, json, time\n", "con = sqlite3.connect(\"backup/food_api_muyong.db\")\n", "\n", "import pandas as pd\n", "df = pd.read_sql(\"select * from 'foods'\", con, index_col=None).drop('index', axis=1)\n", "con.close()\n", "food_links = df.data.values.tolist()\n", "df.data = [json.loads(_) for _ in food_links] # json 디코딩\n", "index_err = [no for no,_ in enumerate(df.data.values.tolist()) if len(_) == 0]\n", "print(df.iloc[index_err, :])" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['foods']\n", " title data\n", "20910 곰_배추찜_양배추 []\n", "CPU times: user 29.2 s, sys: 3.41 s, total: 32.6 s\n", "Wall time: 35.3 s\n" ] } ], "source": [ "%%time\n", "import os, sqlite3, json, time\n", "con = sqlite3.connect(\"backup/food_api_10000_01.db\")\n", "tables = [_[0] for _ in con.execute(\"SELECT name FROM sqlite_master WHERE type='table';\")]\n", "print(tables) # 테이블 이름의 확인\n", "\n", "import pandas as pd\n", "df = pd.read_sql(\"SELECT * FROM '{}'\".format(tables[0]), con, index_col=None).drop('index', axis=1)\n", "con.close()\n", "\n", "# 내부 Json String 을 Decoding\n", "food_links = df.data.values.tolist()\n", "df.data = [json.loads(_) for _ in food_links] # json 디코딩\n", "index_err = [no for no,_ in enumerate(df.data.values.tolist()) if len(_) == 0]\n", "print(df.iloc[index_err, :]) # 자료수집시 오류가 난 Key Word 선별" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# 수집값이 없는 인덱스를 새로 수정하기 \n", "# Token Index 값이 유용한지를 Naver OpenAPI 결과값으로 구분하는 방법도 유용할 듯!!\n", "index_err = [no for no,_ in enumerate(df.data.values.tolist()) if len(_) == 0]\n", "token_temp_list = [\"가쓰오_어묵_유부\",\"가쓰오_유부\",\"가쓰오_유부_팽이\",\"감자_미트볼_알감자_조림\",\\\n", " \"돈육_불고기_간장\",\"떡_부추_해물\",\"무침_부추_콩나물\",\"부추_전_해물\",\"오징어_탕수\"]\n", "\n", "for no, i in enumerate(index_err):\n", " df.iloc[i, [0]] = token_temp_list[no]" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 9/9 [00:23<00:00, 2.60s/it]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 551 ms, sys: 67.8 ms, total: 619 ms\n", "Wall time: 23.4 s\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "%%time\n", "from muyong.naver import get_blog_list\n", "from tqdm import tqdm\n", "result = {}\n", "for _ in tqdm(token_temp_list):\n", " temp = []\n", " query_token = _+\"_만들기\"\n", " for i in range(1, 500, 100):\n", " temp += get_blog_list(query_token, i)['items']\n", " time.sleep(.3)\n", " result[_] = temp" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "save is done\n" ] } ], "source": [ "for no, i in enumerate(index_err):\n", " df.iloc[i, 1] = result[token_temp_list[no]]\n", " \n", "import pickle\n", "with open('data/naver_key_list.pk', 'wb') as handle:\n", " pickle.dump(df, handle, protocol=pickle.HIGHEST_PROTOCOL)\n", "print(\"save is done\")" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['가쓰오_어묵_유부',\n", " '가쓰오_유부',\n", " '가쓰오_유부_팽이',\n", " '감자_미트볼_알감자_조림',\n", " '돈육_불고기_간장',\n", " '떡_부추_해물',\n", " '무침_부추_콩나물',\n", " '부추_전_해물',\n", " '오징어_탕수']" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# with open(\"menus_unique_token.txt\", \"r\") as f:\n", "with open(\"data/nouns_tokens.txt\", \"r\") as f:\n", " word_tokens = f.read().split(\",\")\n", "\n", "# get_blog_list(\"가슴살_닭_매콤_볶음_우동\"+\"_만들기\", 101)[\"items\"][:2]\n", "# len(word_tokens), word_tokens[1000]\n", "list(result.keys())" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "500" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "len(result[list(result.keys())[0]])" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 9/9 [00:18<00:00, 2.04s/it]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 1.53 s, sys: 272 ms, total: 1.8 s\n", "Wall time: 18.3 s\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
titledata
0오징어_탕수[{\"title\": \"[\\ub3c4\\uc2dd\\ub2f9]<b>\\ud0d5\\uc21...
\n", "
" ], "text/plain": [ " title data\n", "0 오징어_탕수 [{\"title\": \"[\\ub3c4\\uc2dd\\ub2f9]\\ud0d5\\uc21..." ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%time\n", "import pandas as pd\n", "from tqdm import tqdm\n", "from muyong.naver import get_blog_list\n", "import time, json, os, sqlite3\n", "file_db = \"foods.db\"\n", "\n", "token_temp_list = [\"가쓰오_어묵_유부\",\"가쓰오_유부\",\"가쓰오_유부_팽이\",\"감자_미트볼_알감자_조림\",\\\n", " \"돈육_불고기_간장\",\"떡_부추_해물\",\"무침_부추_콩나물\",\"부추_전_해물\",\"오징어_탕수\"]\n", "\n", "for _ in tqdm(token_temp_list):\n", " # web link 목록 수집하기\n", " result, temp = [], []\n", " query_token = _+\"_만들기\"\n", " for i in range(1, 500, 100):\n", " temp += get_blog_list(query_token, i)['items']\n", " time.sleep(.3)\n", " result.append([_, temp])\n", " \n", " # sqlite3 저장하기 (단어별 결과를 Json으로 저장 (list는 저장시 오류))\n", " df = pd.DataFrame(result)\n", " df.columns = ['title', 'data']\n", " df.data = [ json.dumps(_) for _ in df.data ]\n", " con = sqlite3.connect(file_db)\n", " df.to_sql('foods', con, if_exists='append')\n", " con.commit()\n", " time.sleep(.1)\n", " \n", "df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **4 링크 url 데이터만 저장하기**\n", "**API 수집결과 중 Link Url** 만 저장하기" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
titledata
0가슴살_계란_닭_장조림[{'title': '부드러운 닭<b>가슴살</b> <b>장조림</b> <b>만들기...
1가슴살_굴소스_닭_볶음밥[{'title': '수비드 닭<b>가슴살</b> 요리 : 돈까스 &amp; <b>...
2가슴살_닭_라이스_카레[{'title': '닭의품격 초간편 냉동닭<b>가슴살</b> <b>카레</b><b...
\n", "
" ], "text/plain": [ " title data\n", "0 가슴살_계란_닭_장조림 [{'title': '부드러운 닭가슴살 장조림 만들기...\n", "1 가슴살_굴소스_닭_볶음밥 [{'title': '수비드 닭가슴살 요리 : 돈까스 & ...\n", "2 가슴살_닭_라이스_카레 [{'title': '닭의품격 초간편 냉동닭가슴살 카레\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
titledata
0가슴살_계란_닭_장조림[{'title': '부드러운 닭<b>가슴살</b> <b>장조림</b> <b>만들기...
1가슴살_굴소스_닭_볶음밥[{'title': '수비드 닭<b>가슴살</b> 요리 : 돈까스 &amp; <b>...
2가슴살_닭_라이스_카레[{'title': '닭의품격 초간편 냉동닭<b>가슴살</b> <b>카레</b><b...
3가슴살_닭_매콤_볶음_우동[{'title': '닭<b>가슴살</b> <b>매콤</b> <b>볶음</b><b>...
4가슴살_닭_볶음밥_파인애플[{'title': '닭<b>가슴살</b>캔햄 치팸 <b>파인애플</b> <b>볶음...
5가슴살_닭_샐러드[{'title': '닭<b>가슴살</b> 샌드위치 <b>만들기</b> <b>샐러드...
6가쓰오_어묵_유부[{'title': '참치<b>유부</b>초밥 <b>가쓰오</b>부시볶음우동 <b>...
7가쓰오_유부[{'title': '참치<b>유부</b>초밥 <b>가쓰오</b>부시볶음우동 <b>...
8가쓰오_유부_팽이[{'title': '<b>유부</b>초밥 맛있게 만드는 법, 냉면과 <b>유부</...
9가오리_무침_회[{'title': '<b>가오리</b>요리- 명절에 손님맞이 밑반찬<b>만들기</...
10가오리_미나리_초무침_회[{'title': '<b>가오리</b> <b>초무침</b>, <b>가오리</b>회...
11가자미_강정[{'title': '매콤새콤달콤 깐풍 <b>가자미</b><b>강정</b> <b>만...
12가자미_강정_파채[{'title': '삼겹살튀김<b>강정</b> 만드는 법바쁜 맛있는 집밥&gt; ...
13가자미_구이[{'title': '에어프라이어 <b>가자미</b><b>구이</b> 맛있게 굽는법...
14가자미_구이_카레[{'title': '<b>가자미</b> <b>카레</b><b>구이</b>, 아이 ...
15가자미_유린기[{'title': '색다른생선요리 <b>가자미</b> <b>유린기</b> <b>만...
16가자미_칠리소스[{'title': '아기반찬 : <b>칠리소스</b> 닭가슴살 레시피(18,19개...
17가자미_카레_튀김[{'title': '바삭한 <b>가자미</b> <b>카레</b><b>튀김</b> ...
18가자미_튀김[{'title': '뉴질랜드 타우랑가에서 <b>가자미</b><b>튀김</b> <b...
19가자미조림[{'title': '<b>가자미조림</b> <b>만들기</b> <b>가자미</b>...
\n", "" ], "text/plain": [ " title data\n", "0 가슴살_계란_닭_장조림 [{'title': '부드러운 닭가슴살 장조림 만들기...\n", "1 가슴살_굴소스_닭_볶음밥 [{'title': '수비드 닭가슴살 요리 : 돈까스 & ...\n", "2 가슴살_닭_라이스_카레 [{'title': '닭의품격 초간편 냉동닭가슴살 카레가슴살 매콤 볶음...\n", "4 가슴살_닭_볶음밥_파인애플 [{'title': '닭가슴살캔햄 치팸 파인애플 볶음...\n", "5 가슴살_닭_샐러드 [{'title': '닭가슴살 샌드위치 만들기 샐러드...\n", "6 가쓰오_어묵_유부 [{'title': '참치유부초밥 가쓰오부시볶음우동 ...\n", "7 가쓰오_유부 [{'title': '참치유부초밥 가쓰오부시볶음우동 ...\n", "8 가쓰오_유부_팽이 [{'title': '유부초밥 맛있게 만드는 법, 냉면과 유부가오리요리- 명절에 손님맞이 밑반찬만들기가오리 초무침, 가오리회...\n", "11 가자미_강정 [{'title': '매콤새콤달콤 깐풍 가자미강정 만...\n", "12 가자미_강정_파채 [{'title': '삼겹살튀김강정 만드는 법바쁜 맛있는 집밥> ...\n", "13 가자미_구이 [{'title': '에어프라이어 가자미구이 맛있게 굽는법...\n", "14 가자미_구이_카레 [{'title': '가자미 카레구이, 아이 ...\n", "15 가자미_유린기 [{'title': '색다른생선요리 가자미 유린기 만...\n", "16 가자미_칠리소스 [{'title': '아기반찬 : 칠리소스 닭가슴살 레시피(18,19개...\n", "17 가자미_카레_튀김 [{'title': '바삭한 가자미 카레튀김 ...\n", "18 가자미_튀김 [{'title': '뉴질랜드 타우랑가에서 가자미튀김 가자미조림 만들기 가자미..." ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.head(20)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## result = []\n", "from tqdm import tqdm\n", "for datum in tqdm(df.data.values.tolist()):\n", " temp = []\n", " for _ in datum: # 500개 개별확인\n", " if _['link'].find(\"https://blog.naver.com/\") != -1:\n", " temp.append(_['link'])\n", " elif len(_) < 3:\n", " print(\"데이터가 없습니다\"); pass\n", " result.append(\"|\".join(temp))\n", "df.data = result\n", "df.to_csv('data/naver_links_muyong.csv', index=None)\n", "df.head()" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[369, 453, 880, 914]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "err_index = [no for no, _ in enumerate(df.data) if len(_.split('|')) < 10]\n", "err_index" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((2335, 2), (2331, 2))" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_sum = df.drop(err_index, axis=0).reset_index(drop=True)\n", "df_sum.to_csv(\"data/naver_links_muyong.csv\", index=None)\n", "df.shape, df_sum.shape" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "from tqdm import tqdm\n", "from muyong.naver import get_blog_list\n", "def error_api(token_list):\n", " for _ in tqdm(token_list):\n", " # web link 목록 수집하기\n", " result, temp = [], []\n", " query_token = _+\"_만들기\"\n", " for i in range(1, 500, 100):\n", " temp += get_blog_list(query_token, i)['items']\n", " time.sleep(.3)\n", " result.append([_, temp])\n", " return result" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "token_temp_list = [\"계란찜_알새우\", \"고추_마늘_무침\", \"깐풍_어묵\", \"깻잎_볶음_나물\"]\n", "error_data = error_api(token_temp_list)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "487" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(df.data[0].split('|'))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Today\n", "# 단어 Token 을 나열된 순서대로 정리하여 문법구조 분석 알고리즘 적용\n", "# CFG 와 유사한 방식으로 불필요한 단어 및 묶음 정리하기\n", "# 묶음 기준을 설정한 뒤, 크롤링을 통해 단어별 문서 300개를 수집 분석하여 연관단어 찾기" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "명엽채(명태채)/청포북(녹두묵)\n", "\n", "1. 석박지/무석박지\n", "\n", "```\n", "마요 => 마요네즈\n", "소시지 => 소세지\n", "꺳잎 => 깻잎\n", "게란 => 계란\n", "배춧 => 배추\n", "불낙 => 낙지\n", "콘 => 옥수수\n", "돈 => 돼지\n", "탕수 => 탕수육\n", "우무 => 우묵\n", "중국식/\n", "한국식/\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

\n", "# **Naver Post Detail Crawling**\n", "메뉴의 이름들 중 대표성 높은 메뉴들 찾기\n", "\n", "## **1 수집결과 살펴보기**\n", "Sqlite 결과를 보다 활용하기 쉽게 저장하기" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# import pandas as pd\n", "# links_org = pd.read_csv('backup/naver_link_temp.csv')\n", "# links_org = links_org.fillna('')\n", "\n", "# import sqlite3\n", "# conn = sqlite3.connect(\"backup/naver.db\")\n", "# df = pd.read_sql('SELECT * FROM \"foods\"', conn, index_col=None).drop('index', axis=1)\n", "# conn.close()\n", "# df.columns = links_org.columns\n", "# df.title = links_org.title[:df.shape[0]].tolist()\n", "# df.to_csv(\"data/naverPost2.csv\", index=None)\n", "# df.head(2)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "# import pandas as pd\n", "# from glob import glob\n", "# file_list = glob(\"data/naverPost*.*\")\n", "# result = []\n", "# for _ in file_list:\n", "# result.extend(pd.read_csv(_).values.tolist())\n", "\n", "# df = pd.DataFrame(result)\n", "# df.columns = ['Query', 'Posts']\n", "# df.to_csv(\"data/naverPost.csv\", index=None)\n", "# df.head(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# **Naver Post Detail Crawling**\n", "메뉴의 이름들 중 대표성 높은 메뉴들 찾기\n", "\n", "## **1 수집결과 살펴보기**\n", "Sqlite 결과를 보다 활용하기 쉽게 저장하기" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((2333, 2),\n", " 100,\n", " Query Posts\n", " 0 가슴살_계란_닭_장조림 반찬 볶음 조림.부드러운 닭가슴살 장조림 만들기.베리츄..2017.9.1.22 32...\n", " 1 가슴살_굴소스_닭_볶음밥 아임닭 7기 종료.수비드 닭가슴살 요리 돈까스 볶음밥 만들기.주니호맘..2019.4...\n", " 2 가슴살_닭_라이스_카레 food.닭의품격 초간편 냉동닭가슴살 카레라이스 만들기.유누네..2018.9.22....)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "# df = pd.read_csv(\"data/naverPost_muyong_fixed.csv\")\n", "# df = df.iloc[:,1:]\n", "df = pd.read_csv(\"data/naverPost_muyong.csv\")\n", "df.shape, len(df.Posts[1].split(\"|\")), df.head(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **2 PreProcessing 전처리 작업**\n", "**Word2vec** 을 만들기 위해서는 **문장 데이터로** 전처리가 필요하다\n", "1. **그냥 만든경우** 와, **문장을 선별한 경우를** 비교하여 성능 향상 시키기\n", "1. **핵심 Token 을 찾고**, 이를 바탕으로 word2vec 결과값 필터링 하기 **(Core 찾기가 우선)**" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "# link_temp = links_org.iloc[370:1200,:] # .to_csv('naver_links_temp.csv')\n", "# link_temp = link_temp.reset_index(drop=True)\n", "# link_temp = link_temp.drop([544], axis=0).reset_index(drop=True)\n", "# link_temp.head(2)" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import re\n", "def dot_fixer(sent):\n", " dot_to_nun = re.compile(r\"(?P(\\d+)).(?P(\\d+))\")\n", " nun_to_dot = re.compile(r\"(?P(\\d+))=(?P(\\d+))\")\n", " post_temp = dot_to_nun.sub(\"\\g=\\g\", sent)\n", " post_temp = \"\\n\".join(post_temp.split(\".\")).replace(\"^\",\" \").replace(\"[\",\" \").replace(\"]\",\" \").replace(\"(\",\" \").replace(\")\",\" \")\n", " post_temp = nun_to_dot.sub(\"\\g.\\g\", post_temp)\n", " return post_temp" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# # 크롤링 잘못된 소숫점 숫자를 치환후 줄바꿈 처리 모두 바꾸기\n", "# import pandas as pd\n", "# df = pd.read_csv(\"data/naverPost_muyong.csv\")\n", "\n", "# from tqdm import tqdm\n", "# posts = df.Posts.tolist()\n", "# df.Posts = [dot_fixer(_) for _ in tqdm(posts)]\n", "# df.head(3)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# df.to_csv(\"data/naverPost_muyong.csv\", index=None)\n", "# print(\"dot fixed\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from konlpy.tag import Mecab, Okt" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "text = \"오늘의 김치찌개는 싱거워서 고유한 텁텁한 단맛이 잘 안난다\"" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('오늘', 'NNG'),\n", " ('의', 'JKG'),\n", " ('김치찌개', 'NNG'),\n", " ('는', 'JX'),\n", " ('싱거워서', 'VA+EC'),\n", " ('고유', 'NNG'),\n", " ('한', 'XSA+ETM'),\n", " ('텁텁', 'XR'),\n", " ('한', 'XSA+ETM'),\n", " ('단맛', 'NNG'),\n", " ('이', 'JKS'),\n", " ('잘', 'MAG'),\n", " ('안', 'MAG'),\n", " ('난다', 'VV+EC')]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Mecab().pos(text)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('오늘', 'Noun'),\n", " ('의', 'Josa'),\n", " ('김치찌개', 'Noun'),\n", " ('는', 'Josa'),\n", " ('싱거워서', 'Adjective'),\n", " ('고유', 'Noun'),\n", " ('한', 'Josa'),\n", " ('텁텁', 'Noun'),\n", " ('한', 'Josa'),\n", " ('단맛', 'Noun'),\n", " ('이', 'Josa'),\n", " ('잘', 'Verb'),\n", " ('안', 'VerbPrefix'),\n", " ('난다', 'Verb')]" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Okt().pos(text)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.8" } }, "nbformat": 4, "nbformat_minor": 4 }