# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# +
''' Copyright 2019 <NAME>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions andlimitations under the License. '''

#Author <NAME>, <EMAIL> 
#Supervisor Na, In Seop, <EMAIL> 
#Starting 2019.01.04
#Reference https://www.kaggle.com/ashishpatel26/think-differently-what-s-cooking

import numpy as np
import pandas as pd
import json
import re

from sklearn.multiclass import OneVsRestClassifier
from nltk.stem import WordNetLemmatizer

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import SVC
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import FunctionTransformer, LabelEncoder

from tqdm import tqdm
tqdm.pandas()
# -

# <1> 데이터 불러오기

train = pd.read_json('train.json')
test = pd.read_json('test.json')

# <2> 데이터 분석

#  1) cuisine의 종류 : 20개

train["cuisine"].unique()

#  2) 각 cuisine에 속하는 음식의 가짓수

train["cuisine"].value_counts()

#  3) 각 cuisine 별로 자주 사용되는 재료 찾기

# +
from collections import Counter
import operator

distinct_ingr = train['ingredients'].apply(lambda x:','.join(x))
cuisines = train['cuisine']
top=' '
total = Counter(','.join(distinct_ingr).split(','))

for cuisine in cuisines.unique():
    ingr = Counter(','.join(distinct_ingr[cuisines == cuisine]).split(','))
    ingr_score = {k:(float(ingr[k])/len(ingr))**2/(float(total[k])/len(total)) for k in ingr.keys()}
               
    top += "\n\n<"+cuisine+">\n"
    for item in sorted(ingr_score.items(), key = lambda x:x[1],reverse=True)[0:5]:
        top += " ."+item[0]
    if(cuisine=="russian"):
        print("\n"+top)
# -

#  4) 그래프로 cuisine 나타내기

# +
import seaborn as sns
import matplotlib.pyplot as plt

ax = train['cuisine'].value_counts().plot(kind='barh', title ="Cuisine types", figsize=(12, 7), legend=True, fontsize=14, rot=5)
ax.set_ylabel("cuisine", fontsize=17, rotation=0)
plt.show()
# -

#  5) 사용되는 재료의 수 음식 별로 파악하기

train['num_ingredients'] = train['ingredients'].apply(lambda x: len(x))
test['num_ingredients'] = test['ingredients'].apply(lambda x: len(x))
train.sort_values(by=["num_ingredients"],ascending=True).head(20)

#  6) 2가지 이하의 재료만 사용되는 음식 제외시키기

train = train[train['num_ingredients'] > 2]

train.sort_values(by=["num_ingredients"],ascending=True).head(20)

sns.distplot(train["num_ingredients"])
plt.title("Dist Plot about the number of ingredients")
plt.show()

#  7) 재료 이름 변경 후 단어로 만들기

lemmatizer = WordNetLemmatizer()
def preprocess(ingredients):
    ingredients_text = ' '.join(ingredients)
    ingredients_text = ingredients_text.lower()
    
    ingredients_text = ingredients_text.replace('-', '')
    ingredients_text = ingredients_text.replace('wasabe', 'wasabi')
    ingredients_text = ingredients_text.replace('fish sauce', 'fishsauce')
    ingredients_text = ingredients_text.replace('coconut cream', 'coconutcream')
    ingredients_text = ingredients_text.replace('yellow onion', 'yellowonion')
    ingredients_text = ingredients_text.replace('cream cheese', 'creamcheese') 
    ingredients_text = ingredients_text.replace('baby spinach', 'babyspinach')
    ingredients_text = ingredients_text.replace('coriander seeds', 'corianderseeds')
    ingredients_text = ingredients_text.replace('corn tortillas', 'corntortillas')
    ingredients_text = ingredients_text.replace('rice cakes', 'ricecakes')
    ingredients_text = ingredients_text.replace('a챌ai', 'acorai')
    ingredients_text = ingredients_text.replace('cr챔me', 'crcoame')
    
    words = []
    for word in ingredients_text.split():
        if re.findall('[0-9]', word): continue
        if len(word) <= 2: continue
        if '’' in word: continue
        word = lemmatizer.lemmatize(word)
        if len(word) > 0: words.append(word)
    return ' '.join(words)


train['new_ingredients'] = train['ingredients'].progress_apply(lambda ingredients: preprocess(ingredients))
test['new_ingredients'] = test['ingredients'].progress_apply(lambda ingredients: preprocess(ingredients))
train.head()

#  8) TfidfVectorizer

vectorizer = make_pipeline(
    TfidfVectorizer(sublinear_tf=True),
    FunctionTransformer(lambda x: x.astype('float'), validate=False)
)

x_train = vectorizer.fit_transform(train['new_ingredients'].values)
x_train.sort_indices()
x_test = vectorizer.transform(test['new_ingredients'].values)

#  9) cuisine에 라벨 인코딩(0~19)

label_encoder = LabelEncoder()
y_train = label_encoder.fit_transform(train['cuisine'].values)
dict(zip(label_encoder.classes_, label_encoder.transform(label_encoder.classes_)))

# <3> 모델 만들기

# +
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression

from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
k_fold = KFold(n_splits=10, shuffle=True, random_state=0)
# -

train_data=train.drop("cuisine", axis=1)
train_data=train_data.drop("ingredients", axis=1)
train_data=train_data.drop("new_ingredients", axis=1)
target=train['cuisine']

#  1)  LogisticRegression : 0.78197

# +
#clf = LogisticRegression()
#parameters = {'C':[1, 10]}
#score=cross_val_score(clf, train_data, target, cv=k_fold, n_jobs=1, scoring='accuracy')
#round(np.mean(score)*100, 2)
#0.78197
# -

#  2)  KNeighborsClassifier : 0.75573

# +
#classifier = KNeighborsClassifier(n_neighbors = 10)
#score=cross_val_score(classifier, train_data, target, cv=k_fold, n_jobs=1, scoring='accuracy')
#round(np.mean(score)*100, 2)
#0.75573
# -

#  3)  DecisionTreeClassifier : 0.63143

# +
#classifier = DecisionTreeClassifier()
#score=cross_val_score(classifier, train_data, target, cv=k_fold, n_jobs=1, scoring='accuracy')
#round(np.mean(score)*100, 2)
#0.63143
# -

#  4)  RandomForestClassifier : 0.70444

# +
#classifier = RandomForestClassifier()
#score=cross_val_score(classifier, train_data, target, cv=k_fold, n_jobs=1, scoring='accuracy')
#round(np.mean(score)*100, 2)
#0.70444
# -

#  5)  OneVsRestClassifier : 0.82662

#  가장 성능 뛰어난 OneVsRestClassifier 선택

estimator = SVC(C=300, kernel='rbf', degree=3, gamma=1.4, coef0=1, shrinking=True, tol=0.001,probability=False, cache_size=1000, 
                class_weight=None, verbose=False, max_iter=-1, decision_function_shape=None, random_state=None)

classifier = OneVsRestClassifier(estimator, n_jobs=-1)

# <4> 모델 훈련시키기

classifier.fit(x_train, y_train)

# <5> test 데이터 예측

y_pred = label_encoder.inverse_transform(classifier.predict(x_test))

from sklearn.metrics import confusion_matrix, classification_report
print(confusion_matrix(y_pred, y_pred))

print(classification_report(y_pred, y_pred))

# <6> 제출용 csv 파일 생성

test['cuisine'] = y_pred
test[['id', 'cuisine']].to_csv('Jsy_submission.csv', index=False)
test[['id', 'cuisine']].head()



StarcoderdataJupyterScriptsDedupFiltered