<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 2A.ml - 2017 - Préparation des données
Ce notebook explique comment les données de la compétation 2017 ont été préparées. On récupére d'abord les données depuis le site OpenFoodFacts.
Step1:  A quoi ça ressemble
Step2:  C'est gros.
Step3:  Idée de la compétation
On veut savoir les additifs ajoutés apparaissent plus fréquemment avec certains produits ou certains compositions. ON cherche donc à prédire la présence d'additifs en fonction de toutes les autres variables. Si un modèle de prédiction fait mieux que le hasard, cela signifie que certaines corrélations existent. J'ai utilisé dask mais si vous de la mémoire, on peut faire avec pandas.
Step4:  Le code qui suit est construit après plusieurs essais en fonction des warnings retournés par le module dask.
Step5:  On ajoute la colonne à prédire, booleénne, qui indique la présence d'additif commençant par 'e
Step6:  On se limite au produit pour lesquels on a quelques informations sur le contenu.
Step7:  Bon la suite prend un peu de temps et ça n'est pas hyper efficace. Il faudrait un dask qui n'utilise pas dask mais uniquement les dataframes pour que ça aille plus vite. Café.
Step8:  Bon je crois que je vais vraiment développer une truc comme dask juste avec pandas.
Step9:  Split...
On impose les mêmes types pour chaque data frame.
Step10:  Ah j'allais oublié, il faut bidouiller la colonne additives pour retirer éviter un memory leak et on recalcule la colonne hasE pour être sûr.
Step11:  On recompose le tout.
Step12:  Il y aura probablement un ou deux data leak dans les autres colonnes..
On découpe le jeu d'évaluation.
Step13:  Premier modèle
Step14:  ROC
<ASSISTANT_TASK:>
Python Code:
from jyquickhelper import add_notebook_menu
add_notebook_menu()
Explanation: 2A.ml - 2017 - Préparation des données
Ce notebook explique comment les données de la compétation 2017 ont été préparées. On récupére d'abord les données depuis le site OpenFoodFacts.
End of explanation
import os
os.stat("c:/temp/fr.openfoodfacts.org.products.csv").st_size / 2**30, 'Go'
Explanation: A quoi ça ressemble
End of explanation
import pyensae
%load_ext pyensae
%head -n 2 c:/temp/fr.openfoodfacts.org.products.csv
import pandas
df = pandas.read_csv("c:/temp/fr.openfoodfacts.org.products.csv", 
                     sep="\t", encoding="utf-8", nrows=10000, low_memory=False)
df.head().T.to_excel("e.xlsx")
df[df.additives.notnull() & df.additives.str.contains("E4")].head().T
Explanation: C'est gros.
End of explanation
import dask
import dask.dataframe as dd
Explanation: Idée de la compétation
On veut savoir les additifs ajoutés apparaissent plus fréquemment avec certains produits ou certains compositions. ON cherche donc à prédire la présence d'additifs en fonction de toutes les autres variables. Si un modèle de prédiction fait mieux que le hasard, cela signifie que certaines corrélations existent. J'ai utilisé dask mais si vous de la mémoire, on peut faire avec pandas.
End of explanation
ddf = dd.read_csv("c:/temp/fr.openfoodfacts.org.products.csv", sep="\t", encoding="utf-8", low_memory=False,
                 dtype={'allergens': 'object',
       'cities_tags': 'object',
       'emb_codes': 'object',
       'emb_codes_tags': 'object',
       'first_packaging_code_geo': 'object',
       'generic_name': 'object',
       'ingredients_from_palm_oil_tags': 'object',
       'labels': 'object',
       'labels_fr': 'object',
       'labels_tags': 'object',
       'manufacturing_places': 'object',
       'manufacturing_places_tags': 'object',
       'origins': 'object',
       'origins_tags': 'object',
       'stores': 'object',
       'code': 'object','allergens_fr': 'object',
       'cities': 'object',
       'created_t': 'object',
       'last_modified_t': 'object'})
ddf.head()
print(type(ddf))
Explanation: Le code qui suit est construit après plusieurs essais en fonction des warnings retournés par le module dask.
End of explanation
ddfe = ddf.assign(hasE=ddf.apply(lambda row: isinstance(row.additives, str) and "en:e" in row.additives, 
                                 axis=1, meta=bool))
ddfe.head()
Explanation: On ajoute la colonne à prédire, booleénne, qui indique la présence d'additif commençant par 'e:' comme E440.
End of explanation
g100 = [_ for _ in ddf.columns if '100g' in _]
g100
ddfe.compute().shape
import numpy
ddfe100 = ddfe.assign(s100=ddf.apply(lambda row: sum(0 if numpy.isnan(row[g]) else 1 for g in g100), 
                                     axis=1, meta=float))
ddfe100 = ddfe100[ddfe100.s100 > 0]
ddfe100.head()
Explanation: On se limite au produit pour lesquels on a quelques informations sur le contenu.
End of explanation
ddfe100.to_csv("ddfe100*.csv", sep="\t", encoding="utf-8", index=False)
Explanation: Bon la suite prend un peu de temps et ça n'est pas hyper efficace. Il faudrait un dask qui n'utilise pas dask mais uniquement les dataframes pour que ça aille plus vite. Café.
End of explanation
dffefiles = [_ for _ in os.listdir(".") if "ddfe" in _]
dffefiles
Explanation: Bon je crois que je vais vraiment développer une truc comme dask juste avec pandas.
End of explanation
types = {k:v for k, v in zip(ddfe100.columns, ddfe100.dtypes)}
from sklearn.model_selection import train_test_split
for i, name in enumerate(dffefiles):
    print("name", name)
    df = pandas.read_csv(name, sep="\t", encoding="utf-8", dtype=types)
    df_train, df_test = train_test_split(df, test_size =0.5)
    df_test, df_eval = train_test_split(df_test, test_size =0.5)
    df_train.to_csv("off_train{0}.txt".format(i), sep="\t", index=False, encoding="utf-8")
    df_test.to_csv("off_test{0}.txt".format(i), sep="\t", index=False, encoding="utf-8")
    df_eval.to_csv("off_eval{0}.txt".format(i), sep="\t", index=False, encoding="utf-8")
Explanation: Split...
On impose les mêmes types pour chaque data frame.
End of explanation
df[["additives", "hasE"]].head()
import re
reg = re.compile("[[](.*?)[]]")
addi = re.compile("(en[:]e[0-9])")
def has_emachine(v):
    if isinstance(v, (list, pandas.core.series.Series)):
        rem = []
        add = []
        for _ in v:
            if isinstance(_, str):
                fd = reg.findall(_)
                for __ in fd:
                    if " en:e" in __ and addi.search(__):                      
                        add.append(__)#.split("->")[-1].strip())
                    elif " en:" not in __:
                        continue
                    else:
                        rem.append(__.split("->")[-1].strip())
            else:
                continue
        return add, list(sorted(set(rem)))
    elif isinstance(v, float) and numpy.isnan(v):
        return [], []
    elif isinstance(v, str):
        if "," in v:
            raise Exception('{0}\n{1}'.format(type(v), v))
        return has_emachine([v])
    else:
        # ???
        raise Exception('{0}\n{1}'.format(type(v), v))
                    
hasE, clean = has_emachine(df.loc[1,"additives"])
hasE, clean
Explanation: Ah j'allais oublié, il faut bidouiller la colonne additives pour retirer éviter un memory leak et on recalcule la colonne hasE pour être sûr.
End of explanation
off = [_ for _ in os.listdir(".") if "off" in _ and "all" not in _]
for cont in ['train', 'test', 'eval']:
    sub = [_ for _ in off if cont in _]
    dfs = []
    for name in sub:
        df = pandas.read_csv(name, sep="\t", encoding="utf-8", dtype=types)
        print("name", name, df.shape)
        df["hasE"] = df["additives"].apply(lambda x: len(has_emachine(x)[0]) > 0)
        df["additives"] = df["additives"].apply(lambda x: ";".join(has_emachine(x)[1]))
        dfs.append(df)
    df = pandas.concat(dfs, axis=0)
    print("merged", df.shape)
    df.to_csv("off_{0}_all.txt".format(cont), sep="\t", index=False, encoding="utf-8")
Explanation: On recompose le tout.
End of explanation
len(types)
df_eval = pandas.read_csv("off_eval_all.txt", sep="\t", dtype=types, encoding="utf-8")
df_eval_X = df_eval.drop("hasE", axis=1)
df_eval_X.to_csv("off_eval_all_X.txt")
df_eval[["hasE"]].to_csv("off_eval_all_Y.txt")
Explanation: Il y aura probablement un ou deux data leak dans les autres colonnes..
On découpe le jeu d'évaluation.
End of explanation
df_train = pandas.read_csv("off_train_all.txt", sep="\t", dtype=types, encoding="utf-8")
df_train.shape
X = df_train[g100].fillna(0)
Y = df_train['hasE']
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression()
clf.fit(X, Y)
pred = clf.predict(X)
from sklearn.metrics import confusion_matrix
confusion_matrix(Y, pred)
df_test = pandas.read_csv("off_test_all.txt", sep="\t", dtype=types, encoding="utf-8")
X_test = df_test[g100].fillna(0)
Y_test = df_test['hasE']
pred = clf.predict(X_test)
confusion_matrix(Y_test, pred)
Explanation: Premier modèle
End of explanation
y_proba = clf.predict_proba(X_test)
y_pred = clf.predict(X_test)
print(y_proba[:3])
print(y_pred[:3])
y_test = Y_test.values
type(y_pred), type(Y_test), type(y_test)
import numpy
prob_pred = numpy.array([(y_proba[i, 1] if c else y_proba[i, 0]) for i, c in enumerate(y_pred)])
prob_pred[:3]
from sklearn.metrics import roc_curve
fpr, tpr, th = roc_curve(y_pred == y_test, prob_pred)
%matplotlib inline
import matplotlib.pyplot as plt
plt.figure()
lw = 2
plt.plot(fpr, tpr, color='darkorange', lw=lw, label='Courbe ROC')
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel("Proportion mal classée")
plt.ylabel("Proportion bien classée")
plt.title('ROC')
plt.legend(loc="lower right")
Explanation: ROC
End of explanation
<END_TASK>