Pertanyaan sklearn.LabelEncoder dengan tidak pernah terlihat sebelumnya nilai-nilai


Jika sebuah sklearn.LabelEncoder telah dipasang di satu set pelatihan, itu mungkin akan rusak jika menemukan nilai-nilai baru ketika digunakan pada satu set tes.

Satu-satunya solusi yang dapat saya peroleh untuk ini adalah memetakan semua yang baru dalam rangkaian pengujian (yaitu tidak termasuk kelas yang ada) untuk "<unknown>", dan kemudian secara eksplisit menambahkan kelas yang sesuai ke LabelEncoder kemudian:

# train and test are pandas.DataFrame's and c is whatever column
le = LabelEncoder()
le.fit(train[c])
test[c] = test[c].map(lambda s: '<unknown>' if s not in le.classes_ else s)
le.classes_ = np.append(le.classes_, '<unknown>')
train[c] = le.transform(train[c])
test[c] = le.transform(test[c])

Ini berfungsi, tetapi apakah ada solusi yang lebih baik?

Memperbarui

Seperti yang ditunjukkan @sapo_cosmico dalam komentar, tampaknya hal di atas tidak berfungsi lagi, mengingat apa yang saya anggap sebagai perubahan implementasi dalam LabelEncoder.transform, yang sekarang tampaknya digunakan np.searchsorted (Saya tidak tahu apakah itu kasusnya sebelumnya). Jadi, bukannya menambahkan <unknown> kelas ke LabelEncoderdaftar kelas yang sudah diekstraksi, perlu disisipkan dalam urutan terurut:

import bisect
le_classes = le.classes_.tolist()
bisect.insort_left(le_classes, '<unknown>')
le.classes_ = le_classes

Namun, karena ini terasa sangat kikuk, saya yakin ada pendekatan yang lebih baik untuk ini.


32
2018-01-11 01:54


asal


Jawaban:


Saya akhirnya beralih ke Pandas ' get_dummies karena masalah ini data yang tidak terlihat.

  • buat dummies pada data pelatihan
    dummy_train = pd.get_dummies(train)
  • buat dummies di data yang baru (tidak terlihat)
    dummy_new = pd.get_dummies(new_data)
  • mengindeks ulang data baru ke kolom data pelatihan, mengisi nilai yang hilang dengan 0
    dummy_new.reindex(columns = dummy_train.columns, fill_value=0)

Secara efektif setiap fitur baru yang bersifat kategoris tidak akan masuk ke dalam classifier, tetapi saya pikir itu seharusnya tidak menimbulkan masalah karena tidak akan tahu apa yang harus dilakukan dengan mereka.


21
2017-11-17 15:53



Saya mendapat kesan bahwa apa yang Anda lakukan sangat mirip dengan apa yang dilakukan orang lain ketika menghadapi situasi ini.

Sudah ada upaya untuk menambahkan kemampuan untuk menyandikan label yang tidak terlihat ke LabelEncoder (lihat khususnya https://github.com/scikit-learn/scikit-learn/pull/3483 dan https://github.com/scikit-learn/scikit-learn/pull/3599), tetapi mengubah perilaku yang ada sebenarnya lebih sulit daripada yang terlihat pada pandangan pertama.

Untuk saat ini sepertinya menangani label "out-of-vocabulary" diserahkan kepada pengguna individu scikit-learn.


5
2018-06-17 06:47



Saya tahu dua pengembang yang bekerja untuk membangun pembungkus di sekitar trafo dan saluran pipa Sklearn. Mereka memiliki 2 transformator encoder yang kuat (satu dummy dan satu label encoders) yang dapat menangani nilai-nilai yang tak terlihat. Di sini adalah dokumentasi ke perpustakaan skutil mereka. Pencarian untuk skutil.preprocessing.OneHotCategoricalEncoder atau skutil.preprocessing.SafeLabelEncoder. Di dalam mereka SafeLabelEncoder(), nilai-nilai tak terlihat dikodekan secara otomatis ke 999999.


1
2017-10-22 17:19



Saya mencoba untuk mengatasi masalah ini dan menemukan dua cara praktis untuk menyandikan data kategori dari train dan set tes dengan dan tanpa menggunakan LabelEncoder. Kategori baru diisi dengan beberapa cetegory "c" (seperti "other" atau "missing"). Metode pertama tampaknya bekerja lebih cepat. Semoga itu akan membantu Anda.

import pandas as pd
import time
df=pd.DataFrame()

df["a"]=['a','b', 'c', 'd']
df["b"]=['a','b', 'e', 'd']


#LabelEncoder + map
t=time.clock()
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
suf="_le"
col="a"
df[col+suf] = le.fit_transform(df[col])
dic = dict(zip(le.classes_, le.transform(le.classes_)))
col='b'
df[col+suf]=df[col].map(dic).fillna(dic["c"]).astype(int)
print(time.clock()-t)

#---
#pandas category

t=time.clock()
df["d"] = df["a"].astype('category').cat.codes
dic =df["a"].astype('category').cat.categories.tolist()
df['f']=df['b'].astype('category',categories=dic).fillna("c").cat.codes
df.dtypes
print(time.clock()-t)

1
2018-01-09 13:27



Jika hanya tentang melatih dan menguji model, mengapa tidak hanya memberi label pada seluruh dataset. Dan kemudian gunakan kelas yang dihasilkan dari objek encoder.

encoder = LabelEncoder()
encoder.fit_transform(df["label"])
train_y = encoder.transform(train_y)
test_y = encoder.transform(test_y)

0
2017-07-13 09:26



Saya baru-baru ini mengalami masalah ini dan dapat muncul dengan solusi yang cukup cepat untuk masalah ini. Jawaban saya memecahkan sedikit lebih dari sekedar masalah ini tetapi itu akan dengan mudah bekerja untuk masalah Anda juga. (Saya pikir itu cukup keren)

Saya bekerja dengan pandas data frame dan awalnya menggunakan labelencoder sklearns () untuk menyandikan data saya yang kemudian saya acar untuk digunakan dalam modul lain dalam program saya.

Namun, label encoder dalam preprocessing sklearn tidak memiliki kemampuan untuk menambahkan nilai baru ke algoritma encoding. Saya memecahkan masalah pengkodean beberapa nilai dan menyimpan nilai-nilai pemetaan SEBAGAI BAIK seperti mampu menambahkan nilai-nilai baru ke encoder oleh (inilah garis besar kasar dari apa yang saya lakukan):

encoding_dict = dict()
for col in cols_to_encode:
    #get unique values in the column to encode
    values = df[col].value_counts().index.tolist()

    # create a dictionary of values and corresponding number {value, number}
    dict_values = {value: count for value, count in zip(values, range(1,len(values)+1))}

    # save the values to encode in the dictionary
    encoding_dict[col] = dict_values

    # replace the values with the corresponding number from the dictionary
    df[col] = df[col].map(lambda x: dict_values.get(x))

Kemudian Anda cukup menyimpan kamus ke file JSON dan dapat menariknya dan menambahkan nilai apa pun yang Anda inginkan dengan menambahkan nilai baru dan nilai integer yang sesuai.

Saya akan menjelaskan beberapa alasan di balik menggunakan peta () bukannya mengganti (). Saya menemukan bahwa menggunakan panda menggantikan () fungsi mengambil alih satu menit untuk mengulang melalui sekitar 117.000 baris kode. Menggunakan peta membawa waktu itu hingga lebih dari 100 mdtk.

TLDR: alih-alih menggunakan sklearns preprocessing hanya bekerja dengan dataframe Anda dengan membuat kamus pemetaan dan petakan nilai-nilai itu sendiri.


0
2017-08-07 20:48