<reponame>MSJ1996/Price-Prediction-for-Wine-Quality-Dataset-ML-
# -*- coding: utf-8 -*-
"""Keras Using Wine DataSet.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1l3QsdlYJKsoQ6lycpBYj_TndZ34E2RqV
"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

# Install the latest version of Tensorflow
!pip install -q -U tensorflow==1.7.0

import itertools
import os
import math
import numpy as np
import pandas as pd
import tensorflow as tf

from sklearn.preprocessing import LabelEncoder
from tensorflow import keras
layers = keras.layers

# This code was tested with Tensorflow v1.7
print("You have Tensorflow version", tf.__version__)

!pip install pandas

# Get the data: original source is here: https://www.kaggle.com/zynicide/wine-reviews/data
URL = "https://storage.googleapis.com/sara-cloud-ml/wine_data.csv"
path = tf.keras.utils.get_file(URL.split('/')[-1], URL)

# Convert the data to a Pandas data frame
data = pd.read_csv(path)

# Shuffle the data
data = data.sample(frac=1)

# Print the first 5 rows
data.head()

# Do some preprocessing to limits the # of wine varities in the dataset
data = data[pd.notnull(data['country'])]
data = data[pd.notnull(data['price'])]
data = data.drop(data.columns[0], axis=1)

variety_threshold = 500 # Anything that occurs less than this will be removed.
value_counts = data['variety'].value_counts()
to_remove = value_counts[value_counts <= variety_threshold].index
data.replace(to_remove, np.nan, inplace=True)
data = data[pd.notnull(data['variety'])]

# Split data into train and test
train_size = int(len(data) * .8)
print ("Train size: %d" % train_size)
print ("Test size: %d" % (len(data) - train_size))

# Train feautures
description_train = data['description'][:train_size]
variety_train = data['variety'][:train_size]

# Train  labels
labels_train = data['price'][:train_size]

# Test features
description_test = data['description'][train_size:]
variety_test = data['variety'][train_size:]

# Test labels
labels_test = data['price'][train_size:]

# Create a tokenizer to preprocess our text description
vocab_size = 12000 # This is a hyperparameter, experiments with different values of your dataset
tokensize = keras.preprocessing.text.Tokenizer(num_words=vocab_size, char_level = False)
tokensize.fit_on_texts(description_train) # only fit on train

# wide features 1: sparse bag of words (bow) vocab_size vector
description_bow_train = tokensize.texts_to_matrix(description_train)
description_bow_test = tokensize.texts_to_matrix(description_test)

# Wide features 2: one-hot vector of variety categories

#Use sklern utility to convert label string to numbered index
encoder = LabelEncoder()
encoder.fit(variety_train)
variety_train = encoder.transform(variety_train)
variety_test = encoder.transform(variety_test)
num_classes = np.max(variety_train) + 1

# Convert labels to one hot
variety_train = keras.utils.to_categorical(variety_train, num_classes)
variety_test = keras.utils.to_categorical(variety_test, num_classes)

# Define our wide model with the functional API
bow_inputs = layers.Input(shape=(vocab_size,))
variety_inputs = layers.Input(shape=(num_classes,))
merged_layer = layers.concatenate([bow_inputs, variety_inputs])
merged_layer = layers.Dense(256, activation='relu')(merged_layer)
predictions = layers.Dense(1)(merged_layer)
wide_model = keras.Model(inputs=[bow_inputs, variety_inputs], outputs=predictions)

wide_model.compile(loss='mse', optimizer= 'adam', metrics=['accuracy'])
print(wide_model.summary())

# Deep Model features: word embedding of wine descriptions
train_embed = tokensize.texts_to_sequences(description_train)
test_embed = tokensize.texts_to_sequences(description_test)

max_seq_length = 170
train_embed = keras.preprocessing.sequence.pad_sequences(train_embed, maxlen=max_seq_length, padding="post")
test_embed = keras.preprocessing.sequence.pad_sequences(test_embed, maxlen=max_seq_length, padding="post")

# Define our deep model with the Functional API
deep_inputs = layers.Input(shape=(max_seq_length,))
embedding = layers.Embedding(vocab_size, 8, input_length=max_seq_length)(deep_inputs)
embedding = layers.Flatten()(embedding)
embed_out = layers.Dense(1)(embedding)
deep_model = keras.Model(inputs=deep_inputs, outputs=embed_out)
print(deep_model.summary())

deep_model.compile(loss='mse',
                   optimizer = 'adam',
                   mertrics=['accuracy'])

# Combine wide and deep into one model
merged_out = layers.concatenate([wide_model.output, deep_model.output])
merged_out = layers.Dense(1)(merged_out)
combined_model = keras.Model(wide_model.input + [deep_model.input], merged_out)
print(combined_model.summary())

combined_model.compile(loss = 'mse',
                       optimizer='adam',
                       metrics=['accuracy'])

# Run training
combined_model.fit([description_bow_train, variety_train] + [train_embed], labels_train, epochs=10, batch_size=128)

combined_model.evaluate([description_bow_test, variety_test] + [test_embed], labels_test, batch_size=128)

# generate predictions
predictions = combined_model.predict([description_bow_test, variety_test] + [test_embed])

# Compare prediction with actual values for the first few items in our test dataset
num_predictions = 40
diff = 0

for i in range(num_predictions):
  val = predictions[i]
  print(description_test.iloc[i])
  print('Predicted: ', val[0], 'Actual: ', labels_test.iloc[i], '\n')
  diff += abs(val[0] - labels_test.iloc[i])

# Compare the average difference between actual price and the model's predicted price
print('Average prediction difference: ', diff / num_predictions)