यह एक आकर्षक समस्या है! दो चीजें इसे विशेष रूप से चुनौतीपूर्ण बनाती हैं:
- हमें दो बिंदु सेट की तुलना कैसे करनी चाहिए? मशीन लर्निंग में शास्त्रीय समस्याओं की एक निश्चित संख्या के गुण होते हैं, और ये विशेषताएँ विनिमेय नहीं होती हैं: उदाहरण के लिए, मेरे पास अलग-अलग व्यक्तियों के गुण
age
और height
(सेंटीमीटर में) डेटा हो सकता है । प्रत्येक नमूने में प्रत्येक के लिए एक प्रविष्टि है, और निश्चित (age, height) = (22, 180)
रूप से समान नहीं है (age, height) = (180, 22)
। न तो आपकी समस्या में सच है। एक बिंदु सेट में 3 और 10 बिंदु होते हैं, और जिस क्रम में हम बिंदुओं में प्रवेश करते हैं, उसे दो बिंदु सेटों की तुलना करते समय फर्क नहीं करना चाहिए।
- हम एक भविष्यवाणी कैसे करते हैं? मान लीजिए कि हमने अपने प्रशिक्षण सेट से पॉइंट सेट लेने का एक तरीका खोज लिया है जो आपके पॉइंट सेट के समान है। हम इस समस्या का सामना करते हैं कि हमारी भविष्यवाणी आपकी तस्वीर के 7 बिंदुओं में से एक होनी चाहिए; लेकिन इनमें से कोई भी बिंदु समान बिंदु सेट में शामिल नहीं हो सकता है।
मुझे एक एल्गोरिथ्म को रेखांकित करने दो जो दोनों चुनौतियों से निपटता है। भविष्यवाणी सटीकता बहुत अच्छी नहीं है; लेकिन हो सकता है कि आपको एक रास्ता दिखाई दे कि इसमें कैसे सुधार किया जा सकता है। और कम से कम यह कुछ भविष्यवाणी करता है , है ना?
1. नमूने का अनुकरण
एल्गोरिथ्म का परीक्षण करने में सक्षम होने के लिए, मैंने ऐसे कार्य लिखे जो नमूने और लेबल उत्पन्न करते हैं।
नमूने उत्पन्न करना:
प्रत्येक नमूने में 3 और 10 अंक होते हैं। अंकों की संख्या यादृच्छिक है, एक समान वितरण से तैयार की गई है। प्रत्येक बिंदु रूप का है (x_coordinate, y_coordinate)
। निर्देशांक फिर से यादृच्छिक हैं, एक सामान्य वितरण से खींचा गया है।
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)])
जनरेटिंग लेबल: एक खिलौना उदाहरण के रूप में, मान लेते हैं कि एक बिंदु चुनने का नियम है: हमेशा उस बिंदु को चुनें जो सबसे नज़दीकी हो (0, 0)
, जहाँ 'निकटतम' को यूक्लिडियन मानदंड के रूप में समझा जाना चाहिए।
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])
अब हम अपनी ट्रेन और परीक्षण सेट बना सकते हैं:
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. हॉसडॉर्फ दूरी के माध्यम से तुलना बिंदु सेट
आइए हम पहली समस्या से निपटें: हमें विभिन्न बिंदुओं की तुलना कैसे करनी चाहिए? पॉइंट सेट में अंकों की संख्या अलग-अलग होती है। यह भी याद रखें कि जिस क्रम में हम अंक लिखते हैं, उससे कोई फर्क नहीं पड़ता: बिंदु सेट की [(0,0), (1,1), (2,2)]
तुलना बिंदु बिंदु की तुलना के समान परिणाम प्राप्त करना चाहिए [(2,2), (0,0), (1,1)]
। मेरा दृष्टिकोण उनके होडॉर्फ दूरी के माध्यम से बिंदु सेट की तुलना करना है :
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. k- निकटतम पड़ोसियों और औसत के माध्यम से भविष्यवाणी करना
अब हमारे पास बिंदु सेट के बीच की दूरी की धारणा है। यह k- निकटतम पड़ोसियों के वर्गीकरण का उपयोग करना संभव बनाता है: एक परीक्षण बिंदु सेट को देखते हुए, हम k
अपने प्रशिक्षण नमूने में बिंदु सेट पाते हैं जो परीक्षण बिंदु सेट के सापेक्ष सबसे छोटा हॉसडॉर्फ दूरी रखते हैं, और उनके लेबल प्राप्त करते हैं। अब दूसरी समस्या आती है: हम इन k
बिंदुओं को परीक्षण बिंदु सेट के लिए एक भविष्यवाणी में कैसे बदल देते हैं ? मैंने सबसे सरल दृष्टिकोण लिया: लेबल को औसत करें और परीक्षण बिंदु सेट में उस बिंदु की भविष्यवाणी करें जो औसत से निकटतम है।
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. परीक्षण
हमारे एल्गोरिथ्म के प्रदर्शन का परीक्षण करने के लिए सब कुछ है।
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])
दिए गए निर्णय समारोह के लिए और num_neighbors = 70
, हम 84% की एक भविष्यवाणी सटीकता प्राप्त करते हैं। यह बहुत अच्छा नहीं है, और यह निश्चित रूप से हमारे निर्णय समारोह के लिए विशिष्ट है, जो भविष्यवाणी करना काफी आसान लगता है।
इसे देखने के लिए, एक अलग निर्णय फ़ंक्शन को परिभाषित करें:
decision_function_maxaverage(sample):
avgs = (sample[:, 0] + sample[:, 1]) / 2
return sample[norms.argmin()]
इस फ़ंक्शन का उपयोग करके dec_fun = decision_function_maxaverage
भविष्यवाणी सटीकता को 45% तक नीचे लाया जाता है। इससे पता चलता है कि आपके लेबल बनाने वाले निर्णय नियमों के बारे में सोचना कितना महत्वपूर्ण है। यदि आपके पास एक विचार है कि लोग कुछ बिंदुओं का चयन क्यों करते हैं, तो यह आपको सबसे अच्छा एल्गोरिथ्म खोजने में मदद करेगा।
इस एल्गोरिथ्म को बेहतर बनाने के कुछ तरीके: (1) हॉसडॉर्फ दूरी के बजाय एक अलग दूरी फ़ंक्शन का उपयोग करें, (2) के-निकटतम पड़ोसियों की तुलना में अधिक परिष्कृत कुछ का उपयोग करें, (3) सुधार कैसे चयनित प्रशिक्षण लेबल एक भविष्यवाणी में बदल जाते हैं।