Clustering pada output t-SNE


78

Saya punya aplikasi di mana akan berguna untuk mengelompokkan dataset yang berisik sebelum mencari efek subkelompok di dalam kluster. Saya pertama kali melihat PCA, tetapi dibutuhkan ~ 30 komponen untuk mencapai 90% dari variabilitas, jadi pengelompokan hanya pada beberapa PC akan membuang banyak informasi.

Saya kemudian mencoba t-SNE (untuk pertama kalinya), yang memberi saya bentuk aneh dalam dua dimensi yang sangat cocok untuk pengelompokan melalui k-means. Terlebih lagi, menjalankan hutan acak pada data dengan tugas cluster sebagai hasilnya menunjukkan bahwa cluster memiliki interpretasi yang cukup masuk akal mengingat konteks masalah, dalam hal variabel yang membentuk data mentah.

Tetapi jika saya akan melaporkan kluster ini, bagaimana saya menggambarkannya? K-means cluster pada komponen utama mengungkapkan individu yang berdekatan satu sama lain dalam hal variabel turunan yang terdiri dari X% dari varians dalam dataset. Pernyataan setara apa yang dapat dibuat tentang klaster t-SNE?

Mungkin sesuatu dengan efek:

t-SNE mengungkapkan perkiraan kedekatan dalam manifold dimensi tinggi yang mendasarinya, jadi klaster pada representasi dimensi rendah dari ruang dimensi tinggi memaksimalkan "kemungkinan" bahwa individu yang berdekatan tidak akan berada dalam kelompok yang sama

Adakah yang bisa mengusulkan uraian yang lebih baik dari itu?


1
Saya akan berpikir bahwa triknya adalah untuk menggambarkan kelompok berdasarkan pada variabel asli, daripada variabel dalam ruang berkurang.
Tim

1
Benar, tetapi tanpa penjelasan ringkas dan intuitif tentang tujuan apa yang diminimalkan oleh algoritma penugasan gugus, saya mungkin terbuka untuk tuduhan memilih algoritme pengelompokan yang memfasilitasi mendapatkan hasil yang saya inginkan.
generic_user

1
Untuk beberapa peringatan dan visual yang bagus di t-SNE juga lihat distill.pub/2016/misread-tsne
Tom Wenseleers

Jawaban:


96

Masalah dengan t-SNE adalah bahwa ia tidak menjaga jarak atau kepadatan. Hanya sampai batas tertentu mempertahankan tetangga terdekat. Perbedaannya halus, tetapi memengaruhi algoritme berbasis kepadatan atau jarak.

Untuk melihat efek ini, cukup buat distribusi Gaussian multivarian. Jika Anda memvisualisasikan ini, Anda akan memiliki bola yang padat dan jauh lebih sedikit padat, dengan beberapa outlier yang bisa sangat jauh.

Sekarang jalankan t-SNE pada data ini. Anda biasanya akan mendapatkan lingkaran dengan kepadatan yang agak seragam. Jika Anda menggunakan kebingungan rendah, mungkin ada beberapa pola aneh di sana. Tapi Anda tidak bisa membedakan outlier lagi.

Sekarang mari kita buat lebih rumit. Mari kita gunakan 250 poin dalam distribusi normal pada (-2,0), dan 750 poin dalam distribusi normal pada (+2,0).

Memasukan data

Ini seharusnya merupakan kumpulan data yang mudah, misalnya dengan EM:

Pengelompokan EM

Jika kita menjalankan t-SNE dengan kebingungan standar 40, kita mendapatkan pola berbentuk aneh:

t-SNE p = 40

Tidak buruk, tetapi juga tidak mudah untuk dikelompokkan, bukan? Anda akan kesulitan menemukan algoritma pengelompokan yang bekerja di sini persis seperti yang diinginkan. Dan bahkan jika Anda akan meminta manusia untuk mengelompokkan data ini, kemungkinan besar mereka akan menemukan lebih dari 2 cluster di sini.

Jika kita menjalankan t-SNE dengan kebingungan yang terlalu kecil seperti 20, kita mendapatkan lebih dari pola-pola ini yang tidak ada:

t-SNE p = 20

Ini akan mengelompok mis dengan DBSCAN, tetapi akan menghasilkan empat cluster. Jadi berhati-hatilah, t-SNE dapat menghasilkan pola "palsu"!

Kesulitan optimal tampaknya sekitar 80 untuk set data ini; tapi saya tidak berpikir parameter ini akan bekerja untuk setiap kumpulan data lainnya.

t-SNE p = 80

Sekarang ini secara visual menyenangkan, tetapi tidak lebih baik untuk analisis . Seorang annotator manusia kemungkinan bisa memilih potongan dan mendapatkan hasil yang layak; Namun k-means akan gagal bahkan dalam skenario yang sangat sangat mudah ini ! Anda sudah dapat melihat bahwa informasi kepadatan hilang , semua data tampaknya hidup di daerah dengan kepadatan yang hampir sama. Jika kita lebih lanjut akan meningkatkan kebingungan, keseragaman akan meningkat, dan pemisahan akan berkurang lagi.

Dalam kesimpulan, gunakan t-SNE untuk visualisasi (dan coba berbagai parameter untuk mendapatkan sesuatu yang menyenangkan secara visual!), Tetapi jangan menjalankan pengelompokan setelah itu , khususnya jangan gunakan algoritme berbasis jarak atau kepadatan, karena informasi ini sengaja dibuat (!) kalah. Pendekatan berbasis-lingkungan mungkin baik-baik saja, tetapi kemudian Anda tidak perlu menjalankan t-SNE terlebih dahulu, cukup gunakan tetangga segera (karena t-SNE berusaha menjaga nn-grafik ini sebagian besar tetap utuh).

Lebih banyak contoh

Contoh-contoh ini disiapkan untuk presentasi makalah (tetapi belum dapat ditemukan di makalah, seperti yang saya lakukan percobaan ini nanti)

Erich Schubert, dan Michael Gertz.
Embedded t-Stochastic Neighbor Intrinsik untuk Visualisasi dan Deteksi Outlier - Sebuah Penyembuhan Terhadap Kutukan Dimensiitas?
Dalam: Prosiding Konferensi Internasional ke-10 tentang Pencarian dan Aplikasi Kesamaan (SISAP), Munich, Jerman. 2017

Pertama, kami memiliki data input ini:

Ikan

Seperti yang Anda tebak, ini berasal dari gambar "warna saya" untuk anak-anak.

Jika kita menjalankan ini melalui SNE ( BUKAN t-SNE , tapi pendahulunya):

Ikan SNE

Wow, ikan kita sudah menjadi monster laut! Karena ukuran kernel dipilih secara lokal, kami kehilangan banyak informasi kepadatan.

Tetapi Anda akan sangat terkejut dengan output dari t-SNE:

ikan t-SNE

Saya sebenarnya telah mencoba dua implementasi (ELKI, dan implementasi sklearn), dan keduanya menghasilkan hasil seperti itu. Beberapa fragmen terputus, tetapi masing-masing terlihat agak konsisten dengan data asli.

Dua poin penting untuk menjelaskan ini:

  1. SGD bergantung pada prosedur perbaikan berulang, dan mungkin terjebak dalam optima lokal. Secara khusus, ini menyulitkan algoritma untuk "membalik" bagian dari data yang telah dicerminkannya, karena ini akan memerlukan titik bergerak melalui yang lain yang seharusnya terpisah. Jadi, jika beberapa bagian ikan dicerminkan, dan bagian lainnya tidak dicerminkan, mungkin tidak dapat memperbaikinya.

  2. t-SNE menggunakan distribusi-t di ruang yang diproyeksikan. Berbeda dengan distribusi Gaussian yang digunakan oleh SNE biasa, ini berarti sebagian besar poin akan saling tolak , karena mereka memiliki 0 afinitas dalam domain input (Gaussian mendapatkan nol dengan cepat), tetapi afinitas> 0 dalam domain output. Terkadang (seperti pada MNIST) ini membuat visualisasi yang lebih bagus. Secara khusus, ini dapat membantu "memecah" suatu set data sedikit lebih banyak dari pada domain input. Penolakan tambahan ini juga sering menyebabkan poin untuk lebih merata menggunakan area, yang juga bisa diinginkan. Tapi di sini dalam contoh ini, efek memukul mundur sebenarnya menyebabkan fragmen ikan terpisah.

Kami dapat membantu (pada kumpulan data mainan ini ) masalah pertama dengan menggunakan koordinat asli sebagai penempatan awal, daripada koordinat acak (seperti biasanya digunakan dengan t-SNE). Kali ini, gambar sklearn bukan ELKI, karena versi sklearn sudah memiliki parameter untuk melewati koordinat awal:

Ikan, t-SNE, dengan koordinat asli sebagai inisialisasi

Seperti yang Anda lihat, bahkan dengan penempatan awal "sempurna", t-SNE akan "memecah" ikan di sejumlah tempat yang semula terhubung karena tolakan Student-t dalam domain keluaran lebih kuat daripada afinitas Gaussian dalam input ruang.

Seperti yang Anda lihat, t-SNE (dan SNE juga!) Adalah teknik visualisasi yang menarik , tetapi mereka perlu ditangani dengan hati-hati. Saya lebih suka tidak menerapkan k-means pada hasilnya! karena hasilnya akan sangat terdistorsi, dan tidak ada jarak atau kepadatan yang terpelihara dengan baik. Sebaliknya, lebih baik menggunakannya untuk visualisasi.


1
Terima kasih atas jawabannya. Saya dapat membayangkan metode pengelompokan adaptif berbasis lingkungan, tetapi adakah metode spesifik yang dikembangkan dengan baik yang dapat Anda rekomendasikan?
generic_user

1
CHAMAELEON mungkin yang paling banyak dikutip, tetapi tampaknya hanya ada biner yang tersedia untuk langkah inti. Idenya terdengar bagus, tetapi Anda akan dengan cepat mengalami efek yang sama dengan t-SNE yang terlihat. Seperti kecenderungan untuk "berduyun-duyun" seperti yang terlihat pada p = 20, masalah dengan hub dan anti-hub, dll.
Erich Schubert

2
@AlexR: Perplexity digunakan untuk menghitung kesamaan dalam ruang dimensi tinggi yang kemudian dicoba oleh t-sne dalam 2D. Mengubah kebingungan berarti mengubah kesamaan, jadi saya tidak melihat bagaimana membandingkan divergensi KL yang dihasilkan bisa bermakna.
Amuba mengatakan Reinstate Monica

1
@AlexR. "Hanya probabilitas bersyarat ruang dimensi bawah yang tergantung pada kebingungan" - pernyataan ini salah. Perplexity digunakan untuk memilih sigma yang dibutuhkan untuk persamaan (1), sehingga memengaruhi cond. probs. di ruang penuh .
Amuba kata Reinstate Monica

1
Untuk beberapa peringatan dan visual yang bagus di t-SNE juga lihat distill.pub/2016/misread-tsne
Tom Wenseleers

34

Saya ingin memberikan pendapat yang agak berbeda dengan yang diperdebatkan dengan baik (+1) dan jawaban yang sangat terangkat oleh @ErichSchubert. Erich tidak merekomendasikan pengelompokan pada output t-SNE, dan menunjukkan beberapa contoh mainan yang bisa menyesatkan. Sarannya adalah menerapkan pengelompokan ke data asli sebagai gantinya.

gunakan t-SNE untuk visualisasi (dan coba berbagai parameter untuk mendapatkan sesuatu yang menyenangkan secara visual!), tetapi jangan menjalankan pengelompokan setelah itu, khususnya jangan gunakan algoritma berbasis jarak atau kepadatan, karena informasi ini sengaja (!) hilang.

Saya menyadari cara-cara di mana output t-SNE mungkin menyesatkan (lihat https://distill.pub/2016/misread-tsne/ ) dan saya setuju bahwa itu dapat menghasilkan hasil yang aneh dalam beberapa situasi.

Tetapi mari kita perhatikan beberapa data dimensi tinggi nyata.

Ambil data MNIST : 70000 gambar satu digit. Kita tahu bahwa ada 10 kelas dalam data. Kelas-kelas ini tampak terpisah dengan baik bagi pengamat manusia. Namun, pengelompokan data MNIST ke 10 cluster adalah masalah yang sangat sulit. Saya tidak mengetahui adanya algoritma pengelompokan yang akan dengan benar mengelompokkan data menjadi 10 kelompok; lebih penting lagi, saya tidak mengetahui adanya heuristik pengelompokan yang akan menunjukkan bahwa ada 10 (tidak lebih dan tidak kurang) cluster dalam data. Saya yakin bahwa pendekatan yang paling umum tidak akan dapat menunjukkan itu.

Tapi mari kita lakukan t-SNE sebagai gantinya. (Seseorang dapat menemukan banyak angka t-SNE yang diterapkan pada MNIST online, tetapi mereka sering tidak optimal. Dalam pengalaman saya, perlu menjalankan pembesaran awal untuk beberapa waktu untuk mendapatkan hasil yang baik. Di bawah ini saya menggunakan perplexity=50, max_iter=2000, early_exag_coeff=12, stop_lying_iter=1000). Inilah yang saya dapatkan, di sebelah kiri tidak berlabel, dan di sebelah kanan diwarnai sesuai dengan kebenaran dasar:

MNIST t-SNE

Saya berpendapat bahwa representasi t-SNE yang tidak berlabel memang menyarankan 10 kluster. Menerapkan algoritma pengelompokan berbasis kepadatan yang baik seperti HDBSCAN dengan parameter yang dipilih dengan hati-hati akan memungkinkan untuk mengelompokkan data 2D ini menjadi 10 cluster.

Jika seseorang akan ragu bahwa plot kiri di atas memang menunjukkan 10 klaster, inilah yang saya dapatkan dengan trik "keterlambatan berlebihan" di mana saya juga menjalankan max_iter=200iterasi exaggeration=4(trik ini disarankan dalam makalah hebat ini: https://arxiv.org /abs/1712.09005 ):

MNIST t-SNE dengan keterlambatan berlebihan

Sekarang harus sangat jelas bahwa ada 10 cluster.

Saya mendorong semua orang yang berpikir mengelompokkan setelah t-SNE adalah ide yang buruk untuk menunjukkan algoritma pengelompokan yang akan mencapai hasil yang relatif baik.

Dan sekarang bahkan lebih banyak data nyata.

Dalam kasus MNIST kita tahu kebenaran dasar. Pertimbangkan sekarang beberapa data dengan kebenaran dasar yang tidak diketahui. Clustering dan t-SNE secara rutin digunakan untuk menggambarkan variabilitas sel dalam data RNA-seq sel tunggal. Misalnya Shekhar et al. 2016 mencoba mengidentifikasi kelompok di antara 27000 sel retina (ada sekitar 20 ribu gen dalam genom tikus sehingga dimensi data pada prinsipnya sekitar 20 ribu; namun orang biasanya memulai dengan mengurangi dimensi dengan PCA menjadi 50 atau lebih). Mereka melakukan t-SNE dan mereka secara terpisah melakukan pengelompokan (pipa pengelompokan yang rumit diikuti oleh beberapa penggabungan kluster dll). Hasil akhir terlihat menyenangkan:

masukkan deskripsi gambar di sini

Alasannya terlihat begitu menyenangkan adalah bahwa t-SNE menghasilkan cluster yang jelas berbeda dan algoritma cluster menghasilkan cluster yang persis sama. Bagus.

Namun, jika Anda melihat dalam suplemen Anda akan melihat bahwa penulis mencoba berbagai pendekatan pengelompokan. Banyak dari mereka terlihat buruk pada plot t-SNE karena misalnya, klaster pusat besar akan terpecah menjadi banyak sub-klaster:

masukkan deskripsi gambar di sini

Jadi, apa yang Anda yakini: output dari algoritma pengelompokan favorit Anda bersama dengan heuristik favorit Anda untuk mengidentifikasi jumlah cluster, atau apa yang Anda lihat pada plot t-SNE? Sejujurnya, terlepas dari semua kekurangan t-SNE, saya cenderung lebih percaya t-SNE. Atau dalam hal apa pun, saya tidak mengerti mengapa saya harus kurang percaya .


2
Dan untuk contoh terakhir, bukankah itu yang pada dasarnya @ErichSchubert amati di atas: Anda bisa mendapatkan hasil yang "menyenangkan" secara visual - yang jelas-jelas salah? Seperti halnya kebingungan 20? TSNE itu suka memisahkan bagian (seperti pada ikan) yang tidak dipisahkan? Jadi, tahukah Anda bahwa kluster yang Anda lihat adalah kluster yang terpisah? Saya tidak suka "kotak hitam" ini di sana. Ya, kami cenderung lebih percaya plot seperti itu, tetapi bagaimana jika mereka salah?
Anony-Mousse

1
Nah, tSNE berbasiskan NN. Kesepakatan dengan ini diharapkan. tSNE adalah pilihan yang baik untuk memvisualisasikan NN. Itu tidak mempertahankan kesamaan dengan baik, jadi itu harus ditafsirkan dengan hati-hati, seperti yang saya mengerti. Kesenjangan dalam tSNE tidak menyiratkan jarak yang jauh.
Anony-Mousse

1
+1 Ingin tahu bagaimana kinerja UMAP dibandingkan dengan t-SNE.
Paul

1
@ Paul: penulis mengklaim keunggulan UMAP, dalam hal waktu komputasi, itu. Pada dataset MNIST, saya menemukan UMAP menghasilkan embedding yang lebih baik daripada t-SNE, tetapi tidak yakin pada dataset lain. Sejauh yang saya ketahui, baru-baru ini ada versi CUDA dari t-SNE, yang jauh lebih cepat daripada t-SNE tercepat sebelumnya, tetapi saya tidak dapat menginstal dan menguji.
SiXUlm

1
@SiXUlm github.com/KlugerLab/FIt-SNE bekerja jauh lebih cepat daripada Barnes-Hut t-SNE dan seringkali lebih cepat dari UMAP. Juga, dalam banyak kasus, seseorang dapat mencapai penyematan yang sangat mirip dengan t-SNE menggunakan beberapa tweak tambahan, misalnya pada MNIST, t-SNE dengan sedikit berlebihan menghasilkan hal yang hampir sama dengan UMAP, lihat contoh notebook Python di repositori FIt-SNE.
Amuba kata Reinstate Monica

6

Saya pikir dengan kebingungan besar t-SNE dapat merekonstruksi topologi global, seperti yang ditunjukkan dalam https://distill.pub/2016/misread-tsne/ .

Dari gambar ikan, saya mencicipi 4000 poin untuk t-SNE. Dengan kebingungan besar (2000), gambar ikan hampir direkonstruksi.

Ini gambar aslinya. Gambar asli

Berikut adalah gambar yang direkonstruksi oleh t-SNE dengan kebingungan = 2000. t-SNE direkonstruksi Gambar (kebingungan = 2000)


8
Jika Anda memilih kebingungan tinggi, itu bukan benar-benar tSNE lagi. Setiap titik adalah tetangga sekitar sehari-hari. Tidak lagi lokal. Ya, gambar 2d kemudian dapat direkonstruksi, karena ini 2d. Tetapi tidak melakukan semuanya itu lebih mudah.
Anony-Mousse

1
Pendapat saya adalah tSNE dengan kebingungan besar dapat merekonstruksi topologi global. Gambar 2d adalah contoh karena dimensi intrinsiknya adalah 2. Aplikasi nyata dari tSNE harus memilih kebingungan yang tepat sesuai dengan tujuan untuk menangkap karakteristik lokal atau global.
renxwise

1
Kesulitan setinggi ini berarti Anda menggunakan "kernel" yang terlalu besar, dan secara efektif hanya menggunakan jarak. Ini kemudian cenderung merosot ke MDS perkiraan dan sangat mahal. Gunakan MDS saja. SNE / tSNE benar-benar harus digunakan dengan kebingungan kecil , dan lingkungan setempat.
Erich Schubert

3
Persis. Ketika kebingungan cukup besar, tSNE memang mendekati MDS, yang menggambarkan bahwa tSNE juga dapat menangkap struktur global. Dengan demikian, pernyataan bahwa tSNE hanya dapat menangkap struktur lokal tidak benar. Berbeda dari MDS, tSNE dapat menyeimbangkan antara struktur lokal dan global melalui pemilihan kebingungan. Jelas, pemilihan kebingungan tergantung pada dataset.
renxwise

Apakah ada aturan praktis untuk memilih kebingungan yang masuk akal?
Catbuilts

5

Berdasarkan bukti matematika yang kami miliki, metode ini secara teknis dapat menjaga jarak! mengapa Anda semua mengabaikan fitur ini! t -SNE mengubah jarak Euclidean dimensi tinggi antara sampel menjadi probabilitas bersyarat yang mewakili kesamaan. Saya telah mencoba t -SNE dengan lebih dari 11.000 sampel (dalam konteks genomik) secara paralel dengan berbagai algoritma pengelompokan konsensus termasuk pengelompokan spektral, Afinitas dan yang terpenting dengan pengelompokan GMM (yang merupakan algoritma pengelompokan berbasis kepadatan!). Sebagai hasilnya, saya menemukan hasil yang sangat sesuai antara dua pendekatan ( t-SNE vs. algoritma pengelompokan konsensus). Saya percaya mengintegrasikan t-SNE dengan algoritma clustering konsensus dapat memberikan bukti terbaik dari struktur data lokal dan global yang ada.


Apakah ada parameter yang akan mempengaruhi kemungkinan t-SNE menjaga jarak?
Keith Hughitt

Itu bukan algoritma pengelompokan konsensus. Konsensus pengelompokan adalah jenis pembelajaran ensembl yang mengumpulkan hasil pengulangan algoritma pengelompokan dengan beberapa variasi dalam parameter atau data input, untuk mendapatkan hasil pengelompokan akhir. Anda dapat menggunakan pendekatan pengelompokan konsensus dengan pengelompokan spektral atau GMM atau memang algoritma pengelompokan apa pun, tetapi poin saya dalam terminologi Anda sedikit berbeda, itu saja :)
Christopher John

1

Anda dapat mencoba algoritma pengelompokan DBSCAN. Juga, kebingungan tsne harus kira-kira seukuran dengan kelompok terkecil yang diharapkan.


0

Secara pribadi, saya pernah mengalami ini sekali, tetapi tidak dengan t-SNE atau PCA. Data asli saya dalam ruang 15 dimensi. Menggunakan UMAP untuk menguranginya menjadi embeddings 2D dan 3D, saya mendapat 2 cluster yang dapat dipisahkan secara visual dan sempurna pada plot 2D dan 3D. Terlalu bagus untuk menjadi kenyataan. Tetapi ketika saya "melihat" pada data asli dari diagram kegigihan, saya menyadari bahwa ada lebih banyak kluster "signifikan", bukan hanya 2.

Pengelompokan pada output dari teknik reduksi dimensi harus dilakukan dengan sangat hati-hati, jika tidak interpretasi dapat sangat menyesatkan atau salah karena pengurangan dimensi pasti akan mengakibatkan kehilangan fitur (mungkin fitur yang berisik atau benar, tetapi fitur yang priori, kami tidak tidak tahu yang mana). Menurut pendapat saya, Anda dapat mempercayai / menafsirkan cluster, jika:

  • Cluster dalam data yang diproyeksikan sesuai / mengkonfirmasi ke beberapa klasifikasi mendefinisikan apriori (pikirkan dataset MNIST, di mana cluster data yang diproyeksikan sangat cocok dengan klasifikasi digit), dan / atau,

  • Anda dapat mengonfirmasi keberadaan kluster ini dalam data asli menggunakan metode lain, seperti diagram kegigihan. Hanya menghitung jumlah komponen yang terhubung dapat dilakukan dalam jumlah waktu yang cukup masuk akal.


Mengapa (apakah) Anda lebih percaya "diagram kegigihan" lebih dari UMAP? Saya tidak berpikir bahwa melihat diagram kegigihan dapat digambarkan sebagai "melihat data asli" ...
amoeba mengatakan Reinstate Monica

Anda benar. Diagram kegigihan hanya menunjukkan beberapa karakteristik data asli, paling sering, komponen yang terhubung, lubang 1 dimensi, dan jauh lebih jarang, lubang 2 dimensi atau lebih karena perhitungan yang mahal. Jadi saya seharusnya mengatakan bahwa saya hanya bisa sebagian "melihat" pada data asli dengan melihat diagram kegigihan yang sesuai. Tapi saya bisa mempercayai apa yang saya amati dari diagram kegigihan ini karena langsung dibangun dari data asli.
SiXUlm

Sebaliknya, dengan menggunakan UMAP atau teknik pengurangan dimensi lainnya, kami hanya bekerja dengan versi yang diproyeksikan / dimodifikasi dari data asli. Seperti yang ditunjukkan oleh jawaban yang paling banyak dipilih, pengelompokan mungkin berbeda untuk pilihan parameter yang berbeda.
SiXUlm
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.