Prétraitement des catégories ou des dates

Comment convertir des catégories ou des dates en features ? That is the question.

TableReport

Le module skrub propose des outils assez pratiques pour prendre vite la mesure d’un jeu de données.

[2]:
from skrub import TableReport
from teachpyx.datasets import load_wines_dataset

df = load_wines_dataset()
TableReport(df)
Processing column  13 / 13
[2]:

Please enable javascript

The skrub table reports need javascript to display correctly. If you are displaying a report in a Jupyter notebook and you see this message, you may need to re-execute the cell or to trust the notebook (button on the top right or "File > Trust notebook").

Catégories

Les catégories sont assez simples à transformer en variable numériques. La plus populaire des transformations est celle ou une catégorie est diluée sur plusieurs colonnes, une par catégorie : OneHotEncoder.

[4]:
import pandas
from sklearn.preprocessing import OneHotEncoder

data = pandas.DataFrame([{"A": "cat1"}, {"A": "cat2"}, {"A": "cat3"}, {"A": "cat1"}])
ohe = OneHotEncoder()
ohe.fit(data)
ohe.transform(data)
[4]:
<Compressed Sparse Row sparse matrix of dtype 'float64'
        with 4 stored elements and shape (4, 3)>

Sparse avez-vous dit ?

[5]:
ohe.transform(data).todense()
[5]:
matrix([[1., 0., 0.],
        [0., 1., 0.],
        [0., 0., 1.],
        [1., 0., 0.]])

Cette approche fonctionne bien excepté que si il y a beaucoup de catégories ou beaucoup de colonnes catégorielles, le nombre de colonnes explose. Pour y remédier, on peut soit compresser le nombre de colonnes en prenant un hash, la représentation binaire, en éliminant les catégories sous représentées, en les regroupant, en la remplaçant par une valeur numérique TargetEncoder. On peut faire aussi une ACP… Il n’y a pas de bonne ou mauvaise solution dans le cas général. Il faut essayer.

Catégories mal orthographiées

Quand elles sont mal orthographiées, les catégories se multiplient. Dans ce cas, on peut soit chercher à corriger manuellement les erreurs soit faire avec, comme par exemple à SimilarityEncoder. Cet estimateur s’appuie sur la proximité des mots ou des caractères.

[9]:
import pandas
from skrub import SimilarityEncoder

data = pandas.DataFrame(
    [
        {"A": "data scientist"},
        {"A": "data scientiste"},
        {"A": "datascientist"},
        {"A": "alpiniste"},
    ]
)
sim = SimilarityEncoder()
sim.fit(data)
sim.transform(data)
[9]:
array([[0.04545455, 1.        , 0.8125    , 0.6875    ],
       [0.14285714, 0.8125    , 1.        , 0.55555556],
       [0.04761905, 0.6875    , 0.55555556, 1.        ],
       [1.        , 0.04545455, 0.14285714, 0.04761905]])

D’autres options.

[11]:
import pandas
from skrub import StringEncoder

data = pandas.DataFrame(
    [
        {"A": "data scientist"},
        {"A": "data scientiste"},
        {"A": "datascientist"},
        {"A": "alpiniste"},
    ]
)
sim = StringEncoder(2)
sim.fit(data.A)
sim.transform(data.A)
[11]:
A_0 A_1
0 0.943822 -0.123520
1 0.907826 0.113797
2 0.824866 -0.170536
3 0.157073 0.980073

Dates

Les dates sont toujours à prendre avec des pincettes. Si les données sont corrélées avec le temps, cela montre qu’il y a une tendance mais il y a toujours un risque que le modèle apprennent un comportement attaché à une époque précise, altérant ses performances dans le futur. Il faut donc distinguer ce qui est une tendance et ce qui est lié à la saisonnalité, le jour de la semaine, le mois de l’année. La saisonnalité est une information qui se répète. Aucune année passé ne revient donc l’année est une information qui ne devrait pas faire partie des bases d’apprentissage. L’objet DatetimeEncoder automatise cela mais le plus simple est sans doute d’utiliser le module datetime.

[14]:
import pandas
from skrub import DatetimeEncoder

login = pandas.to_datetime(
    pandas.Series(["2024-05-13T12:05:36", None, "2024-05-15T13:46:02"], name="login")
)
dt = DatetimeEncoder(add_weekday=True)
dt.fit(login)
dt.transform(login)
[14]:
login_year login_month login_day login_hour login_total_seconds login_weekday
0 2024.0 5.0 13.0 12.0 1.715602e+09 1.0
1 NaN NaN NaN NaN NaN NaN
2 2024.0 5.0 15.0 13.0 1.715781e+09 3.0

Notebook on github