# Importations
import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import numpy as np
import time
import os
# Chargement des donneés
train = pd.read_csv("data/X_train.csv",usecols=['image_file_name','item_name','item_caption'])
test = pd.read_csv("data/X_test.csv",usecols=['image_file_name','item_name','item_caption'])
# Dictionnaire associé à google traduction
google={
# Traduction d'expressions
"text": { "link":"https://translate.google.fr/?hl=fr&sl=auto&tl=en&op=translate",# url de l'UI de traduction d'expressions
"source":"//textarea", # case de saisie du texte à traduire
"result":"//span[@jsname='W297wb']", # balise contenant le texte traduit
"limit":5000 # nombre maximum de caractères traduisables
},
# Traduction de documents
"doc": { "link":"https://translate.google.fr/?hl=fr&sl=auto&tl=en&op=docs", # url de l'UI de traduction de documents
"button":"//div[@class='ld4Jde']/button", # bouton "Traduire"
"file" : "//input[@id='i34']", # input menant au fichier à traduire
"result": "//tbody", # balise contenant le texte traduit
"download":"//div[@class='spinner-container notranslate'][@style='display: none;']", # pop-up "Traduction en cours..." masqué en fin de traduction
"limit":1e7 # taille maximale des fichiers traduisables (10 Mo)
}
}
# Ouverture de Selenium
chrome = webdriver.Chrome(executable_path="./chromedriver.exe.")
chrome.get(google["doc"]["link"]) # Accepter les cookies avant d'exécuter les cellules suivantes
def find_sep(s,i,sep=" "):
"""
Trouver l'indice du caractère sep entre 0 et i
(recherche effectuée à rebours i->0)
Args:
s: chaîne de caractères
i: indice de fin de recherche
sep: caractère à rechercher
Returns
indice de l'espace entre 0 et i
"""
if i<=len(s)-1:
ind = s[0:i+1].rfind(sep)
if ind!=-1:
return ind
return i
def JAP_to_ENG(s,driver,site=google,tempo=1500,max_try=3,sep=" ",mode="text",click=False):
"""
Traduction d'une chaîne de caractères japonaises en anglais
Args:
s: chaîne de caractères japonais à traduire
driver: navigateur commandée par sélénium
tempo: temps d'attente maximum
site: dictionnaire contenant les infos du site de traduction
max_try: nombre d'essais restant
sep: séparteur scindant une chaine de caractère trop longue
mode: choix du mode de traduction
click: défilement manuel des fichiers
Return:
chaîne de caractères traduite en anglais
"""
taille=len(s)
try:
# Traduction de documents (.xslx)
if mode=="doc":
driver.get(site["doc"]["link"])
file = driver.find_element_by_xpath(site["doc"]["file"])
file.send_keys(s)
button = driver.find_element_by_xpath(site["doc"]["button"])
button.click()
if click:
input("Lancer la récup de la traduction :")
else:
WebDriverWait(driver,tempo).until(EC.presence_of_element_located((By.XPATH, site["doc"]["download"])))
driver.implicitly_wait(5)
return driver.find_element_by_xpath(site["doc"]["result"]).text
# Traduction direct du texte (str)
elif mode=="text":
driver.get(site["text"]["link"])
saisie = driver.find_element_by_xpath(site["text"]["source"])
if taille<=site["text"]["limit"]:
saisie.send_keys(s)
else:
space = find_sep(s,site["text"]["limit"],sep)
saisie.send_keys(s[0:space])
WebDriverWait(driver,tempo).until(EC.presence_of_element_located((By.XPATH, site["text"]["result"])))
traduction = chrome.find_element_by_xpath(site["text"]["result"]).text
if taille>site["text"]["limit"]:
return traduction +sep+ JAP_to_ENG(s[space+1:],driver,tempo,site,max_try,sep)
return traduction
except:
if max_try>1:
return JAP_to_ENG(s,driver,tempo,site,max_try-1,sep,mode,click)
return s
def split_doc(f,limit,ext=".xlsx"):
"""
Séparation d'un ficier f en plusieurs fichiers
Args:
f: nom du fichier à scinder en deux
limit: taille maximale par fichier
ext: extension de f
Returns:
liste des noms des fichiers générés
"""
if ext==".xlsx":
data = pd.read_excel(f)
n = round(os.path.getsize(f)/(0.95*limit))
name = f.replace(ext,"")
taille = len(data)
idx = [i for i in range(0,taille,round(taille/n))]+[taille]
files = []
for i in range(n):
files.append("{}{}{}".format(name,i+1,ext))
data.iloc[idx[i]:idx[i+1]].to_excel("{}{}{}".format(name,i+1,ext),index=False)
os.remove(f)
return files
return "Extension saisie non valide"
def translate_var(df,var,driver,Set=None,site=google,path="C:\\Users\\lcpla\\Documents\\Collège de France\\",click=False,to_save=False):
"""
Traduction d'une colonne d'un dataframe
Args:
df: dataframe contenant les textes à traduire
var: nom de la variable de df à traduire
driver: navigateur commandée par sélénium
Set: nom du dataframe
site: dictionnaire contenant les infos associés au site de traduction
path: chemin menant au dossier stockant les fichiers à traduire
click: défilement manuel des fichiers
to_save: sauvegarde des traductions
Return:
variable traduite
"""
if type(df)==type(pd.DataFrame()):
f="data/traduction/{}.xlsx".format(var)
data = pd.DataFrame({"index":["@" for i in range(len(df))],var:df[var]})
data.to_excel(f,index=False)
elif type(df)==str:
f=df
# Lancement de la traduction
if os.path.getsize(f)<=site["doc"]["limit"]:
driver.get(site["doc"]["link"])
traduction = JAP_to_ENG(path+f.replace("/","\\"),driver,mode="doc",click=click)
traduction = traduction.replace('index '+var,"").strip().split("\n")
traduction = pd.Series(traduction,name=var).str.strip("@").str.strip().replace({"":np.nan})
os.remove(f)
else:
files = split_doc(f,site["doc"]["limit"])
traduction = [translate_var(x,var,driver,site,path=path,to_save=False,click=click).to_list() for x in files]
traduction = pd.Series(pd.Series(traduction).sum(),name=var)
# Enregistrement des traductions
if to_save:
if Set+"_trad.csv" in os.listdir("data/traduction"):
trad = pd.read_csv("data/traduction/{}_trad.csv".format(Set))
trad[var] = traduction
trad.to_csv("data/traduction/{}_trad.csv".format(Set),index=False)
else:
traduction.to_csv("data/traduction/{}_trad.csv".format(Set),index=False)
return traduction
start=time.time()
t=translate_var(train,"item_name",chrome,"train",to_save=False)
print(time.strftime('Temps d\'exécution: %Hh %Mmin %Ss', time.gmtime(time.time()-start)))
print("Nb NaN: ",t.isna().sum())
t
Temps d'exécution: 00h 27min 12s Nb NaN: 0
0 Sankyo Aluminum M. Shade 2 Beam-standing type ... 1 [40% OFF SALE / Sale] 30s-40s Fashion Coordina... 2 Geta paulownia Made in Japan Women's TONE Nose... 3 \ Limited time [1000 yen OFF] Coupon issuance ... 4 Post Mailbox Mailbox Post for multi-family hou... ... 212115 Cactus Fashionable group planting Animal Cactu... 212116 [Cash on delivery not possible] [Andmore] Bi-f... 212117 Love Sam Cotton Flared Skirt XS Off Beige 212118 Wall storage Living thin [Free shipping] "Seis... 212119 Women's jacket ANTIBALLISTIC CYG2354 EE3 J27 Name: item_name, Length: 212120, dtype: object
start=time.time()
t=translate_var(train,"item_caption",chrome,"train",to_save=False)
print(time.strftime('Temps d\'exécution: %Hh %Mmin %Ss', time.gmtime(time.time()-start)))
print("Nb NaN: ",t.isna().sum())
t
Temps d'exécution: 00h 24min 17s Nb NaN: 23974
0 Item No. 19235601 Manufacturer Sankyo Aluminum... 1 Increased presence with a thick sash belt Uses... 2 Item Paulownia clogs * Yukata, half-width obi ... 3 ■ Product Description Louver shoe box 60 width... 4 Posts for apartments Variable push locks Colle... ... 212115 NaN 212116 [Caution] * Cash on delivery is not accepted a... 212117 Product name Love Sam Cotton flared skirt Colo... 212118 [Cash on delivery is not possible] This item i... 212119 [ANTIBAL LISTIC] Lady's jacket. Introducing a ... Name: item_caption, Length: 212120, dtype: object
start=time.time()
t=translate_var(test,"item_name",chrome,"test",to_save=False)
print(time.strftime('Temps d\'exécution: %Hh %Mmin %Ss', time.gmtime(time.time()-start)))
print("Nb NaN: ",t.isna().sum())
t
Temps d'exécution: 00h 01min 58s Nb NaN: 0
0 KYV39 miraie f Miraie Forte kyv39 au AU Smartp... 1 SO-04K Xperia XZ2 Premium Xperia XZ2 Premium d... 2 MO-01K MONO Mono mo01k docomo DoCoMo notebook ... 3 Xperia XZ Notebook Type Case Beach Hawaii Expe... 4 [Used] COMME CA DU MODE Skirt Bomb Toss Long L... ... 37342 Acrylic EX board White opaque Thickness 2mm 90... 37343 1-piece genuine leather men's shoes 25.5cm win... 37344 Glitter ribbon open toe pumps wedding shoes dr... 37345 [Used] French Army WAREIN 80's Inner Coat Line... 37346 nano UNIVERSE (Men's) Nano Universe Shorts Men... Length: 37347, dtype: object
start=time.time()
t=translate_var(test,"item_caption",chrome,"test",to_save=False)
print(time.strftime('Temps d\'exécution: %Hh %Mmin %Ss', time.gmtime(time.time()-start)))
print("Nb NaN: ",t.isna().sum())
t
Temps d'exécution: 00h 04min 18s Nb NaN: 4254
0 Precautions Depending on the arrival time of t... 1 Precautions Depending on the arrival time of t... 2 Product features-Seamless full-scale design (c... 3 Compatible model Xperia XZ (Xperia) Sony compa... 4 [Used] COMME CA DU MODE Skirt Bomb Toss Long L... ... 37342 Product Description Material Acrylic resin (co... 37343 Brand & nbsp; ARAGIN Aladdin & nbsp; Product d... 37344 Simple and elegant, it creates a higher-grade ... 37345 [Used] French Army WAREIN 80's Inner Coat Line... 37346 NaN Name: item_caption, Length: 37347, dtype: object
start=time.time()
train_trad = pd.read_csv("data/traduction/train_trad.csv")
test_trad = pd.read_csv("data/traduction/test_trad.csv")
colors = pd.read_csv("data/y_train.csv")
# Suppression des majuscules
train_trad["color_tags"] = colors.color_tags
train_trad = train_trad.fillna('').apply(lambda x: x.str.lower())
test_trad = test_trad.fillna('').apply(lambda x: x.str.lower())
# Récupération des color tags
train_trad.color_tags = train_trad.color_tags.str.strip("[]'").str.split("', '")
colors = list(pd.Series(train_trad.color_tags.sum()).unique())
print("Color_tags possibles: ",colors)
train_trad.color_tags = train_trad.color_tags.apply(lambda x: set(x))
# Concaténations des traductions
train_trad["item_description"] = train_trad.item_name+" "+train_trad.item_caption
test_trad["item_description"] = test_trad.item_name+" "+test_trad.item_caption
# Suppression des caractères non alphabétiques dans les concaténations
train_trad.item_description = train_trad.item_description.apply(lambda x: ''.join(filter(lambda c: str.isalpha(c)|str.isspace(c), x)))
test_trad.item_description = test_trad.item_description.apply(lambda x: ''.join(filter(lambda c: str.isalpha(c)|str.isspace(c), x)))
# Création de sets de mots
train_trad.item_description = train_trad.item_description.str.split(" ").apply(lambda x: set([elt for elt in x if elt.isalpha()]))
test_trad.item_description = test_trad.item_description.str.split(" ").apply(lambda x: set([elt for elt in x if elt.isalpha()]))
print(time.strftime('Temps d\'exécution: %Hh %Mmin %Ss', time.gmtime(time.time()-start)))
train_trad.head()
Color_tags possibles: ['silver', 'grey', 'black', 'brown', 'white', 'beige', 'multiple colors', 'gold', 'yellow', 'orange', 'pink', 'red', 'purple', 'green', 'blue', 'navy', 'khaki', 'burgundy', 'transparent'] Temps d'exécution: 00h 21min 30s
item_name | item_caption | color_tags | item_description | |
---|---|---|---|---|
0 | sankyo aluminum m. shade 2 beam-standing type ... | item no. 19235601 manufacturer sankyo aluminum... | {grey, black, silver} | {item, beamstanding, snowfall, carport, do, wi... |
1 | [40% off sale / sale] 30s-40s fashion coordina... | increased presence with a thick sash belt uses... | {black, brown} | {color, horse, belt, ss, origin, such, size, f... |
2 | geta paulownia made in japan women's tone nose... | item paulownia clogs * yukata, half-width obi ... | {white, black} | {item, photo, texture, or, freight, color, pat... |
3 | \ limited time [1000 yen off] coupon issuance ... | ■ product description louver shoe box 60 width... | {black, brown, beige} | {or, color, outer, you, sizes, origin, availab... |
4 | post mailbox mailbox post for multi-family hou... | post for apartments variable push locks collec... | {silver} | {item, eg, color, kg, you, contents, apartment... |
colors_set = pd.Series([set(colors)]*len(train))
df=pd.DataFrame({"Set":["Train","Test"],
"Présence de tags (%)":[100*(train_trad.item_description&colors_set).sum()/len(train),
100*(test_trad.item_description&colors_set).sum()/len(test)],
"Presence des 'bon' tags (%)": [100*(train_trad.color_tags & train_trad.item_description).sum()/len(train),np.NaN],
"Présence de tous les 'bon' tags (%)":[100*((train_trad.color_tags - train_trad.item_description).apply(len)==0).sum()/len(train),np.nan]})
df
Set | Présence de tags (%) | Presence des 'bon' tags (%) | Présence de tous les 'bon' tags (%) | |
---|---|---|---|---|
0 | Train | 64.714784 | 56.661795 | 43.436734 |
1 | Test | 64.548692 | NaN | NaN |
Données d'apprentissage:
Près de 65% des articles ont au moins un tags de couleurs dans leur descirption ou leur nom
Près de 57% des articles ont au moins un tag appartenant réellement à leur liste color_tags dans leur descirption ou leur nom
Près de 43% des articles ont la totalité de leur liste color_tags dans leur descirption ou leur nom
Données de test:
Près de 65% des articles ont au moins un tags de couleurs dans leur descirption ou leur nom
La description ou le nom de d'un article peuvent contenir des tags n'appartenant pas à ses color_tags ou ne contenir qu'une partie.