Scikit-learn: Memikirkan kembali API CategoricalEncoder ?

Dibuat pada 23 Jan 2018  ·  63Komentar  ·  Sumber: scikit-learn/scikit-learn

Berdasarkan beberapa diskusi yang kami lakukan di sini dan masalah yang terbuka, kami memiliki beberapa keraguan bahwa CategoricalEncoder (https://github.com/scikit-learn/scikit-learn/pull/9151) adalah yang terbaik pilihan nama (dan karena belum dirilis, kami memiliki ruang untuk perubahan).

Jadi ringkasan bagaimana sekarang:

  • Nama kelas CategoricalEncoder menyatakan tipe data yang diterimanya (data kategorikal)
  • Argumen kata kunci encoding menentukan cara menyandikan data tersebut

Saat ini kami sudah memiliki encoding='onehot'|'onehot-dense'|'ordinal' .

Tetapi apa yang harus dilakukan dalam kasus berikut:

  • Kami ingin menambahkan lebih banyak opsi penyandian (misalnya penyandian biner, penyandian target rata-rata, penyandian unary, ...). Apakah kita terus menambahkannya sebagai nilai baru untuk encoding kwarg dalam satu kelas CategoricalEncoder ?
  • Kami ingin menambahkan opsi khusus untuk salah satu pengkodean (misalnya untuk pengkodean 'onehot' untuk menjatuhkan kolom pertama (berlebihan), atau untuk pengkodean 'ordinal' mendasarkan urutan kategori pada frekuensi, ...). Masalahnya di sini adalah bahwa kita kemudian perlu menambahkan argumen kata kunci tambahan ke CategoricalEncoder yang aktif atau tidak, tergantung pada apa yang Anda berikan untuk encoding kwarg, yang bukan merupakan desain API terbaik.

Untuk masalah terakhir itu, kami sudah memiliki ini dengan opsi sparse=True/False , yang hanya relevan untuk 'onehot' dan bukan untuk 'ordinal', dan yang kami selesaikan dengan memiliki 'onehot' dan 'onehot-dense' opsi penyandian dan bukan kata kunci sparse . Tetapi pendekatan seperti itu juga tidak berskala.

Terkait dengan ini, ada PR untuk menambahkan UnaryEncoder (https://github.com/scikit-learn/scikit-learn/pull/8652). Ada diskusi terkait tentang penamaan di PR itu, karena saat ini namanya mengatakan bagaimana pengkodeannya, bukan jenis data apa yang didapatnya (dalam desain saat ini, ia menerima bilangan bulat yang sudah dikodekan, bukan data kategoris aktual. Dalam hal itu, untuk konsisten dengan CategoricalEncoder, mungkin lebih baik diberi nama OrdinalEncoder karena membutuhkan data ordinal sebagai input).


Apa saja opsi ke depan:

1) Pertahankan hal-hal seperti yang kita miliki sekarang di master, dan baik-baik saja dengan menambahkan beberapa opsi baru ke kelas tunggal (pertanyaan penting yang sulit dijawab sekarang, adalah berapa banyak fitur baru yang ingin kita tambahkan di masa depan) .
2) Ganti skema penamaan dan miliki banyak 'encoder kategoris' di mana namanya mengatakan bagaimana pengkodeannya (OnehotEncoder, OrdinalEncoder, dan kemudian mungkin BinaryEncoder, UnaryEncoder, ...)

Jadi ini sedikit trade-off dari potensi peningkatan jumlah kelas vs jumlah argumen kata kunci dalam satu kelas.


Satu masalah dengan pendekatan kedua (dan salah satu alasan kami menggunakan CategoricalEncoder di tempat pertama, bahkan sebelum kami menambahkan beberapa opsi penyandian), adalah bahwa sudah ada OnehotEncoder , yang memiliki API yang berbeda dari CategoricalEncoder . Dan, sebenarnya tidak ada nama lain yang bagus yang bisa kita gunakan untuk encoder yang melakukan one-hot encoding.
Namun, saya pikir, dengan beberapa peretasan jelek sementara, kami dapat menggunakan kembali nama tersebut, jika kami setuju dengan penghentian atribut saat ini (dan saya pikir kami setuju bahwa itu bukan atribut yang paling berguna). Idenya adalah jika Anda menyesuaikan kelas dengan data string, Anda mendapatkan perilaku baru, dan jika Anda menyesuaikan kelas dengan data integer, Anda mendapatkan peringatan penghentian yang menunjukkan perilaku default akan berubah (dan menunjukkan kata kunci mana yang harus ditentukan untuk mendapatkan menghilangkan peringatan).

cc @jnothman @amueller @GaelVaroquaux @rth

Komentar yang paling membantu

Gagasan untuk mengembalikan CategoricalEncoder membuat saya cukup sedih, tapi saya pikir
Anda benar bahwa pengguna masa depan tidak akan terlalu bingung dengan opsi 2. Utama saya
kekhawatiran adalah bahwa kami telah mencoba menerapkan ini sebagai perubahan pada OHE untuk a
lama dan tidak pernah terbang. Mungkin akan lebih baik untuk mencoba
modifikasi pada docstring OneHotEncoder sesuai dengan yang diusulkan
berubah, jadi kita bisa melihat apakah itu terlihat waras.

Semua 63 komentar

Terima kasih atas ringkasannya @jorisvandenbossche. Saya pikir saya mendukung opsi 2: menggunakan kembali kelas OneHotEncoder , mencela atribut aneh dan menambahkan parameter konstruktor untuk memilih perilaku dengan peringatan di masa mendatang yang mengatakan bahwa perilaku default akan berubah tetapi membuatnya mudah untuk dibungkam peringatan itu hanya dengan memberikan nilai untuk opsi itu.

Gagasan untuk mengembalikan CategoricalEncoder membuat saya cukup sedih, tapi saya pikir
Anda benar bahwa pengguna masa depan tidak akan terlalu bingung dengan opsi 2. Utama saya
kekhawatiran adalah bahwa kami telah mencoba menerapkan ini sebagai perubahan pada OHE untuk a
lama dan tidak pernah terbang. Mungkin akan lebih baik untuk mencoba
modifikasi pada docstring OneHotEncoder sesuai dengan yang diusulkan
berubah, jadi kita bisa melihat apakah itu terlihat waras.

+1 untuk apa yang dikatakan Joel

Dikirim dari ponsel saya. Mohon dimaafkan typo dan kekurangannya.​

Pada 23 Januari 2018, 12:28, pukul 12:28, Joel Nothman [email protected] menulis:

Gagasan untuk mengembalikan CategoricalEncoder membuat saya cukup sedih, tapi saya
memikirkan
Anda benar bahwa pengguna masa depan tidak akan terlalu bingung dengan opsi 2. Saya
utama
kekhawatiran adalah bahwa kami telah mencoba menerapkan ini sebagai perubahan pada OHE untuk
A
lama dan tidak pernah terbang. Mungkin akan lebih baik untuk mencoba
modifikasi pada docstring OneHotEncoder sesuai dengan yang diusulkan
berubah, jadi kita bisa melihat apakah itu terlihat waras.

--
Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung atau lihat di GitHub:
https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment -359761818

Gagasan untuk mengembalikan CategoricalEncoder membuat saya cukup sedih

Untuk lebih jelasnya, itu tidak akan menjadi pengembalian, itu akan menjadi refactor / rename yang menjaga semua fungsionalitas!
Tapi saya juga suka nama "CategoricalEncoder", itu memang menyedihkan.

Yang mengatakan, saya akan segera mencoba melakukan perubahan untuk memiliki gagasan tentang bagaimana mungkin untuk mengintegrasikan ini di OnehotEncoder.

Oke, saya membuka PR dengan bukti konsep: https://github.com/scikit-learn/scikit-learn/pull/10523.
Itu belum selesai (tidak ada peringatan penghentian dan atribut baru belum dihitung dalam perilaku lama).

Pertanyaan API utama adalah tentang format data input.
Jadi sebagai rekap, ada dua cara berbeda saat kami memproses data kategorikal :

1) Sebagai data aktual, belum dikodekan (integer atau string), kategorikal (cara melakukannya di CategoricalEncoder ) -> simpulkan kategori dari nilai unik dalam data pelatihan
2) Sebagai integer, data yang sudah dikodekan (bagaimana hal itu dilakukan dalam OneHotEncoder ) -> simpulkan kategori dari nilai maksimum dalam data pelatihan

Pertanyaannya adalah: apakah kita menemukan kedua kasus tersebut layak untuk didukung? Jadi, dalam OneHotEncoder yang berpotensi digabungkan, apakah kami mempertahankan kemampuan untuk melakukan keduanya, atau apakah kami sepenuhnya menghentikan penggunaan dan kemudian menghapus kemampuan untuk memproses input ordinal?

Jika menginginkan kemampuan untuk memproses keduanya, kita dapat menambahkan kata kunci boolean untuk menentukan tipe data input (untuk saat ini saya menggunakan encoded_input=False/True , tetapi ide lain adalah ordinal_input , ...)

Untuk periode penghentian, kami harus mendukung keduanya, dan juga harus memperkenalkan kata kunci untuk memilih perilaku (untuk dapat membungkam peringatan dan memilih perilaku baru).
Jadi pada prinsipnya kita bisa menyimpan kata kunci setelahnya.

Mengingat bahwa kami ingin menangani keduanya, ikhtisar tentang cara kerja OneHotEncoder:

  • untuk saat ini encoded_input=None , dan kami menyimpulkan default berdasarkan data
  • jika data seperti int (ditangani sebelumnya oleh OneHotEncoder) encoded_input secara internal disetel ke True dan peringatan penghentian dimunculkan. Jika pengguna ingin mempertahankan perilaku saat ini, pengguna dapat menetapkannya secara manual sebagai OneHotEncoder(encoded_input=True) untuk membungkam peringatan.
  • jika inputnya tidak seperti int, kami menetapkan encoded_input internal ke False dan tanpa peringatan menggunakan perilaku baru (= perilaku CategoricalEncoder saat ini)
  • di masa depan kami mengubah default encoded_input dari None menjadi False (secara default perilaku baru, juga untuk data seperti int)

Saya masih tidak yakin apa yang Anda sarankan adalah perbedaan praktis karena menyimpulkan kategori dari nilai maks.

@jnothman Saya kira Anda mengakui bisa ada perbedaan dalam praktek? (output yang Anda dapatkan tergantung pada data yang Anda miliki)

Tetapi apakah perbedaan ini penting dalam praktik, saya tidak tahu. Di situlah saya ingin melihat umpan balik. Apakah ada orang yang benar-benar menginginkan metode berbasis "nilai maksimal" ini, atau apakah kami setuju (di masa depan, setelah penghentian) hanya memiliki metode berbasis "nilai unik".

Saya pikir saya pribadi tidak akan pernah membutuhkan metode berbasis nilai maksimal ini, tetapi OneHotEncoder telah seperti itu selama bertahun-tahun (untuk alasan yang bagus atau tidak?).

Sebenarnya menghentikan kategorisasi berdasarkan nilai maks tentu akan membuat implementasi (setelah penghentian) lebih sederhana.
Dan jika kita memilih untuk rute itu, saya setuju pilihannya seharusnya legacy_mode=True/False daripada encoded_input / ordinal_input

Ingatkan saya apa perbedaan sebenarnya dalam output, ketika n_values='auto',
silakan? Saya pikir hal active_features_ membuatnya pada dasarnya
identik, tapi aku mungkin melupakan sesuatu.

Aha, itu memperjelas kesalahpahaman kita :-)
Saya salah mengerti bagaimana OneHotEncoder saat ini benar-benar bekerja. Misalkan Anda memiliki satu fitur dengan nilai [2, 3, 5, 2]. Saya pikir OneHotEncoder saat ini akan memiliki kategori [0, 1, 2, 3, 4, 5] (sementara CategoricalEncoder saat ini akan memiliki kategori [2, 3, 5]). Tetapi Anda benar bahwa active_features_ juga hanya [2, 3, 5], pada dasarnya membuatnya sama dengan nilai default n_values='auto' .

Jadi hanya kasus di mana Anda meneruskan bilangan bulat ke n_values (seperti n_values=6 untuk kategori=[0, 1, 2, 3, 4, 5] dalam kasus di atas) untuk menentukan jumlah kategori yang sebenarnya akan menjadi perubahan API (usang/dihapus).
Dan itu akan dengan mudah diganti oleh pengguna dengan categories=range(6)

Maaf bila membingungkan.
Dalam hal itu, saya pikir kita bahkan tidak memerlukan opsi legacy_mode . Kami hanya dapat menerjemahkan n_values=6 ke categories=range(6) internal dan memberikan peringatan untuk itu (tetapi perlu memeriksa ini dengan tes yang sebenarnya).

Perbedaan lainnya adalah penanganan kategori gaib. Dengan perilaku OneHotEncoder saat ini, jika nilai yang tidak terlihat berada dalam rentang (0, maks), itu tidak akan menimbulkan kesalahan bahkan jika handle_unknow='error' (default). Tetapi juga itu dapat diselesaikan secara terpisah dengan dalam kasus seperti itu memunculkan peringatan bahwa pengguna harus mengatur handle_unknown='ignore' secara manual untuk menjaga perilaku yang ada.

Satu-satunya fitur yang akan kami lepaskan adalah perbedaan antara kategori tidak dikenal yang berada dalam rentang (0, maks) (oleh OneHotEncoder saat ini tidak dianggap sebagai 'tidak diketahui') dan kategori yang lebih besar dari itu (> maks, yang saat ini sudah dianggap seperti yang tidak diketahui oleh OneHotEncoder).

tidak, itu adalah hal yang telah kami coba sebelumnya dan itu juga
rewel. kecuali ada alasan bagus untuk mempertahankan perilaku saat ini, kami
seharusnya hanya memiliki legacy_mode untuk membawa kita ke masa depan secara perlahan.

tidak, itu adalah hal yang telah kami coba sebelumnya dan itu terlalu rewel.

Bisakah Anda menjelaskan aspek mana yang dimaksud dengan "tidak" ini?
Fakta bahwa saya pikir legacy_mode tidak diperlukan?

ya, dengan gagasan bahwa Anda bisa membuat sesuatu yang terbalik
kompatibel dan apa yang kita inginkan ke depan

ya, dengan gagasan bahwa Anda dapat membuat sesuatu yang kompatibel ke belakang dan apa yang kita inginkan untuk maju

Bukan itu yang saya coba sarankan. Saya ingin memperjelas bahwa berpikir adalah mungkin untuk tidak memiliki kata kunci legacy_mode , bukan dengan membuatnya secara ajaib kompatibel dan apa yang kita inginkan di masa depan, tetapi dengan mencela perilaku kata kunci yang ada.

Jadi untuk menjadi konkret: nilai non-default n_values dapat ditinggalkan dan harus diganti dengan spesifikasi categories . handle_unknow jika data bilangan bulat harus disetel secara eksplisit oleh pengguna untuk memilih pengabaian penuh atau kesalahan penuh alih-alih campuran saat ini (dan jika tidak, peringatan penghentian dimunculkan).

jadi jika saya melakukan .fit([[5]]).transform([[4]]), yang nilai n_values,
kategori dan handle_umknown apakah itu akan menimbulkan kesalahan?

Pada 25 Jan 2018 09:32, "Joris Van den Bossche" [email protected]
menulis:

ya, dengan gagasan bahwa Anda bisa membuat sesuatu yang terbalik
kompatibel dan apa yang kita inginkan ke depan

Bukan itu yang saya coba sarankan. Saya ingin memperjelas pemikiran itu
dimungkinkan untuk tidak memiliki kata kunci legacy_mode, bukan dengan memilikinya secara ajaib
baik compat mundur dan apa yang kita inginkan di masa depan, tetapi dengan mencela
perilaku kata kunci yang ada.

Jadi untuk lebih konkret: nilai n_values ​​non-default dapat ditinggalkan dan
harus diganti dengan spesifikasi kategori. handle_unknow jika terjadi
data integer harus diatur secara eksplisit oleh pengguna untuk memilih baik penuh
mengabaikan atau kesalahan penuh alih-alih campuran saat ini (dan sebaliknya penghentian
peringatan dinaikkan).


Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub
https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment-360296569 ,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/AAEz6-DrQWep22_gs-hg9cC0u19B1_PSks5tN6-HgaJpZM4RpUE8
.

bisakah kita membuatnya sehingga selama penghentian, kategori harus ditetapkan
secara eksplisit, dan mode lama dengan peringatan sebaliknya berlaku? Apakah itu
apa yang Anda sarankan?

bisakah kita membuatnya sehingga selama penghentian, kategori harus ditetapkan secara eksplisit, dan mode lama dengan peringatan berlaku sebaliknya? Apakah itu yang Anda sarankan?

Ya, mungkin masih ada kasus yang hilang, tapi saya pikir ini mungkin (akan diperiksa dengan pengkodean aktual minggu depan).

Kasus 'warisan' yang berbeda:

  • n_values='auto' (default)

    • handle_unknown='ignore' -> baik, tidak ada perubahan perilaku

    • handle_unknown='error' -> Masalah, nilai dalam rentang masih diabaikan, nilai di atas rentang kesalahan



      • Solusi yang mungkin:





        • cocok, jika rentangnya berurutan => baik, tidak ada perubahan perilaku (untuk semua orang yang sekarang menggabungkan LabelEncoder dengannya, yang menurut saya merupakan kasus penggunaan yang khas)



        • jika bukan ini masalahnya: naikkan peringatan penghentian bahwa mereka harus menetapkan kategori secara eksplisit untuk menjaga perilaku ini (dan secara internal menggunakan mode lama)






  • n_nilai=nilai

    • ini dapat diterjemahkan ke kategori=[rentang(nilai)] secara internal, dan meningkatkan peringatan penghentian bahwa pengguna harus melakukannya sendiri di masa mendatang

    • dalam hal ini handle_unknown='error' / 'ignore' berfungsi seperti yang diharapkan

Peringatan penghentian dalam kasus n_values='auto' hanya akan dinaikkan di fit dan bukan pada konstruksi (yang tidak terlalu ideal), tetapi hanya sesuai bahwa kita tahu bahwa pengguna melewatinya data numerik dan bukan data string.

kami biasanya tidak menaikkan peringatan sampai cocok dalam hal apa pun jadi jangan khawatir
itu.

strategi itu terdengar bagus.

Saya sebenarnya tidak yakin apakah kita harus mengendus string dalam data,
meskipun. Anda pada dasarnya menginginkannya: mode lama aktif jika kategorinya
tidak disetel dan jika datanya semua bilangan bulat?

Satu pertanyaan: jika parameter kategori dan n_values ​​adalah defaultnya, lakukan
kami menerbitkan kategori_? Jika n_values ​​disetel secara eksplisit, apakah kami menerbitkan
kategori_?

Pada 29 Jan 2018 10:00, "Joris Van den Bossche" [email protected]
menulis:

bisakah kita membuatnya sehingga selama penghentian, kategori harus ditetapkan
secara eksplisit, dan mode lama dengan peringatan sebaliknya berlaku? Apakah itu
apa yang Anda sarankan?

Ya, mungkin masih ada kasus yang hilang, tapi saya pikir ini mungkin (akan
periksa dengan pengkodean aktual minggu depan).

Kasus 'warisan' yang berbeda:

  • n_values='auto' (default)

    • handle_unknown='ignore' -> baik, tidak ada perubahan perilaku

    • handle_unknown='error' -> Masalah, nilai dalam rentang masih

      diabaikan, nilai di atas rentang kesalahan



      • Solusi yang mungkin:





        • cocok, jika rentangnya berurutan => baik, tidak ada perubahan



          perilaku (untuk semua orang yang sekarang menggabungkan LabelEncoder dengannya, yaitu



          kasus penggunaan khas saya pikir)



        • jika ini bukan masalahnya: naikkan peringatan penghentian bahwa



          mereka harus menetapkan kategori secara eksplisit untuk menjaga perilaku ini (dan



          menggunakan mode lama secara internal)





      • n_nilai=nilai



    • ini dapat diterjemahkan ke kategori=[rentang(nilai)] secara internal,

      dan meningkatkan peringatan penghentian bahwa pengguna harus melakukannya sendiri di

      masa depan

    • dalam hal ini handle_unknown='error' / 'ignore' berfungsi seperti yang diharapkan

Peringatan penghentian dalam kasus n_values='auto' hanya akan dinaikkan dalam
cocok dan tidak pada konstruksi (yang tidak benar-benar ideal), tetapi hanya
sesuai bahwa kita tahu bahwa pengguna meneruskannya data numerik dan bukan string
data.


Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub
https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment-361104495 ,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/AAEz6x8xnyZXBLij-DCC45JyYNf8pA5kks5tPPwXgaJpZM4RpUE8
.

Anda pada dasarnya menginginkannya: mode lama aktif jika kategori tidak disetel dan jika data semuanya bilangan bulat?

Ya memang (dalam prakteknya kurang lebih akan sama)

Satu pertanyaan: jika parameter kategori dan n_nilai adalah defaultnya, apakah kami menerbitkan kategori_? Jika n_values ​​disetel secara eksplisit, apakah kami memublikasikan kategori_?

Saya pribadi sudah sebisa mungkin menyediakan atribut antarmuka baru, bahkan dalam mode lawas. Jadi dalam kedua kasus saya akan menghitung categories_ (bahkan jika itu akan sedikit lebih berhasil)


Jadi saya mencoba memasukkan logika di atas dalam kode (akan mendorong beberapa pembaruan ke PR), dan saya punya satu pertanyaan lagi untuk kasus data integer ketika n_values atau categories tidak disetel ( kasus khas untuk 'legacy_mode'). Masalahnya terletak pada kenyataan bahwa jika kategori yang disimpulkan hanyalah rentang berurutan (0, 1, 2, 3, ... maks), tidak ada perbedaan antara perilaku (warisan) baru dan lama, dan kami tidak perlu meningkatkan peringatan penghentian.
Beberapa kemungkinan yang dapat dilakukan dalam kasus khusus ini:

1) Deteksi kasus ini (bahwa kategori yang disimpulkan adalah rentang berurutan), dan dalam hal ini jangan berikan peringatan.
- Ini mungkin untuk dideteksi (dengan sedikit kerumitan kode tambahan) karena kami sudah fit bagaimanapun
- Saya pikir ini akan menjadi kasus umum ketika menggunakan OneHotEncoder dengan data integer, dan kasus di mana pengguna sebenarnya tidak perlu khawatir tentang refactoring kami, jadi alangkah baiknya untuk tidak mengganggunya dengan peringatan
2) Selalu berikan peringatan, dan tunjukkan dalam pesan peringatan apa yang harus dilakukan jika Anda berada dalam kasus seperti itu (selain penjelasan apa yang harus dilakukan jika Anda tidak memiliki rentang berurutan):
- Jika mereka tahu bahwa mereka hanya memiliki rentang berurutan sebagai kategori, mereka ingin mengabaikan peringatan, jadi kami dapat menambahkan ke pesan peringatan penjelasan bagaimana melakukan ini (tambahkan contoh kode dengan filterwarnings yang dapat mereka salin tempel)
- Keuntungan potensial dari ini adalah bahwa kita juga dapat menambahkan pesan peringatan bahwa jika mereka menggunakan LabelEncoder untuk membuat bilangan bulat, mereka sekarang dapat langsung menggunakan OneHotEncoder (saya pikir ini saat ini adalah pola penggunaan yang khas). Dengan begitu, peringatan itu juga akan hilang
3) Selalu berikan peringatan tetapi berikan kata kunci untuk membungkamnya (misalnya legacy_mode=False )
- Jika menurut kami saran untuk menggunakan pernyataan filterwarnings (lihat poin 2 di atas) terlalu rumit, kami juga dapat menambahkan kata kunci untuk mendapatkan hasil yang sama
- Kerugian dari ini adalah memperkenalkan kata kunci yang tidak akan diperlukan lagi dalam beberapa rilis saat penghentian dibersihkan.

Saya pribadi mendukung opsi 1 atau 2. Menggunakan LabelEncoder sebelum OneHotEncoder tampaknya menjadi pola yang khas (dari pencarian github cepat), dan dalam hal ini Anda selalu memiliki rentang berurutan, dan tidak akan pernah ada perubahan perilaku dengan implementasi baru, jadi kami tidak perlu memperingatkannya. Di sisi lain, jika kami memperingatkan, kami dapat mengarahkan mereka pada fakta bahwa jika mereka menggunakan LabelEncoder, mereka tidak perlu lagi melakukannya. Yang akan menyenangkan untuk benar-benar memberikan saran ini secara eksplisit.
Pertanyaannya adalah seberapa sering pengguna memiliki bilangan bulat berurutan sebagai kategori tanpa menggunakan LabelEncoder seperti langkah sebelumnya ..

Hmm, satu kasus yang saya lupa adalah ketika Anda memiliki kategori yang disimpulkan bilangan bulat yang tidak berurutan (katakanlah [1,3,5]), tetapi Anda menginginkan perilaku baru dan bukan perilaku lama (jadi dalam hal ini Anda tidak bisa mengabaikan peringatan , karena itu akan menangani nilai yang tidak terlihat secara berbeda dalam langkah transformasi, yaitu nilai di antara rentang (misalnya 2) tidak akan menimbulkan kesalahan).
Jika kami tidak menyediakan kata kunci legacy_mode=False , satu-satunya cara untuk mendapatkan perilaku baru adalah dengan meneruskan categories=[1,3,5] secara manual, yang dapat sedikit merepotkan. Itu mungkin alasan untuk memilih opsi 3 dan melepaskan keberatan saya untuk memperkenalkan kata kunci sementara legacy_mode=False (tetapi juga tidak sepenuhnya yakin itu layak, karena ini akan menjadi satu-satunya kasus* di mana kata kunci seperti itu sebenarnya diperlukan)

* this only case = data integer dengan kategori yang disimpulkan yang bukan rentang berurutan, dan di mana Anda tidak dapat / tidak ingin mengatur kategori secara manual atau mengatur handle_unknown untuk diabaikan.

Maaf untuk semua teks yang panjang, tetapi cukup rumit :)

Kami hanya berbicara tentang kasus di mana n_values ​​tidak disetel, bukan?

Saya baik-baik saja dengan 1., dan itu tidak akan lebih mahal, karena otomatis
sudah perlu memeriksa set label. Saya juga bisa menerima, karena
kesederhanaan, varian dari 3. itu hanya "OneHotEncoder berjalan di warisan
mode. Setel kategori='auto' untuk perilaku yang sedikit berbeda tanpa a
peringatan."

Kami hanya berbicara tentang kasus di mana n_values ​​tidak disetel, bukan?

Ya (kasus lain dengan mudah diterjemahkan dalam nilai categories yang setara, dengan peringatan penghentian yang bagus, dan tanpa perbedaan dalam perilaku baru dan lama)

varian dari 3. yang hanya "OneHotEncoder berjalan dalam mode lama. Setel kategori='otomatis' untuk perilaku yang sedikit berbeda tanpa peringatan."

Ah, itu terdengar seperti ide yang bagus! (terlepas dari apakah mendeteksi kasus kategori berurutan atau tidak). Jadi kami mengatur kode default categories ke None (tanpa mengubah semantik default), jadi kami tahu jika pengguna mengaturnya secara eksplisit, dan dengan cara itu adalah cara yang bagus untuk menunjukkan legacy_mode=False tanpa perlu kata kunci tambahan itu.

Ya, tetapi hanya jika kami ingin memperingatkan setiap kali seseorang menggunakannya tanpa melewati
kategori. Ini adalah pendekatan implementasi yang murah, tapi mungkin saja
tidak perlu bertele-tele untuk pengguna, itulah sebabnya saya lebih suka 1 jika itu
dapat dilakukan secara sederhana.

Segar apa ini :-/

ATAU kita bisa menamai yang baru DummyEncoder ;) (meskipun itu agak bertentangan dengan DummyClassifier)

@amueller Jangan membaca semua hal di atas!
Saya hanya berencana membuat ringkasan yang bagus untuk pembaca baru edisi ini. Diskusi di atas terlalu rumit (juga karena saya masih belum sepenuhnya memahami perilaku kompleks OneHotEncoder ... :-))

ATAU kita bisa menamai yang baru DummyEncoder ;)

Saya pikir @GaelVaroquaux menentang itu karena "satu-panas" dikenal sebagai ini di lebih banyak bidang (dan kami sudah menggunakan 'Dummy' untuk hal-hal lain di scikit-learn ...)

Mengulangi ini untuk konsistensi dalam penamaan tidak sepadan. Kami tidak konsisten dalam penamaan di mana saja. Bisakah Anda meringkas diskusi yang mengarah ke ini?

Saya pikir "dummy" adalah apa yang digunakan ahli statistik dan itulah yang digunakan panda.

Posting teratas masih akurat dan layak dibaca, dan merangkum alasan untuk tidak menyimpan CategoricalEncoder (yang tidak berarti bahwa kita perlu menggunakan OneHotEncoder alih-alih misalnya DummyEncoder, itu pertanyaan terpisah)

Saya membaca posting teratas. Itulah yang saya maksud ketika saya mengatakan "melakukan ini untuk konsistensi tidak sepadan".

masalah yang dibuka

Bisakah Anda menjelaskan itu?

"melakukan ini untuk konsistensi tidak sepadan"

Dengan konsistensi, apakah Anda menunjuk ke skema penamaan "apa yang diterima" vs "apa yang dilakukannya"? Jika demikian, itu hanya alasan kecil. Bagi saya ini terutama masalah skalabilitas dalam menambahkan lebih banyak fitur ke satu kelas.

masalah yang dibuka

Kami memiliki masalah tentang cara menangani nilai yang hilang (https://github.com/scikit-learn/scikit-learn/issues/10465), dan untuk ini Anda mungkin menginginkan perilaku yang berbeda untuk penyandian ordinal dan satu-panas (atau tidak semua opsi berlaku untuk keduanya, ..). Kami juga sudah memiliki handle_unknown yang hanya relevan untuk enkode one-hot dan bukan untuk ordinal. Dan ada https://github.com/scikit-learn/scikit-learn/issues/10518 tentang pembobotan fitur untuk penyandian onehot, tetapi juga tidak relevan untuk ordinal (masalah ini pada akhirnya tidak menjadi masalah, seperti yang dapat Anda lakukan pembobotan dengan argumen ColumnTransformer transformer_weights). Dan kami juga memiliki permintaan fitur untuk menambahkan sesuatu seperti drop_first untuk one-hot, yang sekali lagi tidak relevan untuk pengkodean ordinal.

Saya tidak melihat bagaimana perubahan yang diusulkan akan banyak membantu dengan nilai-nilai yang hilang. Dan memiliki opsi yang tidak kompatibel adalah sesuatu yang sering terjadi di scikit-learn. Tidak ideal, tetapi juga bukan masalah besar.

Saya tidak melihat bagaimana perubahan yang diusulkan akan banyak membantu dengan nilai-nilai yang hilang.

Itu tidak membantu seperti itu , tetapi membuatnya kurang kompleks untuk memiliki opsi khusus yang dirancang khusus untuk jenis penyandian yang berbeda.

Dan memiliki opsi yang tidak kompatibel adalah sesuatu yang sering terjadi di scikit-learn. Tidak ideal, tetapi juga bukan masalah besar.

Saat ini tentu masih OK, tidak terlalu banyak opsi yang tidak kompatibel (tetapi juga sebagian karena saya memindahkan sparse=True/False ke opsi encoding ). Tetapi pertanyaannya adalah sejauh mana kami ingin memperluas fungsi pengkodean di scikit-learn di masa mendatang. Yang tentu saja merupakan pertanyaan yang sulit untuk dijawab sekarang .
Kami sudah memiliki PR untuk 'pengkodean unary'. Bukankah ini lebih baik ditambahkan ke CategoricalEncoder daripada menambahkan kelas baru UnaryEncoder? Dan bagaimana jika seseorang ingin menambahkan 'pengkodean biner'? Atau '(berarti) pembuat enkode target'?

"Rata-rata target encoder" adalah CountTransformer , ada PR untuk itu ;)

Apakah Anda memiliki tautan untuk itu? Mencari "CountTransformer" tidak memberikan hasil apa pun

Maaf, CountFeaturizer #9614

Ini tentu terkait, tetapi bukan penyandian target yang berarti. Juga, itu menambahkan kolom, bukan menggantikan, jadi belum akan berfungsi di luar kotak untuk data kategorikal string (tapi itu lebih banyak umpan balik tentang PR itu, bukan untuk dibahas di sini).

Mengapa tidak berarti penyandian target? Tapi ya jangan terlalu banyak mengalihkan di sini ;)

Jadi sebagai ringkasan dari pertanyaan aktual yang perlu kita jawab (dalam urutan ini!):

  1. Apakah kita menyimpan CategoricalEncoder ? Jika tidak, idenya adalah untuk membaginya dalam kelas yang berbeda, satu kelas untuk setiap jenis penyandian (saat ini penyandian 'onehot' dan 'ordinal').

  2. Jika kita membagi dalam beberapa kelas, kita dapat (idealnya?) menggunakan OneHotEncoder untuk pengkodean 'onehot', tetapi kelas ini sudah ada. Jadi, apakah kita mengintegrasikan pengkodean 'onehot' baru (yang mendukung string dan memiliki parameter berbeda) di kelas OneHotEncoder yang ada? Atau kita pilih nama lain? (misalnya DummyEncoder)

  3. Jika kami memilih untuk mengintegrasikan ke dalam OneHotEncoder yang ada, apakah kami setuju dengan konsekuensi berikut: kami menghentikan sekelompok kata kunci/atribut OneHotEncoder, dan kasus penggunaan tertentu (secara otomatis mengabaikan nilai yang tidak terlihat dalam rentang nilai yang terlihat) tidak akan mungkin dilakukan lagi setelah periode penghentian.

Sebagian besar diskusi di atas adalah tentang pertanyaan 3 (detail rumit tentang cara mengintegrasikan CategoricalEncoder(encoding='onehot') ke dalam OneHotEncoder). Tapi mari kita sepakati dulu keputusan untuk 2 pertanyaan pertama.

faktor lain bagi saya adalah semua orang berpikir mode otomatis saat ini masuk
OneHotEncoder aneh. implementasinya mengubah coo ke csr juga
aneh. itu layak didesain ulang. dan memberi tahu orang-orang "jika Anda ingin yang seksi
menyandikan string, buka CategoricalEncoder sebagai gantinya" canggung, karena OHE
sudah ditujukan untuk kategorikal...

hrm. Saya kira kami menyimpan OneHotEncoder karena lebih efisien ketika dapat digunakan.... Idealnya kami akan menyingkirkan semua perilaku aneh. Saya agak ingin mencelanya tetapi kemudian kami tidak...

Saya agak ingin mencelanya tetapi kemudian kami tidak...

Dalam PR POC saya (https://github.com/scikit-learn/scikit-learn/pull/10523), saya menghentikan hampir semua OneHotEncoder, kecuali namanya ...

Ini tidak jauh lebih efisien. Dan jika LabelEncoder memiliki jalur cepat untuk int
dalam kisaran [0, n_values-1], jika dibenarkan, itu sudah cukup baik.

@amueller , apakah Anda diyakinkan oleh masalah bahwa kami pada akhirnya menginginkan parameter tambahan yang berbeda (misalnya drop_first, penanganan nan) tergantung pada penyandian, dan itu membenarkan memiliki penyandi diskrit yang berbeda untuk setiap format penyandian?

Saya akan mencoba untuk melihat ini di liburan musim semi dalam dua minggu, ok? tidak yakin apakah saya akan punya waktu sebelum itu :-/

Saya harap ini bukan tempat yang salah untuk bertanya tetapi apa yang dilakukan implementasi saat ini dengan tabel yang dicampur kategorikal dan non-kategori dalam satu kolom? Mengambil contoh dari https://github.com/pandas-dev/pandas/issues/17418

Pertimbangkan kerangka data df = pd.DataFrame([{'apple': 1, 'pear':'a', 'carrot': 1}, {'apple':'a', 'pear':2, 'carrot':3}, {'apple': 2, 'pear':3, 'carrot':1}, {'apple': 3, 'pear':'b', 'carrot': 1}, {'apple': 4, 'pear':4, 'carrot': 1}]) yang sama dengan:

  apple  carrot pear
0     1       1    a
1     a       3    2
2     2       1    3
3     3       1    b
4     4       1    4

DictVectorizer memberikan persis apa yang saya butuhkan dalam kasus ini.

    from sklearn.feature_extraction import DictVectorizer
    enc = DictVectorizer(sparse = False)
    enc.fit_transform(df.to_dict(orient='r'))

Ini memberikan:

array([[ 1.,  0.,  1.,  0.,  1.,  0.],
       [ 0.,  1.,  3.,  2.,  0.,  0.],
       [ 2.,  0.,  1.,  3.,  0.,  0.],
       [ 3.,  0.,  1.,  0.,  0.,  1.],
       [ 4.,  0.,  1.,  4.,  0.,  0.]])

Kita dapat melihat fitur nama kolom dengan:

    enc.feature_names_
    ['apple', 'apple=a', 'carrot', 'pear', 'pear=a', 'pear=b']

Akan sangat bagus jika CategoricalEncoder baru memiliki opsi untuk melakukan hal yang sama.

Saya tidak berpikir kami bermaksud menangani kasus campuran semacam itu

Itu memalukan. Satu sub kasus sederhana adalah di mana kolom numerik tetapi memiliki beberapa nilai yang hilang. Solusi sederhana adalah mengubah NaN menjadi string kosong dan kemudian menggunakan DictVectorizer seperti pada contoh saya di atas. Ini secara efektif menciptakan fitur baru ketika nilai hilang tetapi membiarkan nilai numerik tidak berubah. Saya telah menemukan ini teknik yang sangat berguna.

Akankah CategoricalEncoder baru dapat melakukan hal serupa?

kami telah mempertimbangkan untuk mengizinkan pengguna memperlakukan NaN sebagai kategori terpisah
atau serupa. tapi itu tidak sama dengan menangani nilai numerik arbitrer seperti
berbeda dengan string.

Boleh juga.

Anda benar ada dua kasus penggunaan. Biarkan saya menjelaskan contoh khusus di mana memperlakukan nilai numerik sebagai berbeda dari string telah berguna bagi saya. Mungkin ada solusi yang lebih baik.

Katakanlah Anda memiliki fitur numerik integer yang mengambil rentang nilai yang besar. Namun Anda menduga bahwa untuk beberapa nilai kecil, nilai tepatnya adalah signifikan. Untuk nilai yang lebih besar, Anda menduga ini bukan masalahnya. Hal sederhana yang dapat dilakukan adalah mengonversi semua nilai kecil menjadi string, jalankan DictVectorizer seperti di atas lalu lakukan pemilihan fitur atau langsung gunakan classifier favorit Anda.

Jadi Anda menggunakannya untuk diskritisasi non-linier? Rilisan berikutnya adalah
kemungkinan akan menyertakan discretizer lebar tetap, tetapi mengikuti dari log
transformasi atau transformasi kuantil itu harus bertindak sangat mirip dengan apa yang Anda
mau... Tapi transformasi log mungkin saja sudah cukup di pengaturan Anda.

Pada 25 Februari 2018 pukul 18:10, lesshaste [email protected] menulis:

Boleh juga.

Anda benar ada dua kasus penggunaan. Mari saya jelaskan contoh tertentu
di mana memperlakukan nilai numerik berbeda dari string telah berguna
untuk saya. Mungkin ada solusi yang lebih baik.

Katakanlah Anda memiliki fitur numerik bilangan bulat yang membutuhkan rentang besar
nilai-nilai. Namun Anda menduga bahwa untuk beberapa nilai kecil, nilai yang tepat
signifikan. Untuk nilai yang lebih besar, Anda menduga ini bukan masalahnya. Sederhana
hal yang harus dilakukan adalah mengonversi semua nilai kecil menjadi string, jalankan DictVectorizer
seperti di atas lalu lakukan pemilihan fitur atau gunakan saja favorit Anda
pengklasifikasi secara langsung.


Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub
https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment-368288727 ,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/AAEz60cmjwlDVKGyXc6oPyIC9oLbptSgks5tYQdvgaJpZM4RpUE8
.

@jnothman Ya dalam arti tertentu kecuali dengan twist. Katakanlah saya menduga bahwa beberapa nilai dari 1...1024 bermakna. Itu 22 menunjukkan sesuatu yang spesifik yang sangat berbeda dari 21 atau 23. Mengambil log tidak akan membantu di sini. Tetapi saya ingin membiarkan semua nilai di atas 1024 sebagai numerik karena menurut saya nilai-nilai spesifik itu tidak terlalu berarti.

Sepertinya Anda tahu terlalu banyak tentang variabel Anda untuk generik
berubah menjadi hal yang Anda butuhkan.

Pada 25 Februari 2018 pukul 20:37, lesshaste [email protected] menulis:

@jnothman https://github.com/jnothman Ya dalam arti tertentu kecuali dengan a
memutar. Katakanlah saya menduga bahwa beberapa nilai dari 1...1024 bermakna.
Itu adalah 22 menunjukkan sesuatu yang spesifik yang sangat berbeda dari 21 atau

  1. Mengambil log tidak akan membantu di sini. Tapi saya ingin meninggalkan semua nilai
    1024 sebagai numerik karena saya tidak berpikir nilai-nilai spesifik itu berarti banyak.


Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub
https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment-368295895 ,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/AAEz65bOdVB6k7rCAcgLBYz_NslxXWV0ks5tYSnggaJpZM4RpUE8
.

@jnothman Agar sedikit lebih jelas, saya tidak tahu bahwa 22 itu signifikan. Saya hanya curiga ada beberapa nilai tetapi saya tidak tahu yang mana atau berapa jumlahnya. Saya telah menemukan "konversi ke string" dan kemudian metode DictVectorizer sangat berguna untuk menemukan yang mana ini.

@lesshaste Untuk masalah tentang NaN sebagai kategori terpisah, lihat https://github.com/scikit-learn/scikit-learn/issues/10465
Jika Anda ingin mendiskusikan lebih lanjut diskritisasi non-linier tertentu atau penyandian numerik/string campuran, jangan ragu untuk membuka edisi baru. Tapi ingin tetap yang satu ini terfokus pada masalah asli, yaitu penamaan dan organisasi di kelas yang berbeda dari CategoricalEncoder/OneHotEncoder.

Saya akan mencoba untuk melihat ini di liburan musim semi dalam dua minggu, ok? tidak yakin apakah saya akan punya waktu sebelum itu :-/

@amueller tidak apa-apa. Saya tidak akan punya waktu dua minggu mendatang untuk mengerjakan PR yang diblokir oleh ini. Setelah itu saya juga harus punya waktu lagi untuk mengerjakannya.

@amueller apakah Anda punya waktu untuk melihat ini?

@amueller apakah Anda

Maaf karena tidak hadir. Sepertinya baik-baik saja, tetapi bisakah Anda memberi saya dua minggu agar saya benar-benar dapat meninjau? Terima kasih!

@amueller tidak masalah, bagi saya sama :-)
Tapi, saya sekarang berencana untuk melihat ini lagi. Jadi jika Anda bisa memberikan tampilan ini, itu akan disambut baik. Saya memiliki beberapa pekerjaan yang harus dilakukan pada PR (https://github.com/scikit-learn/scikit-learn/pull/10523), jadi jangan tinjau secara detail (Anda dapat melihatnya untuk mendapatkan ide dari apa yang kami usulkan).
Saya pikir pertanyaan utama yang ingin saya lihat dijawab sebelum saya menghabiskan banyak waktu di dalamnya, adalah apakah Anda setuju dengan membagi CategoricalEncoder menjadi beberapa kelas, dan dalam hal itu, jika Anda setuju dengan menggunakan kembali OneHotEncoder (yang berarti mencela beberapa fitur (aneh) saat ini). Pertanyaan-pertanyaan itu dirangkum dalam https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment -363851328 dan https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment -364802471.

(dan setelah kita sepakat di bagian itu, masih banyak yang harus dibahas tentang implementasi sebenarnya di PR :))

Saya memperbarui PR https://github.com/scikit-learn/scikit-learn/pull/10523 , siap untuk ditinjau

Saya akan dengan hati-hati mengatakan saya kembali;)

IMHO yang paling penting adalah API universal (yaitu parameter dan pola perilaku) untuk semua pembuat enkode yang kita diskusikan

PS https://github.com/scikit-learn-contrib/categorical-encoding ?

Dalam paket category_encoders , semua pembuat enkode memiliki argumen cols , mirip dengan categorical_features di OneHotEncoder lama (meskipun tidak menerima jenis nilai yang persis sama). Lihat misalnya http://contrib.scikit-learn.org/categorical-encoding/onehot.html
Jadi itu terkait dengan diskusi saat ini yang kami lakukan di https://github.com/scikit-learn/scikit-learn/pull/10523 tentang mencela categorical_features atau tidak.

Selebihnya, saya pikir tidak ada kata kunci yang benar-benar bertentangan (mereka memiliki beberapa kata kunci lain yang spesifik untuk kerangka data yang tidak akan kami tambahkan ke sklearn saat ini). Penamaan OneHotEncoder dan OrdinalEncoder setidaknya konsisten dengan paket category_encoders .

Apakah halaman ini membantu?
0 / 5 - 0 peringkat