# -*- coding: utf-8 -*-
"""ProjetBigData.ipynb

Automatically generated by Colaboratory.

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

from google.colab import drive
drive.mount('/content/gdrive')

!ls "/content/gdrive/MyDrive/ProjetBigData"

"""### Telechargement des Librairies Pour l'etude du Projet Big Data"""

!pip install researchpy
import spacy
import en_core_web_sm
from textblob import TextBlob
from textblob import Word
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import scipy.stats as ss
import nltk
import re
from researchpy import crosstab
import random
from nltk.stem import WordNetLemmatizer 
from nltk.corpus import wordnet
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from sklearn.cluster import KMeans 
import pylab 
import scipy.stats as stats
nltk.download('punkt')
nltk.download('stopwords')
nltk.download('wordnet')
nltk.download('averaged_perceptron_tagger')
nltk.download('brown')

"""### Importation des jeu de donnees (TRAIN d'abord)"""

#Telechargement du jeu de donnee
trainjob = pd.read_csv("/content/gdrive/MyDrive/ProjetBigData/final_train.csv", encoding="utf-8")
trainjob['LocationRaw']=trainjob['LocationRaw'].astype('string')
trainjob['Location_Raw'] = trainjob['LocationRaw'].str.split(',')

#Description du jeu de donnees
trainjob.info(2)

"""### Valeurs manquantes(nombre)"""

#Affichage des variables dont il existe des valeurs manquantes 
trainjob_copy = trainjob.copy()
trainjob_copy.isnull().sum()[trainjob_copy.isnull().sum()>0]

"""# TRAITEMENTS

## LES FONCTIONS
"""

# Retirer les liens
def remove_url(s):
    s = re.sub('[^\s]*.com[^\s]*', "", s)
    s = re.sub('[^\s]*www.[^\s]*', "", s)
    s = re.sub('[^\s]*.co.uk[^\s]*', "", s)
    return s

#Retirer les chiffres de la description
def remove_num(s):
    return re.sub("[^\s]*[0-9]+[^\s]*", "", s)

#Retirer les espaces supplementaires de la description
def remove_extrablank(s):
  return re.sub(" +"," ",s)

# Retirer les ponctuations de la description
from string import punctuation
def remove_punctuation(s):
    global punctuation
    for p in punctuation:
        s = s.replace(p, ' ')
        s = s.replace('–',' ')
        s = s.replace("’",' ')
        s = re.sub(r"(?<= ).{1}(?= )"," ",s) 
    return s

# Retirer les stopwords de la description
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
en_stopwords = stopwords.words('english')
def remove_stopword(s):
    global en_stopwords
    s = word_tokenize(s)
    s = " ".join([w for w in s if w not in en_stopwords])
    return s

def stopword_company(name):
  words = [ "Agency", "Gmbh", "PA", "and", "Group", "PC", "Assn", "Hotel", "Pharmacy", "Assoc", "Hotels", "PLC", "Associates", "Inc", "PLLC", "Association", "Incorporated",
             "Restaurant", "Bank", "International", "SA", "BV", "Intl", "Sales", "Co", "Limited", "Service", "Comp", "LLC", "Services", "Company", "LLP", "Store", "Corp", "LP",
             "Svcs", "Corporation",  "Ltd", "Travel", "DMD", "Manufacturing", "Unlimited", "Enterprises", "Mfg"]
  for i in words:
    b = i.lower()
    if b in name.split(" "):
        name = re.sub(b,'',name)
  return name


def lemma_1(s):
  liste = []
  for i in TextBlob(s).words:
    liste.append(Word(Word(i).lemmatize()).lemmatize('v'))
  return liste

def lemma_2(s):
  list_v = " ".join(s)
  return list_v

#Cette fonction permet de stocker dans une liste un ensemble de dataframe correspondant chacun a un cluster ainsi que ses top 15 mots.
def get_top_features_cluster(tf_idf_array, prediction, n_feats):
    labels = np.unique(prediction)
    dfs = []
    for label in labels:
        id_temp = np.where(prediction==label) # indices for each cluster
        x_means = np.mean(tf_idf_array[id_temp], axis = 0) # returns average score across cluster
        sorted_means = np.argsort(x_means)[::-1][:n_feats] # indices with top 20 scores
        features = vectorizer.get_feature_names()
        best_features = [(features[i], x_means[i]) for i in sorted_means]
        df = pd.DataFrame(best_features, columns = ['features', 'score'])
        dfs.append(df)
    return dfs

"""### Donnees manquantes (%)"""

print("Initial data missing values")
print(trainjob_copy.isnull().sum()[trainjob_copy.isnull().sum()>0]/len(trainjob_copy))

"""### Imputation par "notSpecified" pour les variables contratype, contractime company"""

#imputation des valeurs manquantes par la valeur 'notSpecified'
trainjob_copy.fillna('notSpecified', inplace = True)

#Verivfication du traitement des donnees manquantes
print("Initial data missing values")
print(trainjob_copy.isnull().sum())

"""### Liste des villes les plus cher en UK"""

#Liste des villes les plus cheres en UK
exp_cities = ['London', 'Cambridge','Oxford','Bournemouth','Bristol', 'Portsmouth', 
              'Edinburgh', 'Southampton']

#Création d'un top_location 0 si la ville de mon dataframe ne fait pas partie et 1 si elle fait partie
trainjob_copy['top_location'] = trainjob_copy['LocationNormalized'].map(lambda place: 1 if place in exp_cities else 0)

#subset dataset column
trainjob_copy = trainjob_copy[['Id','Title', 'FullDescription','top_location','ContractType', 'ContractTime','Company','Category','SalaryNormalized']].copy()

"""### Statistiques univariées

### Normaliser la variable SalaryNormalized
"""

# Quelques statistiques sur la variable salary_normalized
trainjob_copy['SalaryNormalized'].describe()

#Presentation du QQ_plot
stats.probplot(trainjob_copy['SalaryNormalized'], dist="norm", plot=pylab)
pylab.show()

#Boxplot de salaire
ax = sns.boxplot(x=trainjob_copy["SalaryNormalized"])

"""### Suppression des donnees aberrantes de SalaryNormalilzed
Par la methode de l'intervalle interquartile des boites à moustaches
"""

# Calcul des quantiles
q1_salary = trainjob_copy['SalaryNormalized'].quantile(0.25)
q3_salary = trainjob_copy['SalaryNormalized'].quantile(0.75)
# Calcul de l'IQR
IQR = q3_salary - q1_salary
upper_salary = q3_salary + 1.5 * IQR
trainjob_copy[trainjob_copy['SalaryNormalized'] > upper_salary].count()

trainjob1 = trainjob[trainjob['SalaryNormalized']>upper_salary]

#Representation graphiques des dix premieres plus frequentes valeurs
trainjob1['Title'].value_counts().head(30).plot(kind='bar')

"""#### Contrat-type et Contract-time"""

# les valeurs uniques de cette variable
trainjob_copy['ContractTime'].value_counts()

#Representation graphique des dites variables
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(15, 15))
def label_function(val):
    return f'{val / 100 * len(trainjob):.0f}\n{val:.0f}%'
trainjob_copy.groupby('ContractType').size().plot(kind='pie', autopct=label_function, textprops={'fontsize': 20},
                                  colors=['tomato', 'gold', 'skyblue'], ax=ax1)
trainjob_copy.groupby('ContractTime').size().plot(kind='pie', autopct=label_function, textprops={'fontsize': 20},
                                 colors=['violet', 'lime', 'red'], ax=ax2)
ax1.set_ylabel('ContractType', size=22)
ax2.set_ylabel('ContractTime', size=22)
plt.tight_layout()
plt.show()

"""#### Title"""

#Valeur Unique
trainjob_copy['Title'].value_counts().count() # 62739 valeurs differentes

#les dix premieres plus frequentes valeurs
trainjob_copy['Title'].value_counts().head(10).plot(kind='bar')

#Representation d'un graphique croisé presentant le salaire moyen par title de metier
table = trainjob_copy.pivot_table(index='Title',values='SalaryNormalized', aggfunc=np.mean)
table = table.reindex(table['SalaryNormalized'].sort_values(ascending=False).index)
table = table.head(10)
plt.barh(table.index, table.SalaryNormalized)

"""#### Category"""

#Valeur Unique
trainjob_copy['Category'].value_counts().count() # 28 valeurs differentes

#Representation graphiques des dix premieres plus frequentes valeurs
trainjob_copy['Category'].value_counts().head(10).plot(kind='bar')

#Representation d'un graphique croisé presentant le salaire moyen par categorie de metier
table = trainjob_copy.pivot_table(index='Category',values='SalaryNormalized', aggfunc=np.mean)
table = table.reindex(table['SalaryNormalized'].sort_values(ascending=False).index)
table = table.head(10)
plt.barh(table.index, table.SalaryNormalized)

"""#### Company"""

#Valeur Unique
trainjob_copy['Company'].value_counts().count() # 14511 valeurs differentes

#les dix premieres plus frequentes valeurs
trainjob_copy['Company'].value_counts().head(10).plot(kind='bar')

# Representation d'un graphique croisé presentant le salaire moyen par societe emettrice
table = trainjob_copy.pivot_table(index='Company',values='SalaryNormalized', aggfunc=np.mean)
table = table.reindex(table['SalaryNormalized'].sort_values(ascending=False).index)
table = table.head(10)
plt.barh(table.index, table.SalaryNormalized)

"""### Top_location"""

#Valeur Unique
trainjob_copy['top_location'].value_counts().plot(kind = 'pie',autopct=label_function, figsize = (6,6)) # 2 valeurs differentes
plt.title('Frequence Top_location')
plt.xlabel('Top_location(1 = "< au cout moyen", 0 = "> au cout moyen")')
plt.ylabel(' ')
plt.show()

#Tableau croisé entre le salaire et la variable Location
trainjob_copy.pivot_table(index='top_location',values='SalaryNormalized', aggfunc=np.mean)

"""#### Extraction des heures dans la description

**Nous pensons que les heures de travail ont une infulence sur le salaire. Etant donné que nous ne disposons pas de caracteristiques dans nos jeu de donnees permettant d'estimer cela, nous allons dans cette partie essayer de retirer les heures travailler dans le feature FullDescription.**
"""

#Create column hour
trainjob_copy['hour'] = 0
#trainjob['Clean_Full_Descriptions_no_stop'] = trainjob['Clean_Full_Descriptions_no_stop'].astype('string')
for i in trainjob_copy.index:
  if trainjob_copy['FullDescription'].loc[i].__contains__("hours per week") == True:
    m = re.search(r"(\w{1}|\w{2}|\w{3})(?=( hours per week|hours per week))",trainjob_copy['FullDescription'].loc[i])
    if str(m)== 'None':
      continue
    elif str(m) != 'None' and m.group(0).strip().isnumeric() == True:
      if len(m.group(0).strip())==3:
        trainjob_copy['hour'].loc[i] = pd.to_numeric(m.group(0).strip()[:2]+'.'+m.group(0).strip()[2:])
      else:
        trainjob_copy['hour'].loc[i] = pd.to_numeric(m.group(0).strip())
      continue

"""**Relation entre heures et salaire**"""

#Valeur Unique
trainjob_copy['hour'].value_counts().count() # 2 valeurs differentes

#Representation graphique de la repartition de ladite variable
trainjob_copy['hour'].value_counts(normalize = True).head(10)

#Tableau croisé entre la colonne heure et le salaire
trainjob_copy.pivot_table(index='hour',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire en fonction des heures(10 premiers chiffres)')
plt.xlabel('Heures')
plt.ylabel('Salaire moyen')
plt.show()

"""***Coefficient de correlation entre hour et salaryNormalized***"""

#SS pour spic, la fonction pearsonr permet de calculer le coefficient de correlation 
ss.pearsonr(trainjob_copy['SalaryNormalized'], trainjob_copy['hour'])

"""On voit que le coefficient de correlation est assez faible, on peut deduire que les informations sur les heures recuperées n'ont pas de lien avec le salaire.

#### Extraction d'informations supplémentaires
Nous avons jugé bien de rajouter d'autres informations qui potentiellement pourraient influencer le salaire, a savoir:
* le diplome: licence, master et doctorat
* l'experience: l'existence du mot experience dans la description
* l'existence du terme "degree" signifiant diplome pour les offres d'emplois où le diplome a proprement dit n'y figure pas.
* l'existence du mot "knowledge" signifiant des "connaissance"
* l'existence du mot "education" signifiant "formation"
* la categorie du contrat: 'permanent', 'full-time', 'part-time', 'fixed-term', 'temporary', 'independent'.

l'hypothese faite ici est que: si ces informations ressortent a l'issu du traitement, nous considererons qu'ils sont requis pour le poste recherché pour les informations telles que diplome, experience, formation et connaissance.

Petites phase de netoyage.

Ici nous allons justes vectoriser ladite variable via la methode TF-IDF
"""

# Mettre la variable en minuscule
trainjob_copy['FullDescription'] = trainjob_copy['FullDescription'].map(lambda x: x.lower())
#Rétirer les urls
trainjob_copy['clean_desc'] = trainjob_copy['FullDescription'].map(remove_url)
#Retirer les ponctuations
trainjob_copy['clean_desc'] = trainjob_copy['clean_desc'].map(remove_punctuation)
#Retirer les nombres
trainjob_copy['clean_desc'] = trainjob_copy['clean_desc'].map(remove_num)
#Retirer les stopwords
trainjob_copy['clean_desc'] = trainjob_copy['clean_desc'].map(remove_stopword)
#Retirer les espaces supplementaires
trainjob_copy['clean_desc'] = trainjob_copy['clean_desc'].map(remove_extrablank)
#Lemmatiser les mots afin de les uniformiser
trainjob_copy['clean_desc'] = trainjob_copy['clean_desc'].map(lemma_1)
#Joindre les listes crées par l'etape de lemmatisation
trainjob_copy['clean_desc'] = trainjob_copy['clean_desc'].map(lemma_2)

word = ['licence', 'experience', 'benefit', 'degree', 'expert', 'skill', 'knowledge', 'education', 'master', 'phd', 'bachelor', 'fixed-term', 'temporary', 'independent']

for i in range(0,len(word)):
  for n in trainjob_copy.index:
    if word[i] in trainjob_copy['clean_desc'][n]:
      trainjob_copy.loc[n,word[i]] = 1
    else:
      trainjob_copy.loc[n,word[i]] = 0

#Representation graphique de la variable Licence
trainjob_copy['licence'].value_counts(normalize = True)

### Resultats ###
###0.0    0.952287###
###1.0    0.047713###

#Tableau croisé entre la colonne licence et la variable SalaryNormalized
trainjob_copy.pivot_table(index='licence',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / diplome(Licence)')
plt.xlabel('Licence(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable Experience
trainjob_copy['experience'].value_counts(normalize = True)

### Resultats ###
###0.0    0.184245###
###1.0    0.815755###

#Tableau croisé entre la colonne experience et la variable SalaryNormalized
trainjob_copy.pivot_table(index='experience',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Existence du mot Experience')
plt.xlabel('Experience(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable benefit
trainjob_copy['benefit'].value_counts(normalize = True)

### Resultats ###
###0.0    0.742833###
###1.0    0.257167###

#Tableau croisé entre la colonne benefit et la variable SalaryNormalized
trainjob_copy.pivot_table(index='benefit',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Existence du mot Benefit')
plt.xlabel('Benefit(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable degree
trainjob_copy['degree'].value_counts(normalize = True)

### Resultats ###
###0.0  0.877182###
###1.0  0.122818###

#Tableau croisé entre la colonne degree et la variable SalaryNormalized
trainjob_copy.pivot_table(index='degree',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Existence du mot "Degree"')
plt.xlabel('Degree(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable expert
trainjob_copy['expert'].value_counts(normalize = True)

### Resultats ###
###0.0  0.912295###
###1.0  0.087705###

#Tableau croisé entre la colonne expert et la variable SalaryNormalized
trainjob_copy.pivot_table(index='expert',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Existence du mot "Expert"')
plt.xlabel('Expert(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable skill
trainjob_copy['skill'].value_counts(normalize = True)

### Resultats ###
###0.0  0.455578###
###1.0  0.544422###

#Tableau croisé entre la colonne skill et la variable SalaryNormalized
trainjob_copy.pivot_table(index='skill',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Existence du mot "Skill"')
plt.xlabel('Skill(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable knowledge
trainjob_copy['knowledge'].value_counts(normalize = True)

### Resultats ###
###0.0  0.693458###
###1.0  0.306542###

#Tableau croisé entre la colonne knowledge et la variable SalaryNormalized
trainjob_copy.pivot_table(index='knowledge',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).plot(kind='bar')
plt.title('Salaire / Existence du mot "Knowledge"')
plt.xlabel('Knowledge(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable education
trainjob_copy['education'].value_counts(normalize = True)

### Resultats ###
###0.0  0.931547###
###1.0  0.068453###

#Tableau croisé entre la colonne education et la variable SalaryNormalized
trainjob_copy.pivot_table(index='education',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).plot(kind='bar')
plt.title('Salaire / Existence du mot "Education"')
plt.xlabel('Education(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable master
trainjob_copy['master'].value_counts(normalize = True)

### Resultats ###
###0.0  0.988356###
###1.0  0.011644###

#Tableau croisé entre la colonne master et la variable SalaryNormalized
trainjob_copy.pivot_table(index='master',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / diplome(Master)')
plt.xlabel('Master(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable phd
trainjob_copy['phd'].value_counts(normalize = True)

### Resultats ###
###0.0  0.995273###
###1.0  0.004727###

#Tableau croisé entre la colonne phd et la variable SalaryNormalized
trainjob_copy.pivot_table(index='phd',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / diplome(Phd)')
plt.xlabel('Phd(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable bachelor
trainjob_copy['bachelor'].value_counts(normalize = True)

### Resultats ###
###0.0  0.993884###
###1.0  0.006116###

#Tableau croisé entre la colonne bachelor et la variable SalaryNormalized
trainjob_copy.pivot_table(index='bachelor',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / diplome(Bachelor)')
plt.xlabel('Bachelor(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable temporary
trainjob_copy['temporary'].value_counts(normalize = True)

### Resultats ###
###0.0  0.917319###
###1.0  0.082681###

#Tableau croisé entre la colonne temporary et la variable SalaryNormalized
trainjob_copy.pivot_table(index='temporary',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Contrat(Temporary)')
plt.xlabel('Temporary(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable independent
trainjob_copy['independent'].value_counts(normalize = True)

### Resultats ###
###0.0  0.940983###
###1.0  0.059017###

#Tableau croisé entre la colonne independent et la variable SalaryNormalized
trainjob_copy.pivot_table(index='independent',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Contrat(Independent)')
plt.xlabel('Independent(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

"""Les informations recherchées à l'interieur de chaque description sont très peu representées. Cependant on se rencontre que les offres d'emploi pour lesquelles ces informations y figures ont une influence sur le salaire.
Finalement, nous allons opter pour l'analyse de la description totale des offres d'emplois via le clustering par la methode du TF-IDF.

### Separer le data trainjob en deux dataframe train et test
Cette option de spliter les donner d'entrainement en deux autres jeux de donnees d'entrainement et de test est pour nous un moyen de tester nos modeles sur deux jeu de donnees differents afin de s'assurer des resultats et de la robustesse.
"""

train_set = trainjob_copy.copy().sample(frac=0.6, random_state=0)
test_set = trainjob_copy.copy().drop(train_set.index)

print ('Training set')
print (train_set)
print ('\nTest set')
print (test_set)

"""#### Transformation Logarithmique: Standardisation de la variable SalaryNormalized"""

from math import log
train_set['SalaryNormalized_transform'] = train_set['SalaryNormalized'].apply( lambda x: log(x))
test_set['SalaryNormalized_transform'] = test_set['SalaryNormalized'].apply( lambda x: log(x))

trainjob_copy['SalaryNormalized_transform'] = trainjob_copy['SalaryNormalized'].apply( lambda x: log(x))
ax = sns.boxplot(x=trainjob_copy["SalaryNormalized_transform"])

#Vérification de la normalité de notre variable cible: On observe quelque outliers, cependant elle reste plus normale 
stats.probplot(trainjob_copy['SalaryNormalized_transform'], dist="norm", plot=pylab)
pylab.show()

"""#### Valeurs uniques"""

# Obtention des valeurs uniques dans notre jeu de donnees d'entrainement: On voit qu'il se peut que nous ayons des problemes pour la modelisation
# Car avant de modeliser sous python, les variables doivent numerique(sous entendu, nous devons les dichotomisés ou les vectorisés)  
train_set.select_dtypes('object').nunique(dropna = False)

"""**Afin de pouvoir reduire les dimensions dans notre jeu de donnees de façon a permettre la modelisation, nous allons clusteriser le titre et le nom de la societé dans un premier temps. Puis dans un deuxieme temps, nous allons tenter de vectoriser la variable FullDescription.**

### Travail sur la variable Title

#### K-means
"""

# Mettre la variable en minuscule
train_set['Title'] = train_set['Title'].map(lambda x: x.lower())

"""**La vectorisation que nous allons utiliser ici, se base une methode de machine learning beaucoup utiliser dans le traitement des textes. Nommé TF-IDF, elle permet de vectoriser chaque mot dans un copus en lui attribuant un nombre relativement a son apparition dans un corpus. En ce qui concerne le titre de l'offre, cette methode permettra à l'issu du regroupement fait sur les mots vectorisés de pouvoir les regroupeé par ressemblance et donc par vecteur proche.**"""

vectorizer = TfidfVectorizer(stop_words='english', ngram_range=(2,2))
X = vectorizer.fit_transform(train_set["Title"])

# Elbow Method(Methode du coude): Permet de determiner la valeur de K 

score = []

vectorizer = TfidfVectorizer(stop_words='english', ngram_range=(2,2))
X = vectorizer.fit_transform(train_set["Title"])

#for cluster in range(2,8):
#    kmeans = KMeans(n_clusters = cluster, init="k-means++", random_state=10)
#    kmeans.fit(X)
#    score.append(kmeans.inertia_)
#plt.plot(range(2,8), score)
#plt.title('The Elbow Method')
#plt.xlabel('no of clusters')
#plt.ylabel('wcss')
#plt.show()

#Application du clustering afin de determiner les mots discriminants donnant a l'offre d'emploi un caractere pertinent ou pas

true_k = 5
model_title = KMeans(n_clusters=true_k, init='k-means++', max_iter=100, random_state= 10, n_init=1)
model_title.fit(X)

#Pour presenter les mots contenant le cluster 
print("Top terms per cluster:")
order_centroids = model_title.cluster_centers_.argsort()[:, ::-1]
terms = vectorizer.get_feature_names()
for i in range(true_k):
    print("Cluster %d:" % i),
    for ind in order_centroids[i, :30]:
        print(' %s' % terms[ind]),
    print

#Nous avons appris sur les donnees d'entrainement, nous allons appliquer les resultats retenus aux données et les stockés dans une variable
Y = vectorizer.transform(test_set["Title"])

predict_X  = model_title.fit_predict(X)
train_set['Title_cluster'] = pd.Series(predict_X, index=train_set.index)

predict_Y  = model_title.fit_predict(Y)
test_set['Title_cluster'] = pd.Series(predict_Y, index=test_set.index)

train_set.pivot_table(index='Title_cluster',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).plot(kind='bar')
plt.title("Salaire en fonction des clusters du titre de l'offre")
plt.xlabel('Clusters')
plt.ylabel('Salaire moyen')
plt.show()

"""### Company

Nous allons effectuer le meme traitement ou du moins appliquer la meme methode de vectorisation pour la variable Company. De la meme maniere, le regroupement aura la meme portée, c'est a dire associé les mots dans le nom des societés qui sont les plus proches du point de vue de la vectorisation. Aussi comme la majorité des entreprises possede des noms composés, generalement, un nom propre a l'entreprise et un autre compris comme un suffixe.  
1.   Nous avons donc decidé de retirer les suffixes des noms des entreprises car, pour une meme entreprise les suffixes peuvent changer dans l'offre. Comme exemple : "Cox and David Limited" et "Cox and David Ltd".
2.   Nous avons decidé de faire de la vectorisation sur deux mots afin de concerver les entreprises dont les noms sont composés.
"""

train_set['Company'] = train_set['Company'].astype("string")
test_set['Company'] = test_set['Company'].astype("string")

train_set['Company'] = train_set['Company'].map(lambda x: x.lower())
test_set['Company'] = test_set['Company'].map(lambda x: x.lower())

train_set["Company_clean"] = train_set['Company'].map(stopword_company)
test_set["Company_clean"] = test_set['Company'].map(stopword_company)

# Elbow Method (la methode du coude):permettant de choisir la valeur de k 

score = []

vectorizer = TfidfVectorizer(stop_words='english', ngram_range=(2,2))
X = vectorizer.fit_transform(train_set["Company_clean"])

#Pour presenter le graphique correspondant à la methode du coude
for cluster in range(2,8):
    kmeans = KMeans(n_clusters = cluster, init="k-means++", random_state=10)
    kmeans.fit(X)
    score.append(kmeans.inertia_)
plt.plot(range(2,8), score)
plt.title('The Elbow Method')
plt.xlabel('no of clusters')
plt.ylabel('wcss')
plt.show()

#Application avec la valeur de k choisi

true_k = 4
model_comp = KMeans(n_clusters=true_k, init='k-means++', max_iter=100, n_init=1)
model_comp.fit(X)

#Pour presenter les mots contenant le cluster 
print("Top terms per cluster:")
order_centroids = model_comp.cluster_centers_.argsort()[:, ::-1]
terms = vectorizer.get_feature_names()
for i in range(true_k):
    print("Cluster %d:" % i),
    for ind in order_centroids[i, :30]:
        print(' %s' % terms[ind]),
    print

#Nous avons appris sur les donnees d'entrainement, nous allons appliquer les resultats retenus aux données et les stockés dans une variable
Y = vectorizer.transform(test_set["Company_clean"])

predict_X  = model_comp.fit_predict(X)
train_set['company_clus'] = pd.Series(predict_X, index=train_set.index)

predict_Y  = model_comp.fit_predict(Y)
test_set['company_clus'] = pd.Series(predict_Y, index=test_set.index)

train_set.pivot_table(index='company_clus',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).plot(kind='bar')
plt.title('Salaire en fonction des clusters de la societe')
plt.xlabel('Clusters')
plt.ylabel('Salaire moyen')
plt.show()

"""### Travail sur la variable FullDescription

### Numeriser la variable FullDescription
"""

#Application de la vectorisation apres avoir nettoyer la variable
vectorizer = TfidfVectorizer(stop_words='english', min_df = 0.01)
X = vectorizer.fit_transform(train_set["clean_desc"])
#Nous avons appris sur les donnees d'entrainement, nous allons appliquer les resultats retenus aux données et les stockés dans une variable
Y = vectorizer.transform(test_set["clean_desc"])

"""### PRINCIPAL COMPONENT ANALYSIS: Réduction de dimensionalité"""

#Telechargement de la librairie et application de la fonction PCA pour 400 composantes principales
from sklearn.decomposition import PCA
pca = PCA(400)
pca.fit(X.toarray())
pca.explained_variance_ratio_.cumsum()

"""Nous avons decidé de retirer seulement les dimentions qui explique environ 60% de la variance expliqué, d'ou les 400 composantes.

Ci-dessous le graphique representant les dimensions et le cumul de la variance expliquée par ces derniers.
"""

plt.figure(figsize = (10,8))
plt.plot(range(1,401), pca.explained_variance_ratio_.cumsum(), marker = 'o', linestyle = '--')
plt.title('Explained variance by components')
plt.xlabel('number of components')
plt.ylabel('cumulative explained variance')

"""### KMEANS POUR CLUSTERING SUR LES DIMENSIONS RETENUES:
Nous allons par la suite regrouper les dimensions dans des classes afin de mieux les apprehender. Ci-dessous la methode du coude permettant de choisir le nombre de classe adequat pour le regroupement. Il correspond a l'endroit sur le graphique ou nous observons un courde.
"""

X_pca = pca.fit_transform(X.toarray())
Y_pca = pca.transform(Y.toarray())

df_train = pd.DataFrame(pca.components_, columns=vectorizer.get_feature_names()).head(3).T
df_train.columns = ('PC1', 'PC2', 'PC3')
df_train_pc1 = df_train[df_train['PC1']>=df_train.PC1.mean()]['PC1']
df_train_pc2 = df_train[df_train['PC2']>=df_train.PC2.mean()]['PC2']
df_train_pc3 = df_train[df_train['PC3']>=df_train.PC3.mean()]['PC3']

df_train_pc3.sort_values(ascending=False).head(10).plot(kind='barh')
plt.title('Features de la troisième composante principale')
plt.xlabel('Coefficient dans la construction de la dimension')
plt.ylabel('Features')
plt.show()

#Elbow Method (la methode du coude):permettant de choisir la valeur de k 

score = []

#Pour presenter le graphique correspondant à la methode du coude
for cluster in range(2,9):
    kmeans = KMeans(n_clusters = cluster, init="k-means++", random_state=10)
    kmeans.fit(X_pca)
    score.append(kmeans.inertia_)
plt.figure(figsize = (10,8))
plt.plot(range(2,9), score)
plt.title('The Elbow Method')
plt.xlabel('no of clusters')
plt.ylabel('wcss')
plt.show()

#Application de l'algorithme de clustering sur la valeur de k choisi
true_k = 6
model_comp = KMeans(n_clusters=true_k, init='k-means++', random_state=10)
model_comp.fit(X_pca)

#Nous avons appris sur les donnees d'entrainement, nous allons appliquer les resultats retenus aux données et les stockés dans une variable
predict_X  = model_comp.predict(X_pca)
train_set['desc_clus'] = pd.Series(predict_X, index=train_set.index)

predict_Y  = model_comp.predict(Y_pca)
test_set['desc_clus'] = pd.Series(predict_Y, index=test_set.index)

#Representation graphique de la variable phd
train_set['desc_clus'].value_counts(normalize = True).plot(kind = 'bar')

train_set.pivot_table(index='desc_clus',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).plot(kind='bar')
plt.title('Salaire en fonction des clusters de description')
plt.xlabel('Clusters')
plt.ylabel('Salaire moyen')
plt.show()

#Cette fonction permet de stocker dans une liste un ensemble de dataframe correspondant chacun a un cluster ainsi que ses top 15 mots.
dfs = get_top_features_cluster(X.toarray(), predict_X, 10)

# Exemple de Répresentation du cluster 0
dfs[5].plot.barh(x='features', y='score')
plt.title('Cluster 5 :Graphs(top 10 words) ordered by relative importance as measured by TF-IDF')
plt.xlabel('Features')
plt.ylabel('Score')

"""### Preparing to modelling

#### Concatenating
"""

# Les colonnes à encoder avant modelisation
train_columns = ['ContractType', 'ContractTime', 'Category', 'Title_cluster','company_clus', 'desc_clus']

#Suppression des colonnes non utiles ou deja transformés
train = train_set.drop(['Id', 'Title', 'FullDescription', 'Company', 'clean_desc', 'Company_clean', 'SalaryNormalized','licence', 'experience', 'benefit', 'degree', 'expert', 'skill', 'knowledge', 'education', 'master', 'phd', 'bachelor', 'fixed-term', 'temporary', 'independent', 'hour'], axis=1)
test = test_set.drop(['Id', 'Title', 'FullDescription', 'Company', 'clean_desc', 'Company_clean', 'SalaryNormalized','licence', 'experience', 'benefit', 'degree', 'expert', 'skill', 'knowledge', 'education', 'master', 'phd', 'bachelor', 'fixed-term', 'temporary', 'independent', 'hour'], axis=1)

#Separation des donnees en donnees de variables explicatives (X) et de variables expliquées (y) 
X_train = train.drop(['SalaryNormalized_transform'], axis=1)
X_test = test.drop(['SalaryNormalized_transform'],axis=1)
y_train = train["SalaryNormalized_transform"]
y_test = test["SalaryNormalized_transform"]

#Dichotomisation des données
X_train_dum = pd.get_dummies(X_train, columns = train_columns)

X_test_dum = pd.get_dummies(X_test, columns = train_columns)

print("shape of X_train_dum :",X_train_dum.shape, "\n",
      "shape of X_test_dum :", X_test_dum.shape, "\n",
      "shape of y_train :", y_train.shape, "\n",
      "shape of y_test :", y_test.shape)

"""### Model Evaluation

There are three primary metrics used to evaluate linear models. These are: Mean absolute error (MAE), Mean squared error (MSE), or Root mean squared error (RMSE).

MAE: The easiest to understand. Represents average error

MSE: Similar to MAE but noise is exaggerated and larger errors are “punished”. It is harder to interpret than MAE as it’s not in base units, however, it is generally more popular.

RMSE: Most popular metric, similar to MSE, however, the result is square rooted to make it more interpretable as it’s in base units. It is recommended that RMSE be used as the primary metric to interpret your model.

Below, you can see how to calculate each metric. All of them require two lists as parameters, with one being your predicted values and the other being the true values

### Regression linéaire
"""

from sklearn.linear_model import LinearRegression
from sklearn.feature_selection import SelectKBest, f_regression
from sklearn import metrics

#model1 = SelectKBest(score_func=f_regression, k = 100)

#X_reg_new= model1.fit_transform(X_train_dum, y_train)
# Application des transf sur le jeu de données de test
#X_reg_test = model1.transform(X_test_dum)

model_reg = LinearRegression()

model_reg.fit(X_train_dum, y_train)

r_sq = model_reg.score(X_test_dum, y_test)
print('coefficient of determination:', r_sq, "\n")

y_pred = model_reg.predict(X_test_dum)

#print result of MAE
print("result of MAE sans transformation",metrics.mean_absolute_error(y_test, y_pred))

#print result of MAE
print("result of MAE",metrics.mean_absolute_error(np.exp(y_test), np.exp(y_pred)))

#print result of MSE
print("result of MSE",metrics.mean_squared_error(y_test, y_pred))

#print result of RMSE
print("result of RMSE", np.sqrt(metrics.mean_squared_error(y_test,y_pred)))

"""#### Regression LASSO"""

from sklearn.linear_model import LassoCV, RidgeCV

# define model
model_lasso = LassoCV()

# fit model
model_lasso.fit(X_train_dum, y_train)

y_pred = model_lasso.predict(X_test_dum)
#print result of MAE
print("result of MAE sans transformation",metrics.mean_absolute_error(y_test, y_pred))

#print result of MAE
print("result of MAE",metrics.mean_absolute_error(np.exp(y_test), np.exp(y_pred)))

#print result of MSE
print("result of MSE",metrics.mean_squared_error(y_test, y_pred))

#print result of RMSE
print("result of RMSE", np.sqrt(metrics.mean_squared_error(y_test,y_pred)))

"""### Ridge Regression"""

# define model
model_ridge = RidgeCV()

# fit model
model_ridge.fit(X_train_dum, y_train)

y_pred = model_ridge.predict(X_test_dum)
#print result of MAE
print("result of MAE sans transformation",metrics.mean_absolute_error(y_test, y_pred))

#print result of MAE
print("result of MAE",metrics.mean_absolute_error(np.exp(y_test), np.exp(y_pred)))

#print result of MSE
print("result of MSE",metrics.mean_squared_error(y_test, y_pred))

#print result of RMSE
print("result of RMSE", np.sqrt(metrics.mean_squared_error(y_test,y_pred)))

"""### Decision Tree"""

from sklearn.tree import DecisionTreeRegressor
#Create an object (model)
model_tree = DecisionTreeRegressor(criterion='mae')

#Fit (train) the model
model_tree.fit(X_train_dum, y_train)

y_pred = model_tree.predict(X_test_dum)

#print result of MAE
print("result of MAE sans transformation",metrics.mean_absolute_error(y_test, y_pred))

#print result of MAE
print("result of MAE",metrics.mean_absolute_error(np.exp(y_test), np.exp(y_pred)))

#print result of MSE
print("result of MSE",metrics.mean_squared_error(y_test, y_pred))

#print result of RMSE
print("result of RMSE", np.sqrt(metrics.mean_squared_error(y_test,y_pred)))

"""### Random Forest"""

#Import Library
from sklearn.ensemble import RandomForestRegressor
#Create an object (model)
model_random = RandomForestRegressor(n_estimators = 10, criterion='mae')

#Fit (train) the model
model_random.fit(X_train_dum, y_train)

y_pred = model_random.predict(X_test_dum)

from sklearn import metrics
#print result of MAE
print("result of MAE sans transformation",metrics.mean_absolute_error(y_test, y_pred))

#print result of MAE
print("result of MAE",metrics.mean_absolute_error(np.exp(y_test), np.exp(y_pred)))

#print result of MSE
print("result of MSE",metrics.mean_squared_error(y_test, y_pred))

#print result of RMSE
print("result of RMSE", np.sqrt(metrics.mean_squared_error(y_test,y_pred)))

"""### Plot Graphic to see feature importance"""

plt.rcParams.update({'figure.figsize': (12.0, 8.0)})
plt.rcParams.update({'font.size': 14})
sorted_idx = model_random.feature_importances_.argsort()[43:54]
plt.barh(X_train_dum.columns[sorted_idx], model_random.feature_importances_[sorted_idx])
plt.xlabel("Score")
plt.title("Niveau d'importance des caracteristiques dans le modèle")
plt.ylabel('Features')
plt.show()

"""### TEST data """

#Affichage des variables dont il existe des valeurs manquantes 
#Telechargement du jeu de donnee
test_job = pd.read_csv("/content/gdrive/MyDrive/ProjetBigData/test.csv", encoding="utf-8")
#trainjob['LocationNormalized']=trainjob['LocationNormalized'].astype('string')
test_job['LocationRaw']=test_job['LocationRaw'].astype('string')
test_job['Location_Raw'] = test_job['LocationRaw'].str.split(',')

test_job.info(2)

#Liste des villes les plus cheres en UK
exp_cities = ['London', 'Cambridge','Oxford','Bournemouth','Bristol', 'Portsmouth', 
              'Edinburgh', 'Southampton']

#Création d'un top_location 0 si la ville de mon dataframe ne fait pas partie et 1 si elle fait partie
test_job['top_location'] = test_job['LocationNormalized'].map(lambda place: 1 if place in exp_cities else 0)
test_job = test_job[['Id','Title', 'FullDescription','top_location','ContractType', 'ContractTime','Company','Category']]

test_job.shape

test_job.isnull().sum()[test_job.isnull().sum()>0]

#imputation des valeurs manquantes par la valeur 'notSpecified'

test_job["ContractType"].fillna('notSpecified', inplace = True)
test_job["ContractTime"].fillna('notSpecified', inplace = True)
test_job["Company"].fillna('notSpecified', inplace = True)

#Verivfication du traitement des donnees manquantes

print("Initial data missing values")
print(test_job.isnull().sum())

#attribution du cluster au dataframe relativement a son index
Y = vectorizer.transform(test_job["Title"])

predict_Y  = model_title.fit_predict(Y)
test_job['Title_cluster'] = pd.Series(predict_Y, index=test_job.index)

test_job.shape

test_job['Company'] = test_job['Company'].astype("string")
test_job['Company'] = test_job['Company'].map(lambda x: x.lower())
test_job["Company_clean"] = test_job['Company'].map(stopword_company)

test_job.shape

#attribution du cluster au dataframe relativement a son index
Y = vectorizer.transform(test_job["Company_clean"])

predict_Y  = model_comp.fit_predict(Y)
test_job['company_clus'] = pd.Series(predict_Y, index=test_job.index)

test_job.shape

#Jeu de test
# Mettre la variable en minuscule
test_job['FullDescription'] = test_job['FullDescription'].map(lambda x: x.lower())
#Garder que les caractères alphabetiques
test_job['clean_desc'] = test_job['FullDescription'].map(remove_url)
test_job['clean_desc'] = test_job['clean_desc'].map(remove_punctuation)
test_job['clean_desc'] = test_job['clean_desc'].map(remove_num)
test_job['clean_desc'] = test_job['clean_desc'].map(remove_stopword)
test_job['clean_desc'] = test_job['clean_desc'].map(remove_extrablank)
test_job['clean_desc'] = test_job['clean_desc'].map(lemma_1)
test_job['clean_desc'] = test_job['clean_desc'].map(lemma_2)

Y = vectorizer.transform(test_job["clean_desc"])
Y_pca = pca.transform(Y.toarray())

predict_Y  = model_comp.predict(Y_pca)
test_set['desc_clus'] = pd.Series(predict_Y, index=test_job.index)

test = test_set.drop(['Id', 'Title', 'FullDescription', 'Company', 'clean_desc', 'Company_clean'], axis=1)
test.shape

test_job_columns = ['ContractType', 'ContractTime', 'Category', 'Title_cluster','company_clus', 'desc_clus']
X_test_dum = pd.get_dummies(test, columns = test_job_columns)

X_test_dum.shape

#Regresion Lineaire
y_pred = model_random.predict(X_test_dum)
test_job['SalaryNormalized'] = np.exp(y_pred)

submission = test_job[["Id", "SalaryNormalized"]]

submission.head(20)

"""# Export"""

train_set.to_csv("/content/gdrive/MyDrive/ProjetBigData/trainset1.csv", index=False)

"""# MERCI A TOUS ET A CHACUN POUR VOTRE DEVOUEMENT ET VOTRE TENACITE:) 4eme 
                                  ## Score de submission: 8308.85

"""
463c5675a1790024f56fe477641bfe6af9b92e4a
# -*- coding: utf-8 -*-
"""ProjetBigData.ipynb

Automatically generated by Colaboratory.

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

from google.colab import drive
drive.mount('/content/gdrive')

!ls "/content/gdrive/MyDrive/ProjetBigData"

"""### Telechargement des Librairies Pour l'etude du Projet Big Data"""

!pip install researchpy
import spacy
import en_core_web_sm
from textblob import TextBlob
from textblob import Word
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import scipy.stats as ss
import nltk
import re
from researchpy import crosstab
import random
from nltk.stem import WordNetLemmatizer 
from nltk.corpus import wordnet
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from sklearn.cluster import KMeans 
import pylab 
import scipy.stats as stats
nltk.download('punkt')
nltk.download('stopwords')
nltk.download('wordnet')
nltk.download('averaged_perceptron_tagger')
nltk.download('brown')

"""### Importation des jeu de donnees (TRAIN d'abord)"""

#Telechargement du jeu de donnee
trainjob = pd.read_csv("/content/gdrive/MyDrive/ProjetBigData/final_train.csv", encoding="utf-8")
trainjob['LocationRaw']=trainjob['LocationRaw'].astype('string')
trainjob['Location_Raw'] = trainjob['LocationRaw'].str.split(',')

#Description du jeu de donnees
trainjob.info(2)

"""### Valeurs manquantes(nombre)"""

#Affichage des variables dont il existe des valeurs manquantes 
trainjob_copy = trainjob.copy()
trainjob_copy.isnull().sum()[trainjob_copy.isnull().sum()>0]

"""# TRAITEMENTS

## LES FONCTIONS
"""

# Retirer les liens
def remove_url(s):
    s = re.sub('[^\s]*.com[^\s]*', "", s)
    s = re.sub('[^\s]*www.[^\s]*', "", s)
    s = re.sub('[^\s]*.co.uk[^\s]*', "", s)
    return s

#Retirer les chiffres de la description
def remove_num(s):
    return re.sub("[^\s]*[0-9]+[^\s]*", "", s)

#Retirer les espaces supplementaires de la description
def remove_extrablank(s):
  return re.sub(" +"," ",s)

# Retirer les ponctuations de la description
from string import punctuation
def remove_punctuation(s):
    global punctuation
    for p in punctuation:
        s = s.replace(p, ' ')
        s = s.replace('–',' ')
        s = s.replace("’",' ')
        s = re.sub(r"(?<= ).{1}(?= )"," ",s) 
    return s

# Retirer les stopwords de la description
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
en_stopwords = stopwords.words('english')
def remove_stopword(s):
    global en_stopwords
    s = word_tokenize(s)
    s = " ".join([w for w in s if w not in en_stopwords])
    return s

def stopword_company(name):
  words = [ "Agency", "Gmbh", "PA", "and", "Group", "PC", "Assn", "Hotel", "Pharmacy", "Assoc", "Hotels", "PLC", "Associates", "Inc", "PLLC", "Association", "Incorporated",
             "Restaurant", "Bank", "International", "SA", "BV", "Intl", "Sales", "Co", "Limited", "Service", "Comp", "LLC", "Services", "Company", "LLP", "Store", "Corp", "LP",
             "Svcs", "Corporation",  "Ltd", "Travel", "DMD", "Manufacturing", "Unlimited", "Enterprises", "Mfg"]
  for i in words:
    b = i.lower()
    if b in name.split(" "):
        name = re.sub(b,'',name)
  return name


def lemma_1(s):
  liste = []
  for i in TextBlob(s).words:
    liste.append(Word(Word(i).lemmatize()).lemmatize('v'))
  return liste

def lemma_2(s):
  list_v = " ".join(s)
  return list_v

#Cette fonction permet de stocker dans une liste un ensemble de dataframe correspondant chacun a un cluster ainsi que ses top 15 mots.
def get_top_features_cluster(tf_idf_array, prediction, n_feats):
    labels = np.unique(prediction)
    dfs = []
    for label in labels:
        id_temp = np.where(prediction==label) # indices for each cluster
        x_means = np.mean(tf_idf_array[id_temp], axis = 0) # returns average score across cluster
        sorted_means = np.argsort(x_means)[::-1][:n_feats] # indices with top 20 scores
        features = vectorizer.get_feature_names()
        best_features = [(features[i], x_means[i]) for i in sorted_means]
        df = pd.DataFrame(best_features, columns = ['features', 'score'])
        dfs.append(df)
    return dfs

"""### Donnees manquantes (%)"""

print("Initial data missing values")
print(trainjob_copy.isnull().sum()[trainjob_copy.isnull().sum()>0]/len(trainjob_copy))

"""### Imputation par "notSpecified" pour les variables contratype, contractime company"""

#imputation des valeurs manquantes par la valeur 'notSpecified'
trainjob_copy.fillna('notSpecified', inplace = True)

#Verivfication du traitement des donnees manquantes
print("Initial data missing values")
print(trainjob_copy.isnull().sum())

"""### Liste des villes les plus cher en UK"""

#Liste des villes les plus cheres en UK
exp_cities = ['London', 'Cambridge','Oxford','Bournemouth','Bristol', 'Portsmouth', 
              'Edinburgh', 'Southampton']

#Création d'un top_location 0 si la ville de mon dataframe ne fait pas partie et 1 si elle fait partie
trainjob_copy['top_location'] = trainjob_copy['LocationNormalized'].map(lambda place: 1 if place in exp_cities else 0)

#subset dataset column
trainjob_copy = trainjob_copy[['Id','Title', 'FullDescription','top_location','ContractType', 'ContractTime','Company','Category','SalaryNormalized']].copy()

"""### Statistiques univariées

### Normaliser la variable SalaryNormalized
"""

# Quelques statistiques sur la variable salary_normalized
trainjob_copy['SalaryNormalized'].describe()

#Presentation du QQ_plot
stats.probplot(trainjob_copy['SalaryNormalized'], dist="norm", plot=pylab)
pylab.show()

#Boxplot de salaire
ax = sns.boxplot(x=trainjob_copy["SalaryNormalized"])

"""### Suppression des donnees aberrantes de SalaryNormalilzed
Par la methode de l'intervalle interquartile des boites à moustaches
"""

# Calcul des quantiles
q1_salary = trainjob_copy['SalaryNormalized'].quantile(0.25)
q3_salary = trainjob_copy['SalaryNormalized'].quantile(0.75)
# Calcul de l'IQR
IQR = q3_salary - q1_salary
upper_salary = q3_salary + 1.5 * IQR
trainjob_copy[trainjob_copy['SalaryNormalized'] > upper_salary].count()

trainjob1 = trainjob[trainjob['SalaryNormalized']>upper_salary]

#Representation graphiques des dix premieres plus frequentes valeurs
trainjob1['Title'].value_counts().head(30).plot(kind='bar')

"""#### Contrat-type et Contract-time"""

# les valeurs uniques de cette variable
trainjob_copy['ContractTime'].value_counts()

#Representation graphique des dites variables
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(15, 15))
def label_function(val):
    return f'{val / 100 * len(trainjob):.0f}\n{val:.0f}%'
trainjob_copy.groupby('ContractType').size().plot(kind='pie', autopct=label_function, textprops={'fontsize': 20},
                                  colors=['tomato', 'gold', 'skyblue'], ax=ax1)
trainjob_copy.groupby('ContractTime').size().plot(kind='pie', autopct=label_function, textprops={'fontsize': 20},
                                 colors=['violet', 'lime', 'red'], ax=ax2)
ax1.set_ylabel('ContractType', size=22)
ax2.set_ylabel('ContractTime', size=22)
plt.tight_layout()
plt.show()

"""#### Title"""

#Valeur Unique
trainjob_copy['Title'].value_counts().count() # 62739 valeurs differentes

#les dix premieres plus frequentes valeurs
trainjob_copy['Title'].value_counts().head(10).plot(kind='bar')

#Representation d'un graphique croisé presentant le salaire moyen par title de metier
table = trainjob_copy.pivot_table(index='Title',values='SalaryNormalized', aggfunc=np.mean)
table = table.reindex(table['SalaryNormalized'].sort_values(ascending=False).index)
table = table.head(10)
plt.barh(table.index, table.SalaryNormalized)

"""#### Category"""

#Valeur Unique
trainjob_copy['Category'].value_counts().count() # 28 valeurs differentes

#Representation graphiques des dix premieres plus frequentes valeurs
trainjob_copy['Category'].value_counts().head(10).plot(kind='bar')

#Representation d'un graphique croisé presentant le salaire moyen par categorie de metier
table = trainjob_copy.pivot_table(index='Category',values='SalaryNormalized', aggfunc=np.mean)
table = table.reindex(table['SalaryNormalized'].sort_values(ascending=False).index)
table = table.head(10)
plt.barh(table.index, table.SalaryNormalized)

"""#### Company"""

#Valeur Unique
trainjob_copy['Company'].value_counts().count() # 14511 valeurs differentes

#les dix premieres plus frequentes valeurs
trainjob_copy['Company'].value_counts().head(10).plot(kind='bar')

# Representation d'un graphique croisé presentant le salaire moyen par societe emettrice
table = trainjob_copy.pivot_table(index='Company',values='SalaryNormalized', aggfunc=np.mean)
table = table.reindex(table['SalaryNormalized'].sort_values(ascending=False).index)
table = table.head(10)
plt.barh(table.index, table.SalaryNormalized)

"""### Top_location"""

#Valeur Unique
trainjob_copy['top_location'].value_counts().plot(kind = 'pie',autopct=label_function, figsize = (6,6)) # 2 valeurs differentes
plt.title('Frequence Top_location')
plt.xlabel('Top_location(1 = "< au cout moyen", 0 = "> au cout moyen")')
plt.ylabel(' ')
plt.show()

#Tableau croisé entre le salaire et la variable Location
trainjob_copy.pivot_table(index='top_location',values='SalaryNormalized', aggfunc=np.mean)

"""#### Extraction des heures dans la description

**Nous pensons que les heures de travail ont une infulence sur le salaire. Etant donné que nous ne disposons pas de caracteristiques dans nos jeu de donnees permettant d'estimer cela, nous allons dans cette partie essayer de retirer les heures travailler dans le feature FullDescription.**
"""

#Create column hour
trainjob_copy['hour'] = 0
#trainjob['Clean_Full_Descriptions_no_stop'] = trainjob['Clean_Full_Descriptions_no_stop'].astype('string')
for i in trainjob_copy.index:
  if trainjob_copy['FullDescription'].loc[i].__contains__("hours per week") == True:
    m = re.search(r"(\w{1}|\w{2}|\w{3})(?=( hours per week|hours per week))",trainjob_copy['FullDescription'].loc[i])
    if str(m)== 'None':
      continue
    elif str(m) != 'None' and m.group(0).strip().isnumeric() == True:
      if len(m.group(0).strip())==3:
        trainjob_copy['hour'].loc[i] = pd.to_numeric(m.group(0).strip()[:2]+'.'+m.group(0).strip()[2:])
      else:
        trainjob_copy['hour'].loc[i] = pd.to_numeric(m.group(0).strip())
      continue

"""**Relation entre heures et salaire**"""

#Valeur Unique
trainjob_copy['hour'].value_counts().count() # 2 valeurs differentes

#Representation graphique de la repartition de ladite variable
trainjob_copy['hour'].value_counts(normalize = True).head(10)

#Tableau croisé entre la colonne heure et le salaire
trainjob_copy.pivot_table(index='hour',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire en fonction des heures(10 premiers chiffres)')
plt.xlabel('Heures')
plt.ylabel('Salaire moyen')
plt.show()

"""***Coefficient de correlation entre hour et salaryNormalized***"""

#SS pour spic, la fonction pearsonr permet de calculer le coefficient de correlation 
ss.pearsonr(trainjob_copy['SalaryNormalized'], trainjob_copy['hour'])

"""On voit que le coefficient de correlation est assez faible, on peut deduire que les informations sur les heures recuperées n'ont pas de lien avec le salaire.

#### Extraction d'informations supplémentaires
Nous avons jugé bien de rajouter d'autres informations qui potentiellement pourraient influencer le salaire, a savoir:
* le diplome: licence, master et doctorat
* l'experience: l'existence du mot experience dans la description
* l'existence du terme "degree" signifiant diplome pour les offres d'emplois où le diplome a proprement dit n'y figure pas.
* l'existence du mot "knowledge" signifiant des "connaissance"
* l'existence du mot "education" signifiant "formation"
* la categorie du contrat: 'permanent', 'full-time', 'part-time', 'fixed-term', 'temporary', 'independent'.

l'hypothese faite ici est que: si ces informations ressortent a l'issu du traitement, nous considererons qu'ils sont requis pour le poste recherché pour les informations telles que diplome, experience, formation et connaissance.

Petites phase de netoyage.

Ici nous allons justes vectoriser ladite variable via la methode TF-IDF
"""

# Mettre la variable en minuscule
trainjob_copy['FullDescription'] = trainjob_copy['FullDescription'].map(lambda x: x.lower())
#Rétirer les urls
trainjob_copy['clean_desc'] = trainjob_copy['FullDescription'].map(remove_url)
#Retirer les ponctuations
trainjob_copy['clean_desc'] = trainjob_copy['clean_desc'].map(remove_punctuation)
#Retirer les nombres
trainjob_copy['clean_desc'] = trainjob_copy['clean_desc'].map(remove_num)
#Retirer les stopwords
trainjob_copy['clean_desc'] = trainjob_copy['clean_desc'].map(remove_stopword)
#Retirer les espaces supplementaires
trainjob_copy['clean_desc'] = trainjob_copy['clean_desc'].map(remove_extrablank)
#Lemmatiser les mots afin de les uniformiser
trainjob_copy['clean_desc'] = trainjob_copy['clean_desc'].map(lemma_1)
#Joindre les listes crées par l'etape de lemmatisation
trainjob_copy['clean_desc'] = trainjob_copy['clean_desc'].map(lemma_2)

word = ['licence', 'experience', 'benefit', 'degree', 'expert', 'skill', 'knowledge', 'education', 'master', 'phd', 'bachelor', 'fixed-term', 'temporary', 'independent']

for i in range(0,len(word)):
  for n in trainjob_copy.index:
    if word[i] in trainjob_copy['clean_desc'][n]:
      trainjob_copy.loc[n,word[i]] = 1
    else:
      trainjob_copy.loc[n,word[i]] = 0

#Representation graphique de la variable Licence
trainjob_copy['licence'].value_counts(normalize = True)

### Resultats ###
###0.0    0.952287###
###1.0    0.047713###

#Tableau croisé entre la colonne licence et la variable SalaryNormalized
trainjob_copy.pivot_table(index='licence',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / diplome(Licence)')
plt.xlabel('Licence(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable Experience
trainjob_copy['experience'].value_counts(normalize = True)

### Resultats ###
###0.0    0.184245###
###1.0    0.815755###

#Tableau croisé entre la colonne experience et la variable SalaryNormalized
trainjob_copy.pivot_table(index='experience',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Existence du mot Experience')
plt.xlabel('Experience(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable benefit
trainjob_copy['benefit'].value_counts(normalize = True)

### Resultats ###
###0.0    0.742833###
###1.0    0.257167###

#Tableau croisé entre la colonne benefit et la variable SalaryNormalized
trainjob_copy.pivot_table(index='benefit',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Existence du mot Benefit')
plt.xlabel('Benefit(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable degree
trainjob_copy['degree'].value_counts(normalize = True)

### Resultats ###
###0.0  0.877182###
###1.0  0.122818###

#Tableau croisé entre la colonne degree et la variable SalaryNormalized
trainjob_copy.pivot_table(index='degree',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Existence du mot "Degree"')
plt.xlabel('Degree(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable expert
trainjob_copy['expert'].value_counts(normalize = True)

### Resultats ###
###0.0  0.912295###
###1.0  0.087705###

#Tableau croisé entre la colonne expert et la variable SalaryNormalized
trainjob_copy.pivot_table(index='expert',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Existence du mot "Expert"')
plt.xlabel('Expert(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable skill
trainjob_copy['skill'].value_counts(normalize = True)

### Resultats ###
###0.0  0.455578###
###1.0  0.544422###

#Tableau croisé entre la colonne skill et la variable SalaryNormalized
trainjob_copy.pivot_table(index='skill',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Existence du mot "Skill"')
plt.xlabel('Skill(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable knowledge
trainjob_copy['knowledge'].value_counts(normalize = True)

### Resultats ###
###0.0  0.693458###
###1.0  0.306542###

#Tableau croisé entre la colonne knowledge et la variable SalaryNormalized
trainjob_copy.pivot_table(index='knowledge',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).plot(kind='bar')
plt.title('Salaire / Existence du mot "Knowledge"')
plt.xlabel('Knowledge(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable education
trainjob_copy['education'].value_counts(normalize = True)

### Resultats ###
###0.0  0.931547###
###1.0  0.068453###

#Tableau croisé entre la colonne education et la variable SalaryNormalized
trainjob_copy.pivot_table(index='education',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).plot(kind='bar')
plt.title('Salaire / Existence du mot "Education"')
plt.xlabel('Education(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable master
trainjob_copy['master'].value_counts(normalize = True)

### Resultats ###
###0.0  0.988356###
###1.0  0.011644###

#Tableau croisé entre la colonne master et la variable SalaryNormalized
trainjob_copy.pivot_table(index='master',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / diplome(Master)')
plt.xlabel('Master(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable phd
trainjob_copy['phd'].value_counts(normalize = True)

### Resultats ###
###0.0  0.995273###
###1.0  0.004727###

#Tableau croisé entre la colonne phd et la variable SalaryNormalized
trainjob_copy.pivot_table(index='phd',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / diplome(Phd)')
plt.xlabel('Phd(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable bachelor
trainjob_copy['bachelor'].value_counts(normalize = True)

### Resultats ###
###0.0  0.993884###
###1.0  0.006116###

#Tableau croisé entre la colonne bachelor et la variable SalaryNormalized
trainjob_copy.pivot_table(index='bachelor',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / diplome(Bachelor)')
plt.xlabel('Bachelor(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable temporary
trainjob_copy['temporary'].value_counts(normalize = True)

### Resultats ###
###0.0  0.917319###
###1.0  0.082681###

#Tableau croisé entre la colonne temporary et la variable SalaryNormalized
trainjob_copy.pivot_table(index='temporary',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Contrat(Temporary)')
plt.xlabel('Temporary(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

#Representation graphique de la variable independent
trainjob_copy['independent'].value_counts(normalize = True)

### Resultats ###
###0.0  0.940983###
###1.0  0.059017###

#Tableau croisé entre la colonne independent et la variable SalaryNormalized
trainjob_copy.pivot_table(index='independent',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).head(10).plot(kind='bar')
plt.title('Salaire / Contrat(Independent)')
plt.xlabel('Independent(1 = Oui, 0 = Non)')
plt.ylabel('Salaire moyen')
plt.show()

"""Les informations recherchées à l'interieur de chaque description sont très peu representées. Cependant on se rencontre que les offres d'emploi pour lesquelles ces informations y figures ont une influence sur le salaire.
Finalement, nous allons opter pour l'analyse de la description totale des offres d'emplois via le clustering par la methode du TF-IDF.

### Separer le data trainjob en deux dataframe train et test
Cette option de spliter les donner d'entrainement en deux autres jeux de donnees d'entrainement et de test est pour nous un moyen de tester nos modeles sur deux jeu de donnees differents afin de s'assurer des resultats et de la robustesse.
"""

train_set = trainjob_copy.copy().sample(frac=0.6, random_state=0)
test_set = trainjob_copy.copy().drop(train_set.index)

print ('Training set')
print (train_set)
print ('\nTest set')
print (test_set)

"""#### Transformation Logarithmique: Standardisation de la variable SalaryNormalized"""

from math import log
train_set['SalaryNormalized_transform'] = train_set['SalaryNormalized'].apply( lambda x: log(x))
test_set['SalaryNormalized_transform'] = test_set['SalaryNormalized'].apply( lambda x: log(x))

trainjob_copy['SalaryNormalized_transform'] = trainjob_copy['SalaryNormalized'].apply( lambda x: log(x))
ax = sns.boxplot(x=trainjob_copy["SalaryNormalized_transform"])

#Vérification de la normalité de notre variable cible: On observe quelque outliers, cependant elle reste plus normale 
stats.probplot(trainjob_copy['SalaryNormalized_transform'], dist="norm", plot=pylab)
pylab.show()

"""#### Valeurs uniques"""

# Obtention des valeurs uniques dans notre jeu de donnees d'entrainement: On voit qu'il se peut que nous ayons des problemes pour la modelisation
# Car avant de modeliser sous python, les variables doivent numerique(sous entendu, nous devons les dichotomisés ou les vectorisés)  
train_set.select_dtypes('object').nunique(dropna = False)

"""**Afin de pouvoir reduire les dimensions dans notre jeu de donnees de façon a permettre la modelisation, nous allons clusteriser le titre et le nom de la societé dans un premier temps. Puis dans un deuxieme temps, nous allons tenter de vectoriser la variable FullDescription.**

### Travail sur la variable Title

#### K-means
"""

# Mettre la variable en minuscule
train_set['Title'] = train_set['Title'].map(lambda x: x.lower())

"""**La vectorisation que nous allons utiliser ici, se base une methode de machine learning beaucoup utiliser dans le traitement des textes. Nommé TF-IDF, elle permet de vectoriser chaque mot dans un copus en lui attribuant un nombre relativement a son apparition dans un corpus. En ce qui concerne le titre de l'offre, cette methode permettra à l'issu du regroupement fait sur les mots vectorisés de pouvoir les regroupeé par ressemblance et donc par vecteur proche.**"""

vectorizer = TfidfVectorizer(stop_words='english', ngram_range=(2,2))
X = vectorizer.fit_transform(train_set["Title"])

# Elbow Method(Methode du coude): Permet de determiner la valeur de K 

score = []

vectorizer = TfidfVectorizer(stop_words='english', ngram_range=(2,2))
X = vectorizer.fit_transform(train_set["Title"])

#for cluster in range(2,8):
#    kmeans = KMeans(n_clusters = cluster, init="k-means++", random_state=10)
#    kmeans.fit(X)
#    score.append(kmeans.inertia_)
#plt.plot(range(2,8), score)
#plt.title('The Elbow Method')
#plt.xlabel('no of clusters')
#plt.ylabel('wcss')
#plt.show()

#Application du clustering afin de determiner les mots discriminants donnant a l'offre d'emploi un caractere pertinent ou pas

true_k = 5
model_title = KMeans(n_clusters=true_k, init='k-means++', max_iter=100, random_state= 10, n_init=1)
model_title.fit(X)

#Pour presenter les mots contenant le cluster 
print("Top terms per cluster:")
order_centroids = model_title.cluster_centers_.argsort()[:, ::-1]
terms = vectorizer.get_feature_names()
for i in range(true_k):
    print("Cluster %d:" % i),
    for ind in order_centroids[i, :30]:
        print(' %s' % terms[ind]),
    print

#Nous avons appris sur les donnees d'entrainement, nous allons appliquer les resultats retenus aux données et les stockés dans une variable
Y = vectorizer.transform(test_set["Title"])

predict_X  = model_title.fit_predict(X)
train_set['Title_cluster'] = pd.Series(predict_X, index=train_set.index)

predict_Y  = model_title.fit_predict(Y)
test_set['Title_cluster'] = pd.Series(predict_Y, index=test_set.index)

train_set.pivot_table(index='Title_cluster',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).plot(kind='bar')
plt.title("Salaire en fonction des clusters du titre de l'offre")
plt.xlabel('Clusters')
plt.ylabel('Salaire moyen')
plt.show()

"""### Company

Nous allons effectuer le meme traitement ou du moins appliquer la meme methode de vectorisation pour la variable Company. De la meme maniere, le regroupement aura la meme portée, c'est a dire associé les mots dans le nom des societés qui sont les plus proches du point de vue de la vectorisation. Aussi comme la majorité des entreprises possede des noms composés, generalement, un nom propre a l'entreprise et un autre compris comme un suffixe.  
1.   Nous avons donc decidé de retirer les suffixes des noms des entreprises car, pour une meme entreprise les suffixes peuvent changer dans l'offre. Comme exemple : "Cox and David Limited" et "Cox and David Ltd".
2.   Nous avons decidé de faire de la vectorisation sur deux mots afin de concerver les entreprises dont les noms sont composés.
"""

train_set['Company'] = train_set['Company'].astype("string")
test_set['Company'] = test_set['Company'].astype("string")

train_set['Company'] = train_set['Company'].map(lambda x: x.lower())
test_set['Company'] = test_set['Company'].map(lambda x: x.lower())

train_set["Company_clean"] = train_set['Company'].map(stopword_company)
test_set["Company_clean"] = test_set['Company'].map(stopword_company)

# Elbow Method (la methode du coude):permettant de choisir la valeur de k 

score = []

vectorizer = TfidfVectorizer(stop_words='english', ngram_range=(2,2))
X = vectorizer.fit_transform(train_set["Company_clean"])

#Pour presenter le graphique correspondant à la methode du coude
for cluster in range(2,8):
    kmeans = KMeans(n_clusters = cluster, init="k-means++", random_state=10)
    kmeans.fit(X)
    score.append(kmeans.inertia_)
plt.plot(range(2,8), score)
plt.title('The Elbow Method')
plt.xlabel('no of clusters')
plt.ylabel('wcss')
plt.show()

#Application avec la valeur de k choisi

true_k = 4
model_comp = KMeans(n_clusters=true_k, init='k-means++', max_iter=100, n_init=1)
model_comp.fit(X)

#Pour presenter les mots contenant le cluster 
print("Top terms per cluster:")
order_centroids = model_comp.cluster_centers_.argsort()[:, ::-1]
terms = vectorizer.get_feature_names()
for i in range(true_k):
    print("Cluster %d:" % i),
    for ind in order_centroids[i, :30]:
        print(' %s' % terms[ind]),
    print

#Nous avons appris sur les donnees d'entrainement, nous allons appliquer les resultats retenus aux données et les stockés dans une variable
Y = vectorizer.transform(test_set["Company_clean"])

predict_X  = model_comp.fit_predict(X)
train_set['company_clus'] = pd.Series(predict_X, index=train_set.index)

predict_Y  = model_comp.fit_predict(Y)
test_set['company_clus'] = pd.Series(predict_Y, index=test_set.index)

train_set.pivot_table(index='company_clus',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).plot(kind='bar')
plt.title('Salaire en fonction des clusters de la societe')
plt.xlabel('Clusters')
plt.ylabel('Salaire moyen')
plt.show()

"""### Travail sur la variable FullDescription

### Numeriser la variable FullDescription
"""

#Application de la vectorisation apres avoir nettoyer la variable
vectorizer = TfidfVectorizer(stop_words='english', min_df = 0.01)
X = vectorizer.fit_transform(train_set["clean_desc"])
#Nous avons appris sur les donnees d'entrainement, nous allons appliquer les resultats retenus aux données et les stockés dans une variable
Y = vectorizer.transform(test_set["clean_desc"])

"""### PRINCIPAL COMPONENT ANALYSIS: Réduction de dimensionalité"""

#Telechargement de la librairie et application de la fonction PCA pour 400 composantes principales
from sklearn.decomposition import PCA
pca = PCA(400)
pca.fit(X.toarray())
pca.explained_variance_ratio_.cumsum()

"""Nous avons decidé de retirer seulement les dimentions qui explique environ 60% de la variance expliqué, d'ou les 400 composantes.

Ci-dessous le graphique representant les dimensions et le cumul de la variance expliquée par ces derniers.
"""

plt.figure(figsize = (10,8))
plt.plot(range(1,401), pca.explained_variance_ratio_.cumsum(), marker = 'o', linestyle = '--')
plt.title('Explained variance by components')
plt.xlabel('number of components')
plt.ylabel('cumulative explained variance')

"""### KMEANS POUR CLUSTERING SUR LES DIMENSIONS RETENUES:
Nous allons par la suite regrouper les dimensions dans des classes afin de mieux les apprehender. Ci-dessous la methode du coude permettant de choisir le nombre de classe adequat pour le regroupement. Il correspond a l'endroit sur le graphique ou nous observons un courde.
"""

X_pca = pca.fit_transform(X.toarray())
Y_pca = pca.transform(Y.toarray())

df_train = pd.DataFrame(pca.components_, columns=vectorizer.get_feature_names()).head(3).T
df_train.columns = ('PC1', 'PC2', 'PC3')
df_train_pc1 = df_train[df_train['PC1']>=df_train.PC1.mean()]['PC1']
df_train_pc2 = df_train[df_train['PC2']>=df_train.PC2.mean()]['PC2']
df_train_pc3 = df_train[df_train['PC3']>=df_train.PC3.mean()]['PC3']

df_train_pc3.sort_values(ascending=False).head(10).plot(kind='barh')
plt.title('Features de la troisième composante principale')
plt.xlabel('Coefficient dans la construction de la dimension')
plt.ylabel('Features')
plt.show()

#Elbow Method (la methode du coude):permettant de choisir la valeur de k 

score = []

#Pour presenter le graphique correspondant à la methode du coude
for cluster in range(2,9):
    kmeans = KMeans(n_clusters = cluster, init="k-means++", random_state=10)
    kmeans.fit(X_pca)
    score.append(kmeans.inertia_)
plt.figure(figsize = (10,8))
plt.plot(range(2,9), score)
plt.title('The Elbow Method')
plt.xlabel('no of clusters')
plt.ylabel('wcss')
plt.show()

#Application de l'algorithme de clustering sur la valeur de k choisi
true_k = 6
model_comp = KMeans(n_clusters=true_k, init='k-means++', random_state=10)
model_comp.fit(X_pca)

#Nous avons appris sur les donnees d'entrainement, nous allons appliquer les resultats retenus aux données et les stockés dans une variable
predict_X  = model_comp.predict(X_pca)
train_set['desc_clus'] = pd.Series(predict_X, index=train_set.index)

predict_Y  = model_comp.predict(Y_pca)
test_set['desc_clus'] = pd.Series(predict_Y, index=test_set.index)

#Representation graphique de la variable phd
train_set['desc_clus'].value_counts(normalize = True).plot(kind = 'bar')

train_set.pivot_table(index='desc_clus',values='SalaryNormalized', aggfunc=np.mean).sort_values(by=['SalaryNormalized'], ascending=False).plot(kind='bar')
plt.title('Salaire en fonction des clusters de description')
plt.xlabel('Clusters')
plt.ylabel('Salaire moyen')
plt.show()

#Cette fonction permet de stocker dans une liste un ensemble de dataframe correspondant chacun a un cluster ainsi que ses top 15 mots.
dfs = get_top_features_cluster(X.toarray(), predict_X, 10)

# Exemple de Répresentation du cluster 0
dfs[5].plot.barh(x='features', y='score')
plt.title('Cluster 5 :Graphs(top 10 words) ordered by relative importance as measured by TF-IDF')
plt.xlabel('Features')
plt.ylabel('Score')

"""### Preparing to modelling

#### Concatenating
"""

# Les colonnes à encoder avant modelisation
train_columns = ['ContractType', 'ContractTime', 'Category', 'Title_cluster','company_clus', 'desc_clus']

#Suppression des colonnes non utiles ou deja transformés
train = train_set.drop(['Id', 'Title', 'FullDescription', 'Company', 'clean_desc', 'Company_clean', 'SalaryNormalized','licence', 'experience', 'benefit', 'degree', 'expert', 'skill', 'knowledge', 'education', 'master', 'phd', 'bachelor', 'fixed-term', 'temporary', 'independent', 'hour'], axis=1)
test = test_set.drop(['Id', 'Title', 'FullDescription', 'Company', 'clean_desc', 'Company_clean', 'SalaryNormalized','licence', 'experience', 'benefit', 'degree', 'expert', 'skill', 'knowledge', 'education', 'master', 'phd', 'bachelor', 'fixed-term', 'temporary', 'independent', 'hour'], axis=1)

#Separation des donnees en donnees de variables explicatives (X) et de variables expliquées (y) 
X_train = train.drop(['SalaryNormalized_transform'], axis=1)
X_test = test.drop(['SalaryNormalized_transform'],axis=1)
y_train = train["SalaryNormalized_transform"]
y_test = test["SalaryNormalized_transform"]

#Dichotomisation des données
X_train_dum = pd.get_dummies(X_train, columns = train_columns)

X_test_dum = pd.get_dummies(X_test, columns = train_columns)

print("shape of X_train_dum :",X_train_dum.shape, "\n",
      "shape of X_test_dum :", X_test_dum.shape, "\n",
      "shape of y_train :", y_train.shape, "\n",
      "shape of y_test :", y_test.shape)

"""### Model Evaluation

There are three primary metrics used to evaluate linear models. These are: Mean absolute error (MAE), Mean squared error (MSE), or Root mean squared error (RMSE).

MAE: The easiest to understand. Represents average error

MSE: Similar to MAE but noise is exaggerated and larger errors are “punished”. It is harder to interpret than MAE as it’s not in base units, however, it is generally more popular.

RMSE: Most popular metric, similar to MSE, however, the result is square rooted to make it more interpretable as it’s in base units. It is recommended that RMSE be used as the primary metric to interpret your model.

Below, you can see how to calculate each metric. All of them require two lists as parameters, with one being your predicted values and the other being the true values

### Regression linéaire
"""

from sklearn.linear_model import LinearRegression
from sklearn.feature_selection import SelectKBest, f_regression
from sklearn import metrics

#model1 = SelectKBest(score_func=f_regression, k = 100)

#X_reg_new= model1.fit_transform(X_train_dum, y_train)
# Application des transf sur le jeu de données de test
#X_reg_test = model1.transform(X_test_dum)

model_reg = LinearRegression()

model_reg.fit(X_train_dum, y_train)

r_sq = model_reg.score(X_test_dum, y_test)
print('coefficient of determination:', r_sq, "\n")

y_pred = model_reg.predict(X_test_dum)

#print result of MAE
print("result of MAE sans transformation",metrics.mean_absolute_error(y_test, y_pred))

#print result of MAE
print("result of MAE",metrics.mean_absolute_error(np.exp(y_test), np.exp(y_pred)))

#print result of MSE
print("result of MSE",metrics.mean_squared_error(y_test, y_pred))

#print result of RMSE
print("result of RMSE", np.sqrt(metrics.mean_squared_error(y_test,y_pred)))

"""#### Regression LASSO"""

from sklearn.linear_model import LassoCV, RidgeCV

# define model
model_lasso = LassoCV()

# fit model
model_lasso.fit(X_train_dum, y_train)

y_pred = model_lasso.predict(X_test_dum)
#print result of MAE
print("result of MAE sans transformation",metrics.mean_absolute_error(y_test, y_pred))

#print result of MAE
print("result of MAE",metrics.mean_absolute_error(np.exp(y_test), np.exp(y_pred)))

#print result of MSE
print("result of MSE",metrics.mean_squared_error(y_test, y_pred))

#print result of RMSE
print("result of RMSE", np.sqrt(metrics.mean_squared_error(y_test,y_pred)))

"""### Ridge Regression"""

# define model
model_ridge = RidgeCV()

# fit model
model_ridge.fit(X_train_dum, y_train)

y_pred = model_ridge.predict(X_test_dum)
#print result of MAE
print("result of MAE sans transformation",metrics.mean_absolute_error(y_test, y_pred))

#print result of MAE
print("result of MAE",metrics.mean_absolute_error(np.exp(y_test), np.exp(y_pred)))

#print result of MSE
print("result of MSE",metrics.mean_squared_error(y_test, y_pred))

#print result of RMSE
print("result of RMSE", np.sqrt(metrics.mean_squared_error(y_test,y_pred)))

"""### Decision Tree"""

from sklearn.tree import DecisionTreeRegressor
#Create an object (model)
model_tree = DecisionTreeRegressor(criterion='mae')

#Fit (train) the model
model_tree.fit(X_train_dum, y_train)

y_pred = model_tree.predict(X_test_dum)

#print result of MAE
print("result of MAE sans transformation",metrics.mean_absolute_error(y_test, y_pred))

#print result of MAE
print("result of MAE",metrics.mean_absolute_error(np.exp(y_test), np.exp(y_pred)))

#print result of MSE
print("result of MSE",metrics.mean_squared_error(y_test, y_pred))

#print result of RMSE
print("result of RMSE", np.sqrt(metrics.mean_squared_error(y_test,y_pred)))

"""### Random Forest"""

#Import Library
from sklearn.ensemble import RandomForestRegressor
#Create an object (model)
model_random = RandomForestRegressor(n_estimators = 10, criterion='mae')

#Fit (train) the model
model_random.fit(X_train_dum, y_train)

y_pred = model_random.predict(X_test_dum)

from sklearn import metrics
#print result of MAE
print("result of MAE sans transformation",metrics.mean_absolute_error(y_test, y_pred))

#print result of MAE
print("result of MAE",metrics.mean_absolute_error(np.exp(y_test), np.exp(y_pred)))

#print result of MSE
print("result of MSE",metrics.mean_squared_error(y_test, y_pred))

#print result of RMSE
print("result of RMSE", np.sqrt(metrics.mean_squared_error(y_test,y_pred)))

"""### Plot Graphic to see feature importance"""

plt.rcParams.update({'figure.figsize': (12.0, 8.0)})
plt.rcParams.update({'font.size': 14})
sorted_idx = model_random.feature_importances_.argsort()[43:54]
plt.barh(X_train_dum.columns[sorted_idx], model_random.feature_importances_[sorted_idx])
plt.xlabel("Score")
plt.title("Niveau d'importance des caracteristiques dans le modèle")
plt.ylabel('Features')
plt.show()

"""### TEST data """

#Affichage des variables dont il existe des valeurs manquantes 
#Telechargement du jeu de donnee
test_job = pd.read_csv("/content/gdrive/MyDrive/ProjetBigData/test.csv", encoding="utf-8")
#trainjob['LocationNormalized']=trainjob['LocationNormalized'].astype('string')
test_job['LocationRaw']=test_job['LocationRaw'].astype('string')
test_job['Location_Raw'] = test_job['LocationRaw'].str.split(',')

test_job.info(2)

#Liste des villes les plus cheres en UK
exp_cities = ['London', 'Cambridge','Oxford','Bournemouth','Bristol', 'Portsmouth', 
              'Edinburgh', 'Southampton']

#Création d'un top_location 0 si la ville de mon dataframe ne fait pas partie et 1 si elle fait partie
test_job['top_location'] = test_job['LocationNormalized'].map(lambda place: 1 if place in exp_cities else 0)
test_job = test_job[['Id','Title', 'FullDescription','top_location','ContractType', 'ContractTime','Company','Category']]

test_job.shape

test_job.isnull().sum()[test_job.isnull().sum()>0]

#imputation des valeurs manquantes par la valeur 'notSpecified'

test_job["ContractType"].fillna('notSpecified', inplace = True)
test_job["ContractTime"].fillna('notSpecified', inplace = True)
test_job["Company"].fillna('notSpecified', inplace = True)

#Verivfication du traitement des donnees manquantes

print("Initial data missing values")
print(test_job.isnull().sum())

#attribution du cluster au dataframe relativement a son index
Y = vectorizer.transform(test_job["Title"])

predict_Y  = model_title.fit_predict(Y)
test_job['Title_cluster'] = pd.Series(predict_Y, index=test_job.index)

test_job.shape

test_job['Company'] = test_job['Company'].astype("string")
test_job['Company'] = test_job['Company'].map(lambda x: x.lower())
test_job["Company_clean"] = test_job['Company'].map(stopword_company)

test_job.shape

#attribution du cluster au dataframe relativement a son index
Y = vectorizer.transform(test_job["Company_clean"])

predict_Y  = model_comp.fit_predict(Y)
test_job['company_clus'] = pd.Series(predict_Y, index=test_job.index)

test_job.shape

#Jeu de test
# Mettre la variable en minuscule
test_job['FullDescription'] = test_job['FullDescription'].map(lambda x: x.lower())
#Garder que les caractères alphabetiques
test_job['clean_desc'] = test_job['FullDescription'].map(remove_url)
test_job['clean_desc'] = test_job['clean_desc'].map(remove_punctuation)
test_job['clean_desc'] = test_job['clean_desc'].map(remove_num)
test_job['clean_desc'] = test_job['clean_desc'].map(remove_stopword)
test_job['clean_desc'] = test_job['clean_desc'].map(remove_extrablank)
test_job['clean_desc'] = test_job['clean_desc'].map(lemma_1)
test_job['clean_desc'] = test_job['clean_desc'].map(lemma_2)

Y = vectorizer.transform(test_job["clean_desc"])
Y_pca = pca.transform(Y.toarray())

predict_Y  = model_comp.predict(Y_pca)
test_set['desc_clus'] = pd.Series(predict_Y, index=test_job.index)

test = test_set.drop(['Id', 'Title', 'FullDescription', 'Company', 'clean_desc', 'Company_clean'], axis=1)
test.shape

test_job_columns = ['ContractType', 'ContractTime', 'Category', 'Title_cluster','company_clus', 'desc_clus']
X_test_dum = pd.get_dummies(test, columns = test_job_columns)

X_test_dum.shape

#Regresion Lineaire
y_pred = model_random.predict(X_test_dum)
test_job['SalaryNormalized'] = np.exp(y_pred)

submission = test_job[["Id", "SalaryNormalized"]]

submission.head(20)

"""# Export"""

train_set.to_csv("/content/gdrive/MyDrive/ProjetBigData/trainset1.csv", index=False)

"""# MERCI A TOUS ET A CHACUN POUR VOTRE DEVOUEMENT ET VOTRE TENACITE:) 4eme 
                                  ## Score de submission: 8308.85

"""