레시피 데이터 전처리 및 단위기준 일치사전 만들기
계량법 안내
1큰술(1T, 1Ts) = 1숟가락 15ml = 3t (밥숟가락 뜨면 1큰술)
1작은술(1t, 1ts) 5ml (티스푼으로는 2스푼이 1작은술)
1컵(1Cup, 1C) 200ml = 16T (한국,중국,일본) (서양(미국)은 1C가 240~250ml)
1종이컵 180ml; 1oz 28.3g
1파운드(lb) 약 0.453 킬로그램(kg)
1갤런(gallon) 약 3.78 리터(ℓ)
1꼬집 약 2g 정도이며 '약간'이라고 표현하기도 함
조금 약간의 2~3배
적당량 기호에 따라 마음대로 조절해서 넣으란 표현
1줌 한손 가득 (예시 : 멸치 1줌 = 국멸치인 경우 12~15마리, 나물 1줌은 50g) 크게 1줌 = 2줌 [1줌의 두배]
1주먹 여자 어른의 주먹크기, 고기로는 100g
1토막 2~3cm두께 정도의 분량
마늘 1톨 깐 마늘 한쪽
생강 1쪽 마늘 1톨의 크기와 비슷
생강 1톨 아기 손바닥만한 크기의 통생강 1개
고기 1근 600g
채소 1근 400g
채소 1봉지 200g 정도
units = {
"15ml":["1큰술","1T","1Ts","3t"],
"5ml":["1작은술","1t","1ts"],
"200ml":["1컵","1Cup","1C"],
"250ml":["16T", "1C"],
"180ml":["1종이컵"],
"28.3g":["1oz"],
"453g":["1파운드","lb"],
"3780ml":["1갤런","gallon"],
"2g":["1꼬집",'약간'],
"4g":["조금"],
"6g":["조금"],
"10g":["적당량"],
"50g":["1줌"], # 나물
"100g":["1큰줌"], # 나물
"13마리":["1줌"], # 멸치
"26마리":["1큰줌"], # 멸치
"100g":["1주먹"], # 여자 어른의 주먹크기
"3cm":["1토막"],
"1알":["1톨","1쪽"], # 마늘, 생강 등
"600g":["1근"], # 고기
"400g":["1근"], # 채소
"200g":["1봉지"],
}
unit_tokens = []
for _ in [v for k,v in units.items()]:
unit_tokens += _
", ".join(sorted(set(unit_tokens)))
'16T, 1C, 1Cup, 1T, 1Ts, 1oz, 1t, 1ts, 1갤런, 1근, 1꼬집, 1봉지, 1작은술, 1종이컵, 1주먹, 1줌, 1쪽, 1컵, 1큰술, 1큰줌, 1토막, 1톨, 1파운드, 3t, gallon, lb, 약간, 적당량, 조금'
import json, re
import pandas as pd
df_safe = pd.read_csv("data/food_recipe_safe.csv")
df_safe = df_safe.loc[:, ['메뉴명','재료정보']]
print(df_safe.shape, df_safe.tail())
(1198, 2) 메뉴명 재료정보 1193 토마토 미소 된장국 토마토 50g, 두부 30g, 양파 15g, 표고버섯 15g, 멸치 5g, 고추 8... 1194 미역 미소국 미소된장 3.5g, 건미역 2g, 가츠오부시 0.3g, 미향 0.3g 1195 홍합 배춧국 홍합 50g, 배추 50g, 무 30g, 마늘 2g, 파 3g, 홍고추 1g, 소금... 1196 얼큰 콩나물 수제비 콩나물 50g, 황태머리 40g, 고추장 10g, 밀가루 100g, 고춧가루 5g,... 1197 단호박 생선탕수, 키위소스 동태살 120g, 단호박 10g, 당근 15g, 오이 15g, 양파 15g, 전분 ...
from collections import Counter
df_safe.재료정보 = [_.split('\n') for _ in df_safe.재료정보.fillna('')]
df_safe_names = {no:_ for no,_ in enumerate(df_safe.메뉴명)}
sorted(dict(Counter([len(_) for no, _ in enumerate(df_safe["재료정보"])])).items(),\
key=lambda x:x[0], reverse = False) # Value 기준 정렬
[(1, 459), (2, 127), (3, 202), (4, 190), (5, 95), (6, 76), (7, 24), (8, 14), (9, 9), (10, 1), (12, 1)]
# Step3 에서 구분에 오류가 나는 부분을 전처리
# Key 와 혼동되는 Item 레시피 전처리 진행
result = []
for item in df_safe["재료정보"]:
temp = [_.replace("약간","약간(5g)") for _ in item]
result.append(temp)
df_safe["재료정보"] = result
깔대기 방식으로
# 재료정보의 value 갯수
df_safe.insert(1, "Values", [len(_) for _ in df_safe["재료정보"]])
# 중간 구분가능 Key 갯수의 확인
result = []
result_key = []
result_recipe = []
for _ in range(len(df_safe)):
# 레시피 구분데이터
data = df_safe.loc[_]
count, temp = 0, []
for no,_ in enumerate(data["재료정보"]):
# 재료정보 List 전처리를 위한 위치값 탐지기
if "".join(re.findall("[가-힣]+", _)) == _.replace(' ',""):
count += 1
temp.append(no)
# 유효한 Key 값이 발견되었으나
if count != 0:
# 0번 index 값이 없을때..
if 0 not in temp:
result_recipe.append([data['메뉴명']] + data['재료정보'])
temp = [0] + [_+1 for _ in temp]
else:
result_recipe.append(data['재료정보'])
else:
result_recipe.append(data['재료정보'])
result.append(count)
result_key.append(temp)
df_safe.insert(2, "Keys", result)
df_safe.insert(3, "Key_index", result_key)
df_safe["재료정보"] = result_recipe
df_safe.head(2)
메뉴명 | Values | Keys | Key_index | 재료정보 | |
---|---|---|---|---|---|
0 | 칼륨 듬뿍 고구마죽 | 2 | 1 | [0] | [고구마죽, 고구마 100g(2/3개), 설탕 2g(1/3작은술), 찹쌀가루 3g(... |
1 | 누룽지 두부 계란죽 | 4 | 2 | [0, 2] | [채소준비, 애호박 30g(1/6개), 표고버섯 20g(2개), 당근 5g(3×2×... |
분류값, Key 내용을 Key, Value 로 구분 및 작업의 진행
# _ = [(10, 5), (8, 5),
# (7, 4), (8, 4), (9, 4), (12, 4),
# (6, 3), (7, 3), (8, 3), (9, 3),
# (4, 2), (5, 2), (6, 2), (7, 2),
# (5, 1), (4, 1), (3, 1), (2, 1), (1, 1), # Key 1개는 1개로 묶는다
# (1, 0), (2, 0), (3, 0), (5, 0), (4, 0), (7, 0), (6, 0)] # Key 없으면 다 묶는다
# # Key 가 아닌값이 중간에 Key 처럼 존재시...
# # Key 내용이 붙어있거나, 마지막일 땐, 몰아주기 (거의 레시피일 확률이 높다..)
# df_safe[(df_safe.Values==7) & (df_safe.Keys==4)].iloc[0,3]
# df_safe[(df_safe.Values==8) & (df_safe.Keys==5)].iloc[0,3]
sorted(Counter([(df_safe.Values[_], df_safe.Keys[_])
for _ in range(len(df_safe))]),
key=lambda x :x[1], reverse=True)
Counter([(df_safe.Values[_], df_safe.Keys[_])
for _ in range(len(df_safe))])
Counter({(2, 1): 10, (4, 2): 67, (6, 3): 39, (8, 4): 13, (10, 5): 1, (3, 1): 15, (9, 4): 7, (7, 3): 19, (6, 2): 6, (5, 2): 17, (4, 1): 6, (5, 1): 1, (2, 0): 117, (1, 0): 456, (3, 0): 187, (5, 0): 77, (4, 0): 117, (7, 0): 3, (6, 0): 31, (7, 2): 2, (8, 2): 1, (9, 3): 2, (12, 4): 1, (1, 1): 3})
분류값, Key 내용을 Key, Value 기준의 확인
for no, _ in enumerate(range(len(df_safe))):
data = df_safe.loc[_]
if data.Keys != 0:
if 0 not in data["Key_index"]:
print(no, data["Key_index"], data["Values"])
df_safe.head(2)
메뉴명 | Values | Keys | Key_index | 재료정보 | |
---|---|---|---|---|---|
0 | 칼륨 듬뿍 고구마죽 | 2 | 1 | [0] | [고구마죽, 고구마 100g(2/3개), 설탕 2g(1/3작은술), 찹쌀가루 3g(... |
1 | 누룽지 두부 계란죽 | 4 | 2 | [0, 2] | [채소준비, 애호박 30g(1/6개), 표고버섯 20g(2개), 당근 5g(3×2×... |
분류값, Key 내용을 Key, Value 로 구분 및 작업의 진행
df_safe[df_safe.Values==12].index[0]
temp = df_safe.loc[df_safe[df_safe.Values==12].index[0]]
temp["재료정보"]
['영양밥', '찹쌀 60g, 은행 20g(8알), 잣 5g(5알), 호두 10g(1알), 생땅콩 10g(6알), 밤 20g(2개)', '떡갈비', '쇠갈비살 150g', '1차 양념 : 설탕 2g(1/3작은술), 꿀 2g(1/3작은술), 매실액 5g(1작은술),', '참기름 5g(1작은술)', '2차 양념 : 저염간장 5g(1작은술), 무염피스타치오 10g(4알), 다진 대파 10g(2작은술), 다진 마늘 5g(1작은술), 후추약간(5g)', '저염간장', '레드와인 5g(1작은술), 간장 5g(1작은술), 양파 10g(1/10개),', '마른 홍고추 2g(1/2개), 마른 다시마 5g(3×2cm), 마늘 5g(1쪽), 생강 약간(5g)', '곁들임', '아스파라거스 20g(1개), 더덕 15g(1개), 무염피스타치오']
# 맨 앞 인덱스가 없는 데이터는 더이상 없다..
for _ in df_safe.Key_index:
if len(_) > 0:
if 0 not in _:
print(_)
# 범위 index 를 추가하여 Key, Value 테스트
temp = df_safe.loc[456]
temp_index = temp.Key_index + [len(temp.재료정보)]
{temp["재료정보"][temp_index[_]]:temp["재료정보"][temp_index[_]+1:temp_index[_+1]]
for _ in range(len(temp.Key_index))}
{'만두소': ['곤드레나물 50g, 큰새우 4마리, 돼지고기 50g, 두부 30g(1/9모), 부추 10g(6줄기), 청양고추 10g(1개), 파 5g(2cm), 마늘 2g(1/2쪽), 후추 2g(1/3작은술), 참기름 3g(1/2작은술), 식용유 약간(5g)'], '만두피': ['라이스페이퍼 30g(6장), 부추 3g(2줄기), 물 100ml(1/2컵)'], '초간장': ['저염간장 5g(1작은술), 식초 5g(1작은술)']}
# 테이블 전체를 대상으로 전처리 작업을 진행
result = []
for _ in range(len(df_safe)):
result_temp = {}
temp = df_safe.loc[_]
# 내부에 Key 값이 포함된 경우
if temp.Keys != 0:
temp_index = temp.Key_index + [len(temp.재료정보)]
for _ in range(len(temp.Key_index)):
result_temp[temp["재료정보"][temp_index[_]]] = temp["재료정보"][temp_index[_]+1:temp_index[_+1]]
# Key 가 없는경우
else:
result_temp[temp.메뉴명] = temp.재료정보
result.append(result_temp)
df_safe["재료정보"] = result
df_safe.head(2)
메뉴명 | Values | Keys | Key_index | 재료정보 | |
---|---|---|---|---|---|
0 | 칼륨 듬뿍 고구마죽 | 2 | 1 | [0] | {'고구마죽': ['고구마 100g(2/3개), 설탕 2g(1/3작은술), 찹쌀가루... |
1 | 누룽지 두부 계란죽 | 4 | 2 | [0, 2] | {'채소준비': ['애호박 30g(1/6개), 표고버섯 20g(2개), 당근 5g(... |
# df_org = pd.read_csv("data/food_recipe_safe.csv")
# df_org = df_org.loc[:,['메뉴명','조리방법','요리종류','재료정보','이미지경로(소)','이미지경로(대)']]
# df_org.재료정보 = [json.dumps(_ ,ensure_ascii=False) for _ in result]
# # df_org.to_csv("data/food_recipe_safe_new.csv", index=None)
# df_org.head(2)
df_org = pd.read_csv("data/food_recipe_safe.csv")
df_org = df_org.loc[:,['메뉴명','조리방법','요리종류','재료정보','이미지경로(소)','이미지경로(대)']]
df_org.재료정보 = [json.dumps(_ ,ensure_ascii=False) for _ in result]
# df_org.to_csv("data/food_recipe_safe_new.csv", index=None)
df_org.head(2)
result = []
for item in df_safe["재료정보"]:
temp = list(item.keys()) # Key 이름
temp_dict = {_:len(item[_]) for _ in item}
result.append(temp_dict)
df_safe.insert(4, "Key_Values", result)
df_safe = df_safe.loc[:, ["메뉴명","Key_Values","재료정보"]]
df_safe.insert(2, "Key_Value_nums", [list(_.values()) for _ in df_safe.Key_Values])
df_safe.head(2)
메뉴명 | Key_Values | Key_Value_nums | 재료정보 | |
---|---|---|---|---|
0 | 칼륨 듬뿍 고구마죽 | {'고구마죽': 1} | [1] | {'고구마죽': ['고구마 100g(2/3개), 설탕 2g(1/3작은술), 찹쌀가루... |
1 | 누룽지 두부 계란죽 | {'채소준비': 1, '누룽지 죽': 1} | [1, 1] | {'채소준비': ['애호박 30g(1/6개), 표고버섯 20g(2개), 당근 5g(... |
result = []
for _ in df_safe.Key_Value_nums:
if list(set(_)) == [1]:
result.append('pass')
else:
result.append('work')
df_safe.Key_Value_nums = result
df_safe.head(2)
메뉴명 | Key_Values | Key_Value_nums | 재료정보 | |
---|---|---|---|---|
0 | 칼륨 듬뿍 고구마죽 | {'고구마죽': 1} | pass | {'고구마죽': ['고구마 100g(2/3개), 설탕 2g(1/3작은술), 찹쌀가루... |
1 | 누룽지 두부 계란죽 | {'채소준비': 1, '누룽지 죽': 1} | pass | {'채소준비': ['애호박 30g(1/6개), 표고버섯 20g(2개), 당근 5g(... |
# key 내부 Value 의 데이터를 1개로 전처리
# 작업을 하면서 중간구분자 ":" 포함 데이터 확인하기
temp_list = []
for idx in list(df_safe.index):
temp = df_safe.loc[idx]
temp_dict = {}
for key in list(temp['Key_Values'].keys()):
temp_token = " ".join(temp["재료정보"][key])
# 추가 작업할 내용 ㅜㅜ (정보 내부에 ":" 가 포함시.)
if temp_token.find(":") != -1:
temp_list.append([idx, key, temp_token])
temp_dict[key] = temp_token
temp["재료정보"] = temp_dict
result = []
for _ in list(df_safe.index):
if _ in [_[0] for _ in temp_list]:
result.append('Yes')
else: result.append('Pass')
df_safe = df_safe.loc[:, ["메뉴명", "재료정보"]]
df_safe.insert(1, "Mid_Key", result)
df_safe[df_safe.Mid_Key=='Yes'].tail(3)
메뉴명 | Mid_Key | 재료정보 | |
---|---|---|---|
1127 | 두부선과 저나트륨 겨자 간장소스 | Yes | {'두부선과 저나트륨 겨자 간장소스': '두부 80g, 표고버섯마른것 10g, 쇠고... |
1148 | 삼색 콩튀김 | Yes | {'삼색 콩튀김': '완두콩 7.5g, 강남콩 7.5g, 제비콩 7.5g, 찹쌀가루... |
1151 | 카프라제 | Yes | {'카프라제': '생 모짜렐라치즈 20g, 토마토 35g, 발사믹식초 2.5g[소스... |
노가다고 30개 정도 진행하다 보니 규칙이 보임
- 중간Key :
내용이 문자열 중간에 포함import re
reg_token = "-.*:"
reg_token = "\[.*\]"
texts = "오이고추 160g [절임물] 해물육수 30g, 어간장 10g"
token = re.findall(reg_token, texts)
token = "".join(token)
token
'[절임물]'
temp = "콩나물 70g, 배 50g[소스료리]콩 10g 쌀 20g"
import re
reg_token = "-.*:"
texts = "오이고추 160g - 절임물 : 해물육수 30g, 어간장 10g"
token = re.findall(reg_token, texts)
token = "".join(token)
token
'- 절임물 :'
texts.split(token)
['오이고추 160g ', ' 해물육수 30g, 어간장 10g']
노가다고 30개 정도 진행하다 보니 규칙이 보임
- 중간Key :
내용이 문자열 중간에 포함import re
# reg_token = "-.*:"
reg_token = "\[.*\]"
result = []
for _ in list(df_safe.index):
temp = df_safe.loc[_]
temp_keys = list(temp["재료정보"].keys())
temp_dict = {}
for k in temp_keys:
temp_dict[k] = temp["재료정보"][k]
# 중간 구분자가 포함된 경우
if temp["재료정보"][k].find(":") != -1:
# 구분점이 있는 경우 : dict 2개로 저장
if len(re.findall(reg_token, temp["재료정보"][k])) != 0:
temp_token_key = re.findall(reg_token, temp["재료정보"][k])
temp_token_key = "".join(temp_token_key)
#temp_token_key = temp_token_key.replace("-","").replace(":","").strip()
temp_token_key = temp_token_key.replace("[","").replace("]","").replace(":","").strip()
temp_tokens = temp["재료정보"][k].split(temp_token_key)
temp_dict[k] = temp_tokens[0].replace("[","")
# 구분자 작업 뒤 이름이 포함된 경우, Key 수정작업
temp_values = temp_tokens[-1].replace("]","")
if temp_values.find(":") != -1:
temp_values_list = temp_values.split(":")
if len(temp_values_list) == 2:
temp_dict[temp_token_key] = temp_tokens[-1].replace("]","")
else:
temp_dict[k] = temp["재료정보"][k]
result.append(temp_dict)
# result.append(temp_dict)
df_safe["재료정보"] = result
df_safe.to_csv('data/food_recipe_safe_new_keys_new.csv', index=None)
import ast
import pandas as pd
# df_safe = pd.read_csv("data/food_recipe_safe_new_keys.csv")
df_safe = pd.read_csv('data/food_recipe_safe_new_keys.csv')
df_safe["재료정보"] = [ast.literal_eval(_) for _ in df_safe["재료정보"]]
df_safe = df_safe.iloc[:,[0,-1]]
print(df_safe.shape)
df_safe.head(2)
(1198, 2)
메뉴명 | 재료정보 | |
---|---|---|
0 | 칼륨 듬뿍 고구마죽 | {'고구마죽': '고구마 100g(2/3개), 설탕 2g(1/3작은술), 찹쌀가루 ... |
1 | 누룽지 두부 계란죽 | {'채소준비': '애호박 30g(1/6개), 표고버섯 20g(2개), 당근 5g(3... |
result = []
for idx in list(df_safe.index):
count, temp = 0, df_safe.loc[idx]
temp_keys = list(temp['재료정보'].keys())
for k in temp_keys:
if temp["재료정보"][k].find(':') != -1: count += 1
else: pass
result.append(count)
df_safe.insert(1, 'Mid_Key', result)
df_safe.head(2)
메뉴명 | Mid_Key | 재료정보 | |
---|---|---|---|
0 | 칼륨 듬뿍 고구마죽 | 0 | {'고구마죽': '고구마 100g(2/3개), 설탕 2g(1/3작은술), 찹쌀가루 ... |
1 | 누룽지 두부 계란죽 | 0 | {'채소준비': '애호박 30g(1/6개), 표고버섯 20g(2개), 당근 5g(3... |
idx_key = list(df_safe[df_safe.Mid_Key!=0].index)[-4]
print(df_safe[df_safe.Mid_Key!=0].head(3))
print(df_safe[df_safe.Mid_Key!=0].shape)
df_safe.loc[idx_key]["재료정보"]
메뉴명 Mid_Key 재료정보 202 누룽지새우튀김 1 {'누룽지새우튀김': '새우(100g), 소금(0.3g), 후춧가루(0.02g) 튀... 207 생선카레튀김 2 {'생선카레튀김': '생선살(150g), 생강(10g), 정종(10g), 녹말가루(... 208 삼겹가지볶음 1 {'삼겹가지볶음': '삼겹살(100g), 생강(5g), 정종(10g), 가지(50g... (233, 3)
{'두부 달걀전': '두부 60g, 카레가루 0.4g, 후춧가루 0.1g, 밀가루 1.6g, 식용유 4g, 청고추 0.5g, 홍고추 0.5g ', '소스소개': '저나트륨초간장소스:간장 1g, 식초 1.5g, 설탕 0.3g, 통깨 0.1g'}
df_safe[df_safe.Mid_Key==0].shape()
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-5-3e31fed86d88> in <module> ----> 1 df_safe[df_safe.Mid_Key==0].shape() TypeError: 'tuple' object is not callable
df_safe.loc[idx_num]["재료정보"]
"{'돼지머리수육맑은전골': '돼지머리 200g, 우동면 100g, 미나리 20g, 청고추 15g', '소스': '일본 된장 30g, 다진마늘 10g, 다진대파 10g, 청주 15g, 무 25g', '육수': '해물육수 300g, 청양고추 20g, 맛간장 15g'}"
# 0 ~ 235
num = 0
temp = df_safe[df_safe.Mid_Key!=0]
idx_num = temp.iloc[num,:].name
print(list(df_safe.loc[idx_num]["재료정보"].keys()))
df_safe.loc[idx_num]["재료정보"]
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-17-6e343811d391> in <module> 3 temp = df_safe[df_safe.Mid_Key!=0] 4 idx_num = temp.iloc[num,:].name ----> 5 print(list(df_safe.loc[idx_num]["재료정보"].keys())) 6 df_safe.loc[idx_num]["재료정보"] AttributeError: 'str' object has no attribute 'keys'
# 수작업 수정한 내용
temp_dict = {
'돼지머리수육맑은전골': '돼지머리 200g, 우동면 100g, 미나리 20g, 청고추 15g',
'소스': '일본 된장 30g, 다진마늘 10g, 다진대파 10g, 청주 15g, 무 25g',
'육수' : '해물육수 300g, 청양고추 20g, 맛간장 15g'}
print(temp_dict)
df_safe.loc[idx_num,"재료정보"] = str(temp_dict)
# df_safe.loc[idx_num,"재료정보"] = temp_dict
df_safe.to_csv('data/food_recipe_safe_new_keys.csv', index=None)
print("수정완료")
{'돼지머리수육맑은전골': '돼지머리 200g, 우동면 100g, 미나리 20g, 청고추 15g', '소스': '일본 된장 30g, 다진마늘 10g, 다진대파 10g, 청주 15g, 무 25g', '육수': '해물육수 300g, 청양고추 20g, 맛간장 15g'} 수정완료
df_safe = pd.read_csv('data/food_recipe_safe_new_keys.csv')
df_safe.to_csv("data/food_recipe_safe_new_keys_new.csv", index=None)
{'고추김치': '오이고추 160g 절임물 : 해물육수 30g, 어간장 10g', '소': '영양부추 20g, 연근 20g, 무 20g, 고춧가루 15g, 생강청 15g, 통깨 1g'}
df_safe.iloc[idx_num,-1]
{'고추김치': '오이고추 160g 절임물 : 해물육수 30g, 어간장 10g', '소': '영양부추 20g, 연근 20g, 무 20g, 고춧가루 15g, 생강청 15g, 통깨 1g'}
str(temp_dict)
"{'고추김치': '오이고추 160g', '절임물': '해물육수 30g, 어간장 10g', '소': '영양부추 20g, 연근 20g, 무 20g, 고춧가루 15g, 생강청 15g, 통깨 1g'}"
ast.literal_eval(str(temp_dict))
{'고추김치': '오이고추 160g', '절임물': '해물육수 30g, 어간장 10g', '소': '영양부추 20g, 연근 20g, 무 20g, 고춧가루 15g, 생강청 15g, 통깨 1g'}