ഒരു ഡീപ് ന്യൂറൽ നെറ്റ്വർക്ക് പരിശീലിപ്പിക്കുന്നത് അടിസ്ഥാനപരമായി ഒരു കംപ്രഷൻ ടാസ്ക് ആണ്. ഞങ്ങൾക്ക് ആവശ്യമുള്ളത് ഞങ്ങളുടെ പരിശീലന ഡാറ്റ ഡിസ്ട്രിബ്യൂഷനെ ഒരു കൂട്ടം മെട്രിക്സുകളാൽ പാരാമീറ്ററൈസ് ചെയ്ത ഒരു ഫംഗ്ഷനായി പ്രതിനിധീകരിക്കുക എന്നതാണ്. ഡിസ്ട്രിബ്യൂഷൻ കൂടുതൽ സങ്കീർണ്ണമാകുമ്പോൾ, കൂടുതൽ പാരാമീറ്ററുകൾ ആവശ്യമാണ്. മുഴുവൻ ഡിസ്ട്രിബ്യൂഷൻ അപ്രോക്സിമേറ്റ് ചെയ്യുന്നതിന്റെ യുക്തി എന്നത്, ഇൻഫറൻസ് സമയത്ത് ഏതെങ്കിലും സാധുവായ പോയിന്റ് ഫോർവേഡ് ചെയ്യാൻ ഒരേ മോഡൽ, ഒരേ ഭാരങ്ങൾ ഉപയോഗിക്കാൻ കഴിയും എന്നതാണ്. എന്നാൽ നമ്മുടെ മോഡൽ ഇൻഫറൻസ് സമയത്ത് തന്നെ പരിശീലിപ്പിച്ചാൽ എന്തുണ്ടാകും? അപ്പോൾ, ഫോർവേഡ് ചെയ്യുമ്പോൾ, ചുറ്റുമുള്ള ലോക്കൽ ഡിസ്ട്രിബ്യൂഷൻ മാത്രമേ മോഡൽ ചെയ്യേണ്ടതുള്ളൂ. ലോക്കൽ പ്രദേശത്തിന് മുഴുവൻ പരിശീലന സെറ്റിനേക്കാൾ കുറഞ്ഞ ഡൈമെൻഷണാലിറ്റി ഉണ്ടായിരിക്കണം, അതിനാൽ വളരെ ലളിതമായ ഒരു മോഡൽ മതിയാകും!
ലോക്കൽ അപ്രോക്സിമേഷൻ അല്ലെങ്കിൽ ലോക്കൽ റിഗ്രഷൻ എന്ന ആശയമാണ് ഇത്. നമുക്ക് ഒരു ലളിതമായ റിഗ്രഷൻ ടാസ്ക് പരിഗണിക്കാം.
ടാസ്ക്
നമുക്ക് താഴെയുള്ള ഡാറ്റയുടെ സാമ്പിളുകൾ നൽകിയിട്ടുണ്ട്:
ഇവിടെ
പ്ലോട്ടിംഗ് കോഡ്
import numpy as np
import plotly.graph_objects as go
# ഡാറ്റ ജനറേറ്റ് ചെയ്യുക
np.random.seed(42)
n_points = 100
X = np.random.uniform(0, 1, n_points)
epsilon = np.random.normal(0, 1 / 3, n_points)
Y = np.sin(4 * X) + epsilon
# യഥാർത്ഥ ഫംഗ്ഷൻ
x_true = np.linspace(0, 1, 500)
y_true = np.sin(4 * x_true)
# പ്ലോട്ട് സൃഷ്ടിക്കുക
fig = go.Figure()
# ശബ്ദമുള്ള ഡാറ്റയ്ക്കായി സ്കാറ്റർ പോയിന്റുകൾ ചേർക്കുക
fig.add_trace(
go.Scatter(
x=X,
y=Y,
mode="markers",
name="Noisy Data",
marker=dict(color="gray"),
)
)
# യഥാർത്ഥ ഫംഗ്ഷൻ ചേർക്കുക
fig.add_trace(
go.Scatter(
x=x_true,
y=y_true,
mode="lines",
name="True Function",
line=dict(color="red"),
)
)
# ലേഔട്ട് അപ്ഡേറ്റ് ചെയ്യുക
fig.update_layout(
title="Data",
xaxis_title="X",
yaxis_title="Y",
template="plotly_dark",
height=400,
width=730,
)
# പ്ലോട്ട് ഒരു HTML ഫയലായി സേവ് ചെയ്യുക
filename = "local_approximation_data.html"
fig.write_html(filename)
print(f"Saved plot to {filename}")
# പ്ലോട്ട് കാണിക്കുക
fig.show()
ഡാറ്റാസെറ്റ് എന്ന് സൂചിപ്പിക്കുന്നു, അതിൽ എന്ന സാമ്പിളുകൾ അടങ്ങിയിരിക്കുന്നു.
ഡാറ്റയിലൂടെ ഒരു യുക്തിസഹമായ വക്രം ഫിറ്റ് ചെയ്യുക എന്നതാണ് നമ്മുടെ ടാസ്ക്, അത് യഥാർത്ഥ ഫംഗ്ഷനെ ഏകദേശം പൊരുത്തപ്പെടുന്നു. ഈ വക്രത്തെ എന്ന് സൂചിപ്പിക്കാം.
കെ ന്യൂറസ്റ്റ് നെയ്ബറുകൾ
ഒരു നൽകിയാൽ, എന്നതിനോട് ഏറ്റവും അടുത്തുള്ള മൂല്യങ്ങൾ എടുത്ത് അവയുടെ മൂല്യങ്ങളുടെ ശരാശരി കണക്കാക്കുന്നതാണ് ഒരു സമീപനം. അതായത്,
ഇവിടെ എന്നത് എന്നതിനോട് ഏറ്റവും അടുത്തുള്ള പോയിന്റുകളെ സൂചിപ്പിക്കുന്നു.
പ്ലോട്ടിംഗ് കോഡ്
import plotly.graph_objects as go
import numpy as np
# ഡാറ്റ ജനറേറ്റ് ചെയ്യുക
np.random.seed(42)
n_points = 100
X = np.random.uniform(0, 1, n_points)
epsilon = np.random.normal(0, 1 / 3, n_points)
Y = np.sin(4 * X) + epsilon
# യഥാർത്ഥ ഫംഗ്ഷൻ
x_true = np.linspace(0, 1, 500)
y_true = np.sin(4 * x_true)
# k-NN for a range of k
x_curve = np.arange(0, 1, 0.01)
k_range = range(1, 21)
y_curves_knn = {}
for k in k_range:
y_curve = []
for x in x_curve:
distances = np.square(X - x)
nearest_indices = np.argsort(distances)[:k]
y_curve.append(np.mean(Y[nearest_indices]))
y_curves_knn[k] = y_curve
# Plotly ഫിഗർ സൃഷ്ടിക്കുക
fig = go.Figure()
# സ്റ്റാറ്റിക് ട്രേസുകൾ ചേർക്കുക
fig.add_trace(
go.Scatter(x=X, y=Y, mode="markers", name="Noisy Data", marker=dict(color="gray"))
)
fig.add_trace(
go.Scatter(
x=x_true, y=y_true, mode="lines", name="True Function", line=dict(color="red"))
)
# ആദ്യത്തെ k-NN കർവ് ചേർക്കുക (k=13, സ്ലൈഡറിന്റെ ഡിഫോൾട്ട് സ്ഥാനം)
initial_k = 13
fig.add_trace(
go.Scatter(
x=x_curve,
y=y_curves_knn[initial_k],
mode="lines",
name="k-NN Curve",
line=dict(color="yellow"),
)
)
# സ്ലൈഡർ സ്റ്റെപ്പുകൾ നിർവ്വചിക്കുക
steps = []
for k in k_range:
step = dict(
method="update",
args=[
{"y": [Y, y_true, y_curves_knn[k]]}, # ട്രേസുകളുടെ y-ഡാറ്റ അപ്ഡേറ്റ് ചെയ്യുക
{
"title": f"Interactive k-NN Curve with Slider for k = {k}"
}, # ടൈറ്റിൽ ഡൈനാമിക് ആയി അപ്ഡേറ്റ് ചെയ്യുക
],
label=f"{k}",
)
steps.append(step)
# സ്ലൈഡർ ലേഔട്ടിലേക്ക് ചേർക്കുക
sliders = [
dict(
active=initial_k - 1,
currentvalue={"prefix": "k = "},
pad={"t": 50},
steps=steps,
)
]
fig.update_layout(
sliders=sliders,
title=f"Interactive k-NN Curve with Slider for k = {initial_k}",
xaxis_title="X",
yaxis_title="Y",
template="plotly_dark",
height=400,
width=730,
)
# പ്ലോട്ട് കാണിക്കുകയും സേവ് ചെയ്യുകയും ചെയ്യുക
fig.show()
html_path = "./knn_slider.html"
fig.write_html(html_path)
print(f"Saved interactive plot to {html_path}")
സ്ലൈഡർ ഉപയോഗിച്ച് നിങ്ങൾക്ക് കാണാൻ കഴിയും, വലുതാകുന്തോറും കർവ് മിനുസമാർന്നതാകുന്നു, എന്നാൽ കുറഞ്ഞ കർവുകൾ ചില ശബ്ദങ്ങളെ ഉൾക്കൊള്ളുന്നു. അങ്ങേയറ്റത്തെ സ്ഥിതികളിൽ, ട്രെയിനിംഗ് ഡാറ്റയെ കൃത്യമായി പിന്തുടരുന്നു, ഒരു പരന്ന ആഗോള ശരാശരി നൽകുന്നു.
നദരായ–വാട്സൺ കെർണൽ റിഗ്രഷൻ
ഡാറ്റയുടെ ഉപഗണത്തെ പോയിന്റുകളായി പരിമിതപ്പെടുത്തുന്നതിന് പകരം, സെറ്റിലെ എല്ലാ പോയിന്റുകളും പരിഗണിക്കാം, എന്നാൽ ഓരോ പോയിന്റിന്റെയും സംഭാവന എന്നതിലേക്കുള്ള അതിന്റെ സാമീപ്യത്തെ അടിസ്ഥാനമാക്കി ഭാരം നൽകുക. മോഡൽ പരിഗണിക്കുക
ഇവിടെ ഒരു കെർണൽ ആണ്, ഇത് ഞങ്ങൾ ഒരു സാമീപ്യ മെട്രിക് ആയി ഉപയോഗിക്കും.
ഈ ഫംഗ്ഷൻ എന്ന പാരാമീറ്റർ ഉപയോഗിച്ച് പാരാമീറ്ററൈസ് ചെയ്യപ്പെടുന്നു, ഇത് ബാൻഡ്വിഡ്ത്ത് എന്നറിയപ്പെടുന്നു, ഇത് ന്റെ ഔട്ട്പുട്ടിൽ ഡാറ്റയിലെ മൂല്യങ്ങളുടെ എന്ത് ശ്രേണി പങ്കുവഹിക്കുന്നുവെന്ന് നിയന്ത്രിക്കുന്നു. ഈ ഫംഗ്ഷനുകൾ പ്ലോട്ട് ചെയ്താൽ ഇത് വ്യക്തമാകും.
കെർണൽ ഫംഗ്ഷനുകൾ
ചുവടെ പ്ലോട്ട് ചെയ്തിരിക്കുന്നത്
ഇവിടെ എന്നത് ന്റെ സപ്പോർട്ടിൽ ആയി ഇന്റഗ്രേറ്റ് ചെയ്യുന്നത് നിലനിർത്തുന്നു.
പ്ലോട്ടിംഗ് കോഡ്
import numpy as np
import plotly.graph_objects as go
from scipy.integrate import quad
# കെർണൽ ഫംഗ്ഷനുകൾ നിർവ്വചിക്കുക
def epanechnikov_kernel(u):
return np.maximum(0, 0.75 * (1 - u**2))
def tricube_kernel(u):
return np.maximum(0, (1 - np.abs(u) ** 3) ** 3)
def gaussian_kernel(u):
return np.exp(-0.5 * u**2) / np.sqrt(2 * np.pi)
def renormalized_kernel(kernel_func, u_range, bandwidth):
def kernel_with_lambda(u):
scaled_u = u / bandwidth
normalization_factor, _ = quad(lambda v: kernel_func(v / bandwidth), *u_range)
return kernel_func(scaled_u) / normalization_factor
return kernel_with_lambda
# കെർണൽ ഫംഗ്ഷൻ പ്ലോട്ട് ജനറേറ്റർ
def generate_kernel_plot(
kernel_name, kernel_func, x_range, u_range, lambda_values, y_range
):
fig = go.Figure()
# പ്രാരംഭ ലാംഡ
initial_lambda = lambda_values[len(lambda_values) // 2]
# പ്രാരംഭ കെർണൽ കർവ് ജനറേറ്റ് ചെയ്യുക
x = np.linspace(*x_range, 500)
kernel_with_lambda = renormalized_kernel(kernel_func, u_range, initial_lambda)
y = kernel_with_lambda(x)
fig.add_trace(
go.Scatter(
x=x,
y=y,
mode="lines",
name=f"{kernel_name} കെർണൽ (λ={initial_lambda:.2f})",
line=dict(color="green"),
)
)
# സ്ലൈഡറിനായി ഫ്രെയിമുകൾ സൃഷ്ടിക്കുക
frames = []
for bandwidth in lambda_values:
kernel_with_lambda = renormalized_kernel(kernel_func, u_range, bandwidth)
y = kernel_with_lambda(x)
frames.append(
go.Frame(
data=[
go.Scatter(
x=x,
y=y,
mode="lines",
name=f"{kernel_name} കെർണൽ (λ={bandwidth:.2f})",
line=dict(color="green"),
)
],
name=f"{bandwidth:.2f}",
)
)
# ഫ്രെയിമുകൾ ഫിഗറിലേക്ക് ചേർക്കുക
fig.frames = frames
# സ്ലൈഡർ ചേർക്കുക
sliders = [
{
"active": len(lambda_values) // 2,
"currentvalue": {"prefix": "ബാൻഡ്വിഡ്ത് λ: "},
"steps": [
{
"args": [
[f"{bandwidth:.2f}"],
{"frame": {"duration": 0, "redraw": True}, "mode": "immediate"},
],
"label": f"{bandwidth:.2f}",
"method": "animate",
}
for bandwidth in lambda_values
],
}
]
# ലേഔട്ട് അപ്ഡേറ്റ് ചെയ്യുക
fig.update_layout(
title=f"{kernel_name} കെർണൽ ഫംഗ്ഷൻ",
xaxis_title="u",
yaxis_title="K(u)",
yaxis_range=y_range,
template="plotly_dark",
sliders=sliders,
height=400, # മുമ്പത്തെ വലുപ്പത്തിന് അനുയോജ്യമാക്കി
width=730, # മുമ്പത്തെ വലുപ്പത്തിന് അനുയോജ്യമാക്കി
updatemenus=[
{
"direction": "left",
"pad": {"r": 10, "t": 87},
"showactive": False,
"type": "buttons",
"x": 0.1,
"xanchor": "right",
"y": 0,
"yanchor": "top",
}
],
)
return fig
# കെർണൽ ഫംഗ്ഷനുകൾ
kernels = {
"Epanechnikov": epanechnikov_kernel,
"Tricube": tricube_kernel,
"Gaussian": gaussian_kernel,
}
# പാരാമീറ്ററുകൾ
x_range_plot = (-3, 3) # പ്ലോട്ടിനായുള്ള u മൂല്യങ്ങളുടെ ശ്രേണി
u_range_integration = (-3, 3) # നോർമലൈസേഷനായുള്ള ശ്രേണി
lambda_values = np.linspace(0.01, 2, 20) # 0.01 മുതൽ 2 വരെ ലീനിയർ ലാംഡ മൂല്യങ്ങൾ
y_range_plot = (0, 1.5) # നോർമലൈസ്ഡ് ഫംഗ്ഷനുകൾക്ക് അനുയോജ്യമാക്കി
# ഓരോ കെർണലിനും പ്ലോട്ടുകൾ ജനറേറ്റ് ചെയ്യുകയും പ്രദർശിപ്പിക്കുകയും ചെയ്യുക
for kernel_name, kernel_func in kernels.items():
fig = generate_kernel_plot(
kernel_name,
kernel_func,
x_range_plot,
u_range_integration,
lambda_values,
y_range_plot,
)
# ഫിഗർ ഒരു HTML ഫയലായി സേവ് ചെയ്യുക
filename = f"{kernel_name}_dynamic_normalization_kernel_function.html"
fig.write_html(filename, auto_play=False)
print(f"Saved {kernel_name} kernel plot to {filename}")
# ഫിഗർ പ്രദർശിപ്പിക്കുക
fig.show()
ഫലങ്ങൾ
ഇപ്പോൾ ഓരോ കെർണൽ ഫംഗ്ഷനുകൾക്കും ഫലങ്ങൾ പ്ലോട്ട് ചെയ്യുന്നു. ഓരോ പ്ലോട്ടിലും ഒരു സ്ലൈഡർ ഉണ്ട്, ഇത് ഔട്ട്പുട്ട് ലൈവ് നിയന്ത്രിക്കുന്നു.
പ്ലോട്ടിംഗ് കോഡ്
import numpy as np
import plotly.graph_objects as go
# കെർണൽ ഫംഗ്ഷനുകൾ നിർവചിക്കുക
def epanechnikov_kernel(u):
return np.maximum(0, 0.75 * (1 - u**2))
def tricube_kernel(u):
return np.maximum(0, (1 - np.abs(u) ** 3) ** 3)
def gaussian_kernel(u):
return np.exp(-0.5 * u**2) / np.sqrt(2 * np.pi)
# കെർണൽ റിഗ്രഷൻ ഫംഗ്ഷൻ
def kernel_regression(X, Y, x_curve, kernel_func, bandwidth):
y_curve = []
for x in x_curve:
distances = np.abs(X - x) / bandwidth
weights = kernel_func(distances)
weighted_average = (
np.sum(weights * Y) / np.sum(weights) if np.sum(weights) > 0 else 0
)
y_curve.append(weighted_average)
return y_curve
# ഡാറ്റ ജനറേറ്റ് ചെയ്യുക
np.random.seed(42)
n_points = 100
X = np.random.uniform(0, 1, n_points)
epsilon = np.random.normal(0, 1 / 3, n_points)
Y = np.sin(4 * X) + epsilon
# യഥാർത്ഥ വക്രം
x_true = np.linspace(0, 1, 500)
y_true = np.sin(4 * x_true)
# കെർണൽ എസ്റ്റിമേഷനുള്ള പോയിന്റുകൾ
x_curve = x_true
# കെർണൽ ഫംഗ്ഷനുകൾ
kernels = {
"Epanechnikov": epanechnikov_kernel,
"Tricube": tricube_kernel,
"Gaussian": gaussian_kernel,
}
# സ്ലൈഡറിനായുള്ള ബാൻഡ്വിഡ്ത്ത് ശ്രേണി ലോഗ് സ്പേസിൽ
lambda_values = np.logspace(-2, 0, 20) # 0.01 മുതൽ 1 വരെ
# ഓരോ കെർണലിനും പ്രത്യേക പ്ലോട്ടുകൾ ജനറേറ്റ് ചെയ്യുക
for kernel_name, kernel_func in kernels.items():
fig = go.Figure()
# ശബ്ദമുള്ള ഡാറ്റയ്ക്കായി സ്കാറ്റർ പോയിന്റുകൾ ചേർക്കുക
fig.add_trace(
go.Scatter(
x=X, y=Y, mode="markers", name="Noisy Data", marker=dict(color="gray")
)
)
# യഥാർത്ഥ ഫംഗ്ഷൻ ചേർക്കുക
fig.add_trace(
go.Scatter(
x=x_true,
y=y_true,
mode="lines",
name="True Function",
line=dict(color="red"),
)
)
# പ്രാരംഭ കെർണൽ വക്രം ചേർക്കുക
initial_bandwidth = lambda_values[0]
y_curve = kernel_regression(X, Y, x_curve, kernel_func, initial_bandwidth)
fig.add_trace(
go.Scatter(
x=x_curve,
y=y_curve,
mode="lines",
name=f"Nadaraya-Watson ({kernel_name})",
line=dict(color="green"),
)
)
# സ്ലൈഡറിനായി ഫ്രെയിമുകൾ സൃഷ്ടിക്കുക
frames = []
for bandwidth in lambda_values:
y_curve = kernel_regression(X, Y, x_curve, kernel_func, bandwidth)
frames.append(
go.Frame(
data=[
go.Scatter(
x=X,
y=Y,
mode="markers",
name="Noisy Data",
marker=dict(color="gray"),
),
go.Scatter(
x=x_true,
y=y_true,
mode="lines",
name="True Function",
line=dict(color="red"),
),
go.Scatter(
x=x_curve,
y=y_curve,
mode="lines",
name=f"Nadaraya-Watson ({kernel_name})",
line=dict(color="green"),
),
],
name=f"{bandwidth:.2f}",
)
)
# ഫ്രെയിമുകൾ ഫിഗറിലേക്ക് ചേർക്കുക
fig.frames = frames
# സ്ലൈഡർ ചേർക്കുക
sliders = [
{
"active": 0,
"currentvalue": {"prefix": "Bandwidth λ: "},
"steps": [
{
"args": [
[f"{bandwidth:.2f}"],
{"frame": {"duration": 0, "redraw": True}, "mode": "immediate"},
],
"label": f"{bandwidth:.2f}",
"method": "animate",
}
for bandwidth in lambda_values
],
}
]
# ലേഔട്ട് അപ്ഡേറ്റ് ചെയ്യുക
fig.update_layout(
title=f"Nadaraya-Watson Kernel Regression ({kernel_name} Kernel)",
xaxis_title="X",
yaxis_title="Y",
template="plotly_dark",
sliders=sliders,
height=400,
width=730,
updatemenus=[
{
"buttons": [
{
"args": [
None,
{
"frame": {"duration": 500, "redraw": True},
"fromcurrent": True,
},
],
"label": "Play",
"method": "animate",
},
{
"args": [
[None],
{
"frame": {"duration": 0, "redraw": True},
"mode": "immediate",
},
],
"label": "Pause",
"method": "animate",
},
],
"direction": "left",
"pad": {"r": 10, "t": 87},
"showactive": False,
"type": "buttons",
"x": 0.1,
"xanchor": "right",
"y": 0,
"yanchor": "top",
}
],
)
# ഫിഗർ ഒരു HTML ഫയലിലേക്ക് സേവ് ചെയ്യുക
filename = f"{kernel_name}_kernel_regression.html"
fig.write_html(filename, auto_play=False)
print(f"Saved {kernel_name} kernel plot to {filename}")
# ഫിഗർ കാണിക്കുക
fig.show()
ഡാറ്റയുടെ ഒരു ലളിതമായ ഭാരം കൂടിയ ശരാശരി ഒരു സൈനസോയിഡ് നന്നായി മോഡൽ ചെയ്യാൻ കഴിയുന്നതായി നമ്മൾ കാണുന്നു.
ലോക്കൽ ലീനിയർ റിഗ്രഷൻ
നദരായ-വാട്സൺ കെർണൽ റിഗ്രഷനിൽ, കെർണൽ ഫംഗ്ഷൻ വഴി നിർവചിച്ചിരിക്കുന്ന ഒരു പരിസരത്തിൽ ഒരു ഭാരം കൂടിയ ശരാശരി എടുക്കുന്നു. ഇതിനൊരു സാധ്യമായ പ്രശ്നം എന്നത് ലോക്കൽ പരിസരങ്ങളിലെ മിനുസമാർന്ന ഇന്റർപോളേഷൻ ആണ്, കാരണം ആ പ്രദേശം യാതൊരു മോഡലിനെയും പിന്തുടരുന്നുവെന്ന് നാം യഥാർത്ഥത്തിൽ അനുമാനിക്കുന്നില്ല.
ഓരോ പ്രദേശവും ലോക്കലായി ലീനിയർ ആണെന്ന് നമ്മൾ അനുമാനിച്ചാൽ എന്തുണ്ടാകും? അപ്പോൾ, നമുക്ക് ലീസ്റ്റ് സ്ക്വയർ ഫിറ്റ് പരിഹരിക്കാനും സ്വതന്ത്രമായി ഇന്റർപോളേറ്റ് ചെയ്യാനും കഴിയും!
പ്രദേശം: $k$-NN
നമുക്ക് നമ്മുടെ പ്രാദേശിക പ്രദേശം നമ്മുടെ ഇൻപുട്ടിന്റെ അടുത്തുള്ള അയൽക്കാരായി നിർവചിക്കാം. എന്നും അതിനോടനുബന്ധിച്ച മൂല്യങ്ങളായും എടുക്കാം. ലീസ്റ്റ് സ്ക്വയർ ഫിറ്റ് കോഫിഫിഷ്യന്റുകൾ ഇവയാണ്:
പ്ലോട്ടിംഗ് കോഡ്
import plotly.graph_objects as go
import numpy as np
# ഡാറ്റ ജനറേറ്റ് ചെയ്യുക
np.random.seed(42)
n_points = 100
X = np.random.uniform(0, 1, n_points)
epsilon = np.random.normal(0, 1 / 3, n_points)
Y = np.sin(4 * X) + epsilon
# യഥാർത്ഥ ഫംഗ്ഷൻ
x_true = np.linspace(0, 1, 500)
y_true = np.sin(4 * x_true)
# k-NN ലോക്കൽ ലീനിയർ റിഗ്രഷൻ
def knn_linear_regression(X, Y, x_curve, k_range):
y_curves = {}
for k in k_range:
y_curve = []
for x in x_curve:
# k അടുത്തുള്ള അയൽക്കാരെ കണ്ടെത്തുക
distances = np.abs(X - x)
nearest_indices = np.argsort(distances)[:k]
# k അടുത്തുള്ള അയൽക്കാരെ തിരഞ്ഞെടുക്കുക
X_knn = X[nearest_indices]
Y_knn = Y[nearest_indices]
# k-നെയറസ്റ്റ് നെയ്ബറുകൾക്കായി ഡിസൈൻ മാട്രിക്സ് സൃഷ്ടിക്കുക
X_design = np.vstack((np.ones_like(X_knn), X_knn)).T
# ഓർഡിനറി ലീസ്റ്റ് സ്ക്വയർ ഉപയോഗിച്ച് ബീറ്റ കണ്ടെത്തുക
beta = np.linalg.pinv(X_design.T @ X_design) @ X_design.T @ Y_knn
# y-മൂല്യം പ്രവചിക്കുക
y_curve.append(beta[0] + beta[1] * x)
y_curves[k] = y_curve
return y_curves
# പൊതു വേരിയബിളുകൾ
x_curve = np.arange(0, 1, 0.01)
k_range = range(1, 21) # k യുടെ മൂല്യങ്ങൾ 1 മുതൽ 20 വരെ
initial_k = 10 # k യുടെ ഡിഫോൾട്ട് മൂല്യം
# k-NN ഉപയോഗിച്ച് LLR കണക്കാക്കുക
y_curves_knn = knn_linear_regression(X, Y, x_curve, k_range)
# പ്ലോട്ട്ലി ഫിഗർ സൃഷ്ടിക്കുക
fig = go.Figure()
# സ്റ്റാറ്റിക് ട്രേസുകൾ ചേർക്കുക
fig.add_trace(
go.Scatter(x=X, y=Y, mode="markers", name="Noisy Data", marker=dict(color="gray"))
)
fig.add_trace(
go.Scatter(
x=x_true, y=y_true, mode="lines", name="True Function", line=dict(color="red")
)
)
# ആദ്യത്തെ k-NN കർവ് (k=initial_k) ചേർക്കുക
fig.add_trace(
go.Scatter(
x=x_curve,
y=y_curves_knn[initial_k],
mode="lines",
name="k-NN Curve",
line=dict(color="yellow"),
)
)
# സ്ലൈഡർ സ്റ്റെപ്പുകൾ നിർവചിക്കുക
steps = []
for k in k_range:
step = dict(
method="update",
args=[
{"y": [Y, y_true, y_curves_knn[k]]}, # ട്രേസുകൾക്കായി y-ഡാറ്റ അപ്ഡേറ്റ് ചെയ്യുക
{
"title": f"k-NN Local Linear Regression Curve with k = {k}"
}, # ടൈറ്റിൽ ഡൈനാമിക്കായി അപ്ഡേറ്റ് ചെയ്യുക
],
label=f"{k}",
)
steps.append(step)
# സ്ലൈഡർ ലേഔട്ടിലേക്ക് ചേർക്കുക
sliders = [
dict(
active=k_range.index(initial_k), # initial_k യുടെ ഇൻഡെക്സ് ഉപയോഗിക്കുക
currentvalue={"prefix": "k = "},
pad={"t": 50},
steps=steps,
)
]
fig.update_layout(
sliders=sliders,
title=f"k-NN Local Linear Regression Curve with k = {initial_k}",
xaxis_title="X",
yaxis_title="Y",
template="plotly_dark",
height=400,
width=730,
)
# പ്ലോട്ട് കാണിക്കുക, സേവ് ചെയ്യുക
fig.show()
html_path = "./knn_slider_llr.html"
fig.write_html(html_path)
print(f"Saved interactive k-NN plot to {html_path}")
ചെറിയ മൂല്യങ്ങൾക്ക് ഔട്ട്പുട്ട് വളരെ പരുക്കനായിരിക്കുമെന്ന് നമുക്ക് കാണാം.
പ്രദേശം: കെർണൽ ഫംഗ്ഷൻ
ഒരുപക്ഷേ നാദരായ-വാട്സൺ കെർണലിൽ നിന്ന് ചില ആശയങ്ങൾ പുനരുപയോഗിക്കാം. പരിശീലന സെറ്റിലെ എല്ലാ പോയിന്റുകളും വ്യത്യസ്ത അളവിൽ പരിഗണിക്കാൻ ഞങ്ങൾ ആഗ്രഹിക്കുന്നു, ലോക്കൽ പ്രദേശത്ത് ഉയർന്ന ഭാരങ്ങളും പുറത്ത് കുറഞ്ഞ ഭാരങ്ങളും ഉപയോഗിച്ച്.
ഇതിനായി, ഞങ്ങൾക്ക് ഭാരം കൊടുത്ത ലീസ്റ്റ് സ്ക്വയേഴ്സ് ലക്ഷ്യം ഉപയോഗിക്കാം, ഭാരങ്ങൾ . ഇതിന് പരിഹാരം ഉണ്ട്
വിവിധ കെർണൽ ഫംഗ്ഷനുകൾ യുടെ ഫലങ്ങൾ പ്ലോട്ട് ചെയ്യുന്നു:
പ്ലോട്ടിംഗ് കോഡ്
import plotly.graph_objects as go
import numpy as np
# ഡാറ്റ ജനറേറ്റ് ചെയ്യുക
np.random.seed(42)
n_points = 100
X = np.random.uniform(0, 1, n_points)
epsilon = np.random.normal(0, 1 / 3, n_points)
Y = np.sin(4 * X) + epsilon
# യഥാർത്ഥ ഫംഗ്ഷൻ
x_true = np.linspace(0, 1, 500)
y_true = np.sin(4 * x_true)
# കെർണലുകൾ
def gaussian_kernel(u):
return np.exp(-0.5 * u**2)
def epanechnikov_kernel(u):
return np.maximum(0, 1 - u**2)
def tricube_kernel(u):
return np.maximum(0, (1 - np.abs(u) ** 3) ** 3)
# ഒരു പ്രത്യേക കെർണലിനായി ലോക്കൽ ലീനിയർ റിഗ്രഷൻ
def local_linear_regression(X, Y, x_curve, bandwidths, kernel):
y_curves = {}
for λ in bandwidths:
λ_rounded = round(λ, 2)
y_curve = []
for x in x_curve:
# നിർദ്ദിഷ്ട കെർണൽ ഉപയോഗിച്ച് ഭാരങ്ങൾ കണക്കാക്കുക
distances = (X - x) / λ
weights = kernel(distances)
W = np.diag(weights)
# ഡിസൈൻ മാട്രിക്സ് സൃഷ്ടിക്കുക
X_design = np.vstack((np.ones_like(X), X)).T
# ഭാരം കൊടുത്ത ലീസ്റ്റ് സ്ക്വയേഴ്സ് ഉപയോഗിച്ച് ബീറ്റ കണ്ടെത്തുക
beta = np.linalg.pinv(X_design.T @ W @ X_design) @ X_design.T @ W @ Y
# y-മൂല്യം പ്രവചിക്കുക
y_curve.append(beta[0] + beta[1] * x)
y_curves[λ_rounded] = y_curve
return y_curves
# പൊതു വേരിയബിളുകൾ
x_curve = np.arange(0, 1, 0.01)
bandwidths = np.linspace(0.05, 0.5, 20)
initial_λ = bandwidths[len(bandwidths) // 2]
# ഓരോ കെർണലിനും പ്ലോട്ടുകൾ ജനറേറ്റ് ചെയ്യുക
kernels = {
"Gaussian Kernel": gaussian_kernel,
"Epanechnikov Kernel": epanechnikov_kernel,
"Tricube Kernel": tricube_kernel,
}
plots = []
for kernel_name, kernel_func in kernels.items():
# നിർദ്ദിഷ്ട കെർണൽ ഉപയോഗിച്ച് LLR കണക്കാക്കുക
y_curves = local_linear_regression(X, Y, x_curve, bandwidths, kernel_func)
# Plotly ഫിഗർ സൃഷ്ടിക്കുക
fig = go.Figure()
# സ്റ്റാറ്റിക് ട്രേസുകൾ ചേർക്കുക
fig.add_trace(
go.Scatter(
x=X, y=Y, mode="markers", name="Noisy Data", marker=dict(color="gray")
)
)
fig.add_trace(
go.Scatter(
x=x_true,
y=y_true,
mode="lines",
name="True Function",
line=dict(color="red"),
)
)
# ആദ്യത്തെ LLR കർവ് ചേർക്കുക (ബാൻഡ്വിഡ്ത്തിന്റെ മധ്യ മൂല്യം ഉപയോഗിച്ച്)
fig.add_trace(
go.Scatter(
x=x_curve,
y=y_curves[round(initial_λ, 2)],
mode="lines",
name=f"{kernel_name} Curve",
line=dict(color="yellow"),
)
)
# സ്ലൈഡർ ഘട്ടങ്ങൾ നിർവ്വചിക്കുക
steps = []
for λ in bandwidths:
λ_rounded = round(λ, 2)
step = dict(
method="update",
args=[
{"y": [Y, y_true, y_curves[λ_rounded]]}, # ട്രേസുകൾക്കായി y-ഡാറ്റ അപ്ഡേറ്റ് ചെയ്യുക
{
"title": f"LLR: {kernel_name} with Bandwidth λ = {λ_rounded}"
}, # ടൈറ്റിൽ ഡൈനാമിക് ആയി അപ്ഡേറ്റ് ചെയ്യുക
],
label=f"{λ_rounded}",
)
steps.append(step)
# ലേഔട്ടിലേക്ക് സ്ലൈഡർ ചേർക്കുക
sliders = [
dict(
active=len(bandwidths) // 2, # മധ്യ ബാൻഡ്വിഡ്ത്തിന്റെ ഇൻഡെക്സ് ഉപയോഗിക്കുക
currentvalue={"prefix": "λ = "},
pad={"t": 50},
steps=steps,
)
]
fig.update_layout(
sliders=sliders,
title=f"LLR: {kernel_name} with Bandwidth λ = {round(initial_λ, 2)}",
xaxis_title="X",
yaxis_title="Y",
template="plotly_dark",
height=400,
width=730,
)
plots.append(fig)
# പ്ലോട്ടുകൾ കാണിക്കുകയും സേവ് ചെയ്യുകയും ചെയ്യുക
for i, (kernel_name, fig) in enumerate(zip(kernels.keys(), plots)):
fig.show()
html_path = f"./llr_{kernel_name.lower().replace(' ', '_')}.html"
fig.write_html(html_path)
print(f"Saved interactive plot for {kernel_name} to {html_path}")
ഫലങ്ങൾ വളരെ മിനുസമാർന്നതായി തോന്നുന്നു!
അവലംബങ്ങൾ
- ദ എലമെന്റ്സ് ഓഫ് സ്റ്റാറ്റിസ്റ്റിക്കൽ ലേണിംഗ് - ഹാസ്റ്റി, ടിബ്ഷിറാനി, ഫ്രീഡ്മാൻ (2009). ഡാറ്റാ മൈനിംഗ്, അനുമാനം, പ്രവചനം എന്നിവയെക്കുറിച്ചുള്ള ഒരു സമഗ്ര ഗൈഡ്. കൂടുതൽ വായിക്കുക.