Ini adalah masalah yang menarik! Dua hal yang membuatnya sangat menantang:
- Bagaimana kita membandingkan dua set poin? Masalah klasik dalam Pembelajaran Mesin memiliki sejumlah atribut tetap, dan atribut ini tidak dapat dipertukarkan: Misalnya, saya mungkin memiliki data tentang orang yang berbeda dengan atribut
agedan height(dalam sentimeter). Setiap sampel memiliki satu entri untuk masing-masing, dan tentu saja (age, height) = (22, 180)tidak sama dengan (age, height) = (180, 22). Tidak ada yang benar dalam masalah Anda. Satu set poin memiliki antara 3 dan 10 poin, dan urutan kita memasukkan poin tidak akan membuat perbedaan ketika membandingkan dua set poin.
- Bagaimana cara kita membuat prediksi? Katakanlah kami telah menemukan cara untuk memilih set poin dari set pelatihan kami yang mirip dengan set poin Anda di atas. Kami menghadapi masalah bahwa prediksi kami harus menjadi salah satu dari 7 poin dalam gambar Anda; tetapi tidak satu pun dari poin ini yang mungkin terkandung dalam set poin yang sama.
Biarkan saya menguraikan algoritma yang menangani kedua tantangan. Akurasi prediksi tidak terlalu baik; tetapi mungkin Anda melihat cara bagaimana hal itu dapat ditingkatkan. Dan setidaknya itu memprediksi sesuatu , bukan?
1. Simulasi sampel
Untuk dapat menguji algoritme, saya menulis fungsi yang menghasilkan sampel dan label.
Menghasilkan sampel:
Setiap sampel berisi antara 3 dan 10 poin. Jumlah poin acak, diambil dari distribusi yang seragam. Setiap titik berbentuk (x_coordinate, y_coordinate). Koordinat kembali acak, diambil dari distribusi normal.
import numpy as np
from random import randint
def create_samples(number_samples, min_points, max_points):
def create_single_sample(min_points, max_points):
n = randint(min_points, max_points)
return np.array([np.random.normal(size=2) for _ in range(n)])
return np.array([create_single_sample(min_points, max_points) for _ in range(number_samples)])
Membuat label: Sebagai contoh mainan, mari kita asumsikan bahwa aturan untuk memilih titik adalah: Selalu pilih titik yang paling dekat dengan (0, 0), di mana 'paling dekat' harus dipahami dalam hal norma Euclidean.
def decision_function_minnorm(sample):
norms = np.apply_along_axis(np.linalg.norm, axis=1, arr=sample)
return sample[norms.argmin()]
def create_labels(samples, decision_function):
return np.array([decision_function(sample) for sample in samples])
Kami sekarang dapat membuat set kereta dan tes kami:
n_train, n_test = 1000, 100
dec_fun = decision_function_minnorm
X_train = create_samples(number_samples=n_train, min_points=3, max_points=10)
X_test = create_samples(number_samples=n_test, min_points=3, max_points=10)
y_train = create_labels(X_train, dec_fun)
y_test = create_labels(X_test, dec_fun)
2. Membandingkan set titik melalui jarak Hausdorff
Mari kita atasi masalah pertama: Bagaimana kita harus membandingkan set poin yang berbeda? Jumlah poin dalam set poin berbeda. Juga ingat bahwa urutan penulisan poin tidak menjadi masalah: Membandingkan dengan set poin [(0,0), (1,1), (2,2)]harus menghasilkan hasil yang sama dengan membandingkan dengan set poin [(2,2), (0,0), (1,1)]. Pendekatan saya adalah membandingkan set poin melalui jarak Hausdorff mereka :
def hausdorff(A, B):
def dist_point_to_set(x, A):
return min(np.linalg.norm(x - a) for a in A)
def dist_set_to_set(A, B):
return max(dist_point_set(a, B) for a in A)
return max(dist_set_to_set(A, B), dist_set_to_set(B, A))
3. Memprediksi melalui k-tetangga terdekat dan rata-rata
Kami sekarang memiliki gagasan jarak antara set titik. Hal ini memungkinkan untuk menggunakan klasifikasi tetangga k-terdekat: Diberikan set titik uji, kami menemukan kset titik dalam sampel pelatihan kami yang memiliki jarak Hausdorff terkecil relatif terhadap set titik uji, dan mendapatkan label mereka. Sekarang tiba masalah kedua: Bagaimana kita mengubah klabel ini menjadi prediksi untuk set titik uji? Saya mengambil pendekatan paling sederhana: rata-rata label dan memprediksi titik di set titik uji yang paling dekat dengan rata-rata.
def predict(x, num_neighbors):
# Find num_neighbors closest points in X_train.
distances_to_train = np.array([hausdorff(x, x_train) for x_train in X_train])
neighbors_idx = np.argpartition(distances_to_train, -num_neighbors)[-num_neighbors:]
# Get labels of the neighbors and calculate the average.
targets_neighbors = y_train[neighbors_idx]
targets_mean = sum(targets_neighbors) / num_neighbors
# Find point in x that is closest to targets_mean and use it as prediction.
distances_to_mean = np.array([np.linalg.norm(p - targets_mean) for p in x])
closest_point = x[distances_to_mean.argmin()]
return closest_point
4. Pengujian
Semuanya tersedia untuk menguji kinerja algoritma kami.
num_neighbors = 70
successes = 0
for i, x in enumerate(X_test):
print('%d/%d' % (i+1, n_test))
prediction = predict(x, num_neighbors)
successes += np.array_equal(prediction, y_test[i])
Untuk fungsi keputusan yang diberikan dan num_neighbors = 70, kami mendapatkan akurasi prediksi 84%. Ini tidak terlalu bagus, dan tentu saja spesifik untuk fungsi keputusan kami, yang tampaknya cukup mudah diprediksi.
Untuk melihatnya, tentukan fungsi keputusan yang berbeda:
decision_function_maxaverage(sample):
avgs = (sample[:, 0] + sample[:, 1]) / 2
return sample[norms.argmin()]
Menggunakan fungsi ini melalui dec_fun = decision_function_maxaveragemenurunkan akurasi prediksi hingga 45%. Ini menunjukkan betapa pentingnya memikirkan aturan keputusan yang menghasilkan label Anda. Jika Anda memiliki ide mengapa orang memilih titik-titik tertentu, ini akan membantu Anda menemukan algoritma terbaik.
Beberapa cara untuk meningkatkan algoritme ini: (1) Gunakan fungsi jarak yang berbeda daripada jarak Hausdorff, (2) gunakan sesuatu yang lebih canggih daripada k-tetangga terdekat, (3) tingkatkan cara label pelatihan yang dipilih diubah menjadi prediksi.