• ടാസ്ക്
  • കെ ന്യൂറസ്റ്റ് നെയ്ബറുകൾ
  • നദരായ–വാട്സൺ കെർണൽ റിഗ്രഷൻ
    • കെർണൽ ഫംഗ്ഷനുകൾ
    • ഫലങ്ങൾ
  • ലോക്കൽ ലീനിയർ റിഗ്രഷൻ
    • പ്രദേശം: $k$-NN
    • പ്രദേശം: കെർണൽ ഫംഗ്ഷൻ
  • അവലംബങ്ങൾ
  • ഹോം
  • പോസ്റ്റുകൾ
  • കുറിപ്പുകൾ
  • പുസ്തകശാല
  • രചയിതാവ്
🇺🇸 en 🇫🇷 fr 🇨🇳 zh

Nathaniel Thomas

ലോക്കൽ അപ്രോക്സിമേഷൻ

2024, ഡിസംബർ 1

ഒരു ഡീപ് ന്യൂറൽ നെറ്റ്വർക്ക് പരിശീലിപ്പിക്കുന്നത് അടിസ്ഥാനപരമായി ഒരു കംപ്രഷൻ ടാസ്ക് ആണ്. ഞങ്ങൾക്ക് ആവശ്യമുള്ളത് ഞങ്ങളുടെ പരിശീലന ഡാറ്റ ഡിസ്ട്രിബ്യൂഷനെ ഒരു കൂട്ടം മെട്രിക്സുകളാൽ പാരാമീറ്ററൈസ് ചെയ്ത ഒരു ഫംഗ്ഷനായി പ്രതിനിധീകരിക്കുക എന്നതാണ്. ഡിസ്ട്രിബ്യൂഷൻ കൂടുതൽ സങ്കീർണ്ണമാകുമ്പോൾ, കൂടുതൽ പാരാമീറ്ററുകൾ ആവശ്യമാണ്. മുഴുവൻ ഡിസ്ട്രിബ്യൂഷൻ അപ്രോക്സിമേറ്റ് ചെയ്യുന്നതിന്റെ യുക്തി എന്നത്, ഇൻഫറൻസ് സമയത്ത് ഏതെങ്കിലും സാധുവായ പോയിന്റ് ഫോർവേഡ് ചെയ്യാൻ ഒരേ മോഡൽ, ഒരേ ഭാരങ്ങൾ ഉപയോഗിക്കാൻ കഴിയും എന്നതാണ്. എന്നാൽ നമ്മുടെ മോഡൽ ഇൻഫറൻസ് സമയത്ത് തന്നെ പരിശീലിപ്പിച്ചാൽ എന്തുണ്ടാകും? അപ്പോൾ, x ഫോർവേഡ് ചെയ്യുമ്പോൾ, x ചുറ്റുമുള്ള ലോക്കൽ ഡിസ്ട്രിബ്യൂഷൻ മാത്രമേ മോഡൽ ചെയ്യേണ്ടതുള്ളൂ. ലോക്കൽ പ്രദേശത്തിന് മുഴുവൻ പരിശീലന സെറ്റിനേക്കാൾ കുറഞ്ഞ ഡൈമെൻഷണാലിറ്റി ഉണ്ടായിരിക്കണം, അതിനാൽ വളരെ ലളിതമായ ഒരു മോഡൽ മതിയാകും!

ലോക്കൽ അപ്രോക്സിമേഷൻ അല്ലെങ്കിൽ ലോക്കൽ റിഗ്രഷൻ എന്ന ആശയമാണ് ഇത്. നമുക്ക് ഒരു ലളിതമായ റിഗ്രഷൻ ടാസ്ക് പരിഗണിക്കാം.

ടാസ്ക്

നമുക്ക് താഴെയുള്ള ഡാറ്റയുടെ 100 സാമ്പിളുകൾ നൽകിയിട്ടുണ്ട്:

Y=sin(4X)+ϵ

ഇവിടെ

ϵ∼N(0,31​)
Loading...
Loading...
പ്ലോട്ടിംഗ് കോഡ്
from pathlib import Path

import numpy as np
import plotly.graph_objects as go

# Generate data
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

# True function
x_true = np.linspace(0, 1, 500)
y_true = np.sin(4 * x_true)

# Create the plot
fig = go.Figure()

# Add scatter points for noisy data
fig.add_trace(
    go.Scatter(
        x=X,
        y=Y,
        mode="markers",
        name="Noisy Data",
        marker=dict(color="gray"),
    )
)

# Add true function
fig.add_trace(
    go.Scatter(
        x=x_true,
        y=y_true,
        mode="lines",
        name="True Function",
        line=dict(color="red"),
    )
)

# Update layout shared across themes
fig.update_layout(
    autosize=True,
    title="Data",
    xaxis_title="X",
    yaxis_title="Y",
)

# Theme configuration aligning with dario.css colors
themes = [
    {
        "name": "light",
        "template": "plotly_white",
        "font_color": "#141413",
        "background": "#f0efea",
        "axis_color": "#141413",
        "gridcolor": "rgba(20, 20, 19, 0.2)",
    },
    {
        "name": "dark",
        "template": "plotly_dark",
        "font_color": "#f0efea",
        "background": "#141413",
        "axis_color": "#f0efea",
        "gridcolor": "rgba(240, 239, 234, 0.2)",
    },
]

output_dir = Path(__file__).resolve().parents[3] / "static"
output_dir.mkdir(parents=True, exist_ok=True)

for theme in themes:
    themed_fig = go.Figure(fig)
    themed_fig.update_layout(
        template=theme["template"],
        font=dict(color=theme["font_color"]),
        paper_bgcolor=theme["background"],
        plot_bgcolor=theme["background"],
    )
    themed_fig.update_xaxes(
        showline=True,
        linecolor=theme["axis_color"],
        tickcolor=theme["axis_color"],
        tickfont=dict(color=theme["axis_color"]),
        title_font=dict(color=theme["axis_color"]),
        gridcolor=theme["gridcolor"],
        zeroline=False,
    )
    themed_fig.update_yaxes(
        showline=True,
        linecolor=theme["axis_color"],
        tickcolor=theme["axis_color"],
        tickfont=dict(color=theme["axis_color"]),
        title_font=dict(color=theme["axis_color"]),
        gridcolor=theme["gridcolor"],
        zeroline=False,
    )

    filename = output_dir / f"local_approximation_data_{theme['name']}.html"
    themed_fig.write_html(filename)
    print(f"Saved plot to {filename}")

# Show the plot
fig.show()

ഡാറ്റാസെറ്റ് D എന്ന് സൂചിപ്പിക്കുന്നു, അതിൽ (xi​,yi​)∈D എന്ന സാമ്പിളുകൾ അടങ്ങിയിരിക്കുന്നു.

ഡാറ്റയിലൂടെ ഒരു യുക്തിസഹമായ വക്രം ഫിറ്റ് ചെയ്യുക എന്നതാണ് നമ്മുടെ ടാസ്ക്, അത് യഥാർത്ഥ ഫംഗ്ഷനെ ഏകദേശം പൊരുത്തപ്പെടുന്നു. ഈ വക്രത്തെ f^​ എന്ന് സൂചിപ്പിക്കാം.

കെ ന്യൂറസ്റ്റ് നെയ്ബറുകൾ

ഒരു x നൽകിയാൽ, x എന്നതിനോട് ഏറ്റവും അടുത്തുള്ള k മൂല്യങ്ങൾ xi​ എടുത്ത് അവയുടെ yi​ മൂല്യങ്ങളുടെ ശരാശരി കണക്കാക്കുന്നതാണ് ഒരു സമീപനം. അതായത്,

f^​(x)=Ave(yi​∣xi​∈Nk​(x))

ഇവിടെ Nk​(x) എന്നത് x എന്നതിനോട് ഏറ്റവും അടുത്തുള്ള k പോയിന്റുകളെ സൂചിപ്പിക്കുന്നു.

Loading...
Loading...
പ്ലോട്ടിംഗ് കോഡ്
from pathlib import Path

import numpy as np
import plotly.graph_objects as go

# Generate data
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

# True function
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

# Create the Plotly figure
fig = go.Figure()

# Add static traces
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")
    )
)

# Add the first k-NN curve (k=13, the default slider position)
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"),
    )
)

# Define slider steps
steps = []
for k in k_range:
    step = dict(
        method="update",
        args=[
            {"y": [Y, y_true, y_curves_knn[k]]},  # Update y-data for the traces
            {
                "title": f"Interactive k-NN Curve with Slider for k = {k}"
            },  # Update the title dynamically
        ],
        label=f"{k}",
    )
    steps.append(step)

# Add slider to the layout
sliders = [
    dict(
        active=initial_k - 1,
        currentvalue={"prefix": "k = "},
        pad={"t": 50},
        steps=steps,
    )
]

fig.update_layout(
    sliders=sliders,
    autosize=True,
    title=f"Interactive k-NN Curve with Slider for k = {initial_k}",
    xaxis_title="X",
    yaxis_title="Y",
)

themes = [
    {
        "name": "light",
        "template": "plotly_white",
        "font_color": "#141413",
        "background": "#f0efea",
        "axis_color": "#141413",
        "gridcolor": "rgba(20, 20, 19, 0.2)",
    },
    {
        "name": "dark",
        "template": "plotly_dark",
        "font_color": "#f0efea",
        "background": "#141413",
        "axis_color": "#f0efea",
        "gridcolor": "rgba(240, 239, 234, 0.2)",
    },
]

output_dir = Path(__file__).resolve().parents[3] / "static"
output_dir.mkdir(parents=True, exist_ok=True)

for theme in themes:
    themed_fig = go.Figure(fig)
    themed_fig.update_layout(
        template=theme["template"],
        font=dict(color=theme["font_color"]),
        paper_bgcolor=theme["background"],
        plot_bgcolor=theme["background"],
    )
    themed_fig.update_xaxes(
        showline=True,
        linecolor=theme["axis_color"],
        tickcolor=theme["axis_color"],
        tickfont=dict(color=theme["axis_color"]),
        title_font=dict(color=theme["axis_color"]),
        gridcolor=theme["gridcolor"],
        zeroline=False,
    )
    themed_fig.update_yaxes(
        showline=True,
        linecolor=theme["axis_color"],
        tickcolor=theme["axis_color"],
        tickfont=dict(color=theme["axis_color"]),
        title_font=dict(color=theme["axis_color"]),
        gridcolor=theme["gridcolor"],
        zeroline=False,
    )

    html_path = output_dir / f"knn_slider_{theme['name']}.html"
    themed_fig.write_html(html_path)
    print(f"Saved interactive plot to {html_path}")

# Show the plot
fig.show()

സ്ലൈഡർ ഉപയോഗിച്ച് നിങ്ങൾക്ക് കാണാൻ കഴിയും, k വലുതാകുന്തോറും കർവ് മിനുസമാർന്നതാകുന്നു, എന്നാൽ കുറഞ്ഞ k കർവുകൾ ചില ശബ്ദങ്ങളെ ഉൾക്കൊള്ളുന്നു. അങ്ങേയറ്റത്തെ സ്ഥിതികളിൽ, k=1 ട്രെയിനിംഗ് ഡാറ്റയെ കൃത്യമായി പിന്തുടരുന്നു, k=100 ഒരു പരന്ന ആഗോള ശരാശരി നൽകുന്നു.

നദരായ–വാട്സൺ കെർണൽ റിഗ്രഷൻ

ഡാറ്റയുടെ ഉപഗണത്തെ k പോയിന്റുകളായി പരിമിതപ്പെടുത്തുന്നതിന് പകരം, സെറ്റിലെ എല്ലാ പോയിന്റുകളും പരിഗണിക്കാം, എന്നാൽ ഓരോ പോയിന്റിന്റെയും സംഭാവന x എന്നതിലേക്കുള്ള അതിന്റെ സാമീപ്യത്തെ അടിസ്ഥാനമാക്കി ഭാരം നൽകുക. മോഡൽ പരിഗണിക്കുക

f^​(x)=∑i=1∣D∣​Kλ​(x,xi​)∑i=1∣D∣​Kλ​(x,xi​)yi​​

ഇവിടെ Kλ​ ഒരു കെർണൽ ആണ്, ഇത് ഞങ്ങൾ ഒരു സാമീപ്യ മെട്രിക് ആയി ഉപയോഗിക്കും.

Kλ​(x0​,x)=D(λ∣x−x0​∣​)

ഈ ഫംഗ്ഷൻ λ എന്ന പാരാമീറ്റർ ഉപയോഗിച്ച് പാരാമീറ്ററൈസ് ചെയ്യപ്പെടുന്നു, ഇത് ബാൻഡ്വിഡ്ത്ത് എന്നറിയപ്പെടുന്നു, ഇത് f^​ ന്റെ ഔട്ട്പുട്ടിൽ ഡാറ്റയിലെ x മൂല്യങ്ങളുടെ എന്ത് ശ്രേണി പങ്കുവഹിക്കുന്നുവെന്ന് നിയന്ത്രിക്കുന്നു. ഈ ഫംഗ്ഷനുകൾ പ്ലോട്ട് ചെയ്താൽ ഇത് വ്യക്തമാകും.

കെർണൽ ഫംഗ്ഷനുകൾ

ചുവടെ പ്ലോട്ട് ചെയ്തിരിക്കുന്നത്

f(x)=αKλ,D​(0,x)

ഇവിടെ α എന്നത് f ന്റെ സപ്പോർട്ടിൽ 1 ആയി ഇന്റഗ്രേറ്റ് ചെയ്യുന്നത് നിലനിർത്തുന്നു.

Loading...
Loading...
D(u)=⎩⎨⎧​43​(1−u2)0​if ∣u∣≤1,if ∣u∣>1.​
Loading...
Loading...
D(u)=⎩⎨⎧​(1−∣u∣3)30​if ∣u∣≤1,if ∣u∣>1.​
Loading...
Loading...
D(u)=2π​1​e−21​u2.
പ്ലോട്ടിംഗ് കോഡ്
from pathlib import Path

import numpy as np
import plotly.graph_objects as go
from scipy.integrate import quad


# Define kernel functions
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


# Kernel function plot generator
def generate_kernel_plot(
    kernel_name, kernel_func, x_range, u_range, lambda_values, y_range
):
    fig = go.Figure()

    # Initial lambda
    initial_lambda = lambda_values[len(lambda_values) // 2]

    # Generate initial kernel curve
    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} Kernel (λ={initial_lambda:.2f})",
            line=dict(color="green"),
        )
    )

    # Create frames for the slider
    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} Kernel (λ={bandwidth:.2f})",
                        line=dict(color="green"),
                    )
                ],
                name=f"{bandwidth:.2f}",
            )
        )

    # Add frames to the figure
    fig.frames = frames

    # Add slider
    sliders = [
        {
            "active": len(lambda_values) // 2,
            "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
            ],
        }
    ]

    # Update layout
    fig.update_layout(
        title=f"{kernel_name} Kernel Function",
        xaxis_title="u",
        yaxis_title="K(u)",
        yaxis_range=y_range,
        sliders=sliders,
        autosize=True,
        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",
            }
        ],
    )

    return fig


# Kernel functions
kernels = {
    "Epanechnikov": epanechnikov_kernel,
    "Tricube": tricube_kernel,
    "Gaussian": gaussian_kernel,
}

# Parameters
x_range_plot = (-3, 3)  # Range of u values for the plot
u_range_integration = (-3, 3)  # Range for normalization
lambda_values = np.linspace(0.01, 2, 20)  # Linear lambda values from 0.01 to 2
y_range_plot = (0, 1.5)  # Adjusted range to fit the normalized functions

# Generate and display plots for each kernel
themes = [
    {
        "name": "light",
        "template": "plotly_white",
        "font_color": "#141413",
        "background": "#f0efea",
        "axis_color": "#141413",
        "gridcolor": "rgba(20, 20, 19, 0.2)",
    },
    {
        "name": "dark",
        "template": "plotly_dark",
        "font_color": "#f0efea",
        "background": "#141413",
        "axis_color": "#f0efea",
        "gridcolor": "rgba(240, 239, 234, 0.2)",
    },
]

output_dir = Path(__file__).resolve().parents[3] / "static"
output_dir.mkdir(parents=True, exist_ok=True)

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,
    )

    # Save themed figures to HTML files
    for theme in themes:
        themed_fig = go.Figure(fig)
        themed_fig.update_layout(
            template=theme["template"],
            font=dict(color=theme["font_color"]),
            paper_bgcolor=theme["background"],
            plot_bgcolor=theme["background"],
        )
        themed_fig.update_xaxes(
            showline=True,
            linecolor=theme["axis_color"],
            tickcolor=theme["axis_color"],
            tickfont=dict(color=theme["axis_color"]),
            title_font=dict(color=theme["axis_color"]),
            gridcolor=theme["gridcolor"],
            zeroline=False,
        )
        themed_fig.update_yaxes(
            showline=True,
            linecolor=theme["axis_color"],
            tickcolor=theme["axis_color"],
            tickfont=dict(color=theme["axis_color"]),
            title_font=dict(color=theme["axis_color"]),
            gridcolor=theme["gridcolor"],
            zeroline=False,
        )

        filename = (
            output_dir
            / f"{kernel_name}_dynamic_normalization_kernel_function_{theme['name']}.html"
        )
        themed_fig.write_html(filename, auto_play=False)
        print(f"Saved {kernel_name} kernel plot to {filename}")

    # Show the figure
    fig.show()

ഫലങ്ങൾ

ഇപ്പോൾ ഓരോ കെർണൽ ഫംഗ്ഷനുകൾക്കും ഫലങ്ങൾ പ്ലോട്ട് ചെയ്യുന്നു. ഓരോ പ്ലോട്ടിലും ഒരു λ സ്ലൈഡർ ഉണ്ട്, ഇത് ഔട്ട്പുട്ട് ലൈവ് നിയന്ത്രിക്കുന്നു.

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
പ്ലോട്ടിംഗ് കോഡ്
from pathlib import Path

import numpy as np
import plotly.graph_objects as go


# Define kernel functions
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)


# Kernel regression function
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


# Generate data
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

# True curve
x_true = np.linspace(0, 1, 500)
y_true = np.sin(4 * x_true)

# Points for kernel estimation
x_curve = x_true

# Kernel functions
kernels = {
    "Epanechnikov": epanechnikov_kernel,
    "Tricube": tricube_kernel,
    "Gaussian": gaussian_kernel,
}

# Range of bandwidths for the slider in logspace
lambda_values = np.logspace(-2, 0, 20)  # From 0.01 to 1

# Generate separate plots for each kernel
themes = [
    {
        "name": "light",
        "template": "plotly_white",
        "font_color": "#141413",
        "background": "#f0efea",
        "axis_color": "#141413",
        "gridcolor": "rgba(20, 20, 19, 0.2)",
    },
    {
        "name": "dark",
        "template": "plotly_dark",
        "font_color": "#f0efea",
        "background": "#141413",
        "axis_color": "#f0efea",
        "gridcolor": "rgba(240, 239, 234, 0.2)",
    },
]

output_dir = Path(__file__).resolve().parents[3] / "static"
output_dir.mkdir(parents=True, exist_ok=True)

# Generate separate plots for each kernel
for kernel_name, kernel_func in kernels.items():
    fig = go.Figure()

    # Add scatter points for noisy data
    fig.add_trace(
        go.Scatter(
            x=X, y=Y, mode="markers", name="Noisy Data", marker=dict(color="gray")
        )
    )

    # Add true function
    fig.add_trace(
        go.Scatter(
            x=x_true,
            y=y_true,
            mode="lines",
            name="True Function",
            line=dict(color="red"),
        )
    )

    # Add initial kernel curve
    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"),
        )
    )

    # Create frames for the slider
    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}",
            )
        )

    # Add frames to the figure
    fig.frames = frames

    # Add slider
    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
            ],
        }
    ]

    # Update layout
    fig.update_layout(
        autosize=True,
        title=f"Nadaraya-Watson Kernel Regression ({kernel_name} Kernel)",
        xaxis_title="X",
        yaxis_title="Y",
        sliders=sliders,
        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",
            }
        ],
    )

    # Save the figure to an HTML file per theme
    for theme in themes:
        themed_fig = go.Figure(fig)
        themed_fig.update_layout(
            template=theme["template"],
            font=dict(color=theme["font_color"]),
            paper_bgcolor=theme["background"],
            plot_bgcolor=theme["background"],
        )
        themed_fig.update_xaxes(
            showline=True,
            linecolor=theme["axis_color"],
            tickcolor=theme["axis_color"],
            tickfont=dict(color=theme["axis_color"]),
            title_font=dict(color=theme["axis_color"]),
            gridcolor=theme["gridcolor"],
            zeroline=False,
        )
        themed_fig.update_yaxes(
            showline=True,
            linecolor=theme["axis_color"],
            tickcolor=theme["axis_color"],
            tickfont=dict(color=theme["axis_color"]),
            title_font=dict(color=theme["axis_color"]),
            gridcolor=theme["gridcolor"],
            zeroline=False,
        )

        filename = output_dir / f"{kernel_name}_kernel_regression_{theme['name']}.html"
        themed_fig.write_html(filename, auto_play=False)
        print(f"Saved {kernel_name} kernel plot to {filename}")

    # Show the figure
    fig.show()

ഡാറ്റയുടെ ഒരു ലളിതമായ ഭാരം കൂടിയ ശരാശരി ഒരു സൈനസോയിഡ് നന്നായി മോഡൽ ചെയ്യാൻ കഴിയുന്നതായി നമ്മൾ കാണുന്നു.

ലോക്കൽ ലീനിയർ റിഗ്രഷൻ

നദരായ-വാട്സൺ കെർണൽ റിഗ്രഷനിൽ, കെർണൽ ഫംഗ്ഷൻ Kλ​ വഴി നിർവചിച്ചിരിക്കുന്ന ഒരു പരിസരത്തിൽ ഒരു ഭാരം കൂടിയ ശരാശരി എടുക്കുന്നു. ഇതിനൊരു സാധ്യമായ പ്രശ്നം എന്നത് ലോക്കൽ പരിസരങ്ങളിലെ മിനുസമാർന്ന ഇന്റർപോളേഷൻ ആണ്, കാരണം ആ പ്രദേശം യാതൊരു മോഡലിനെയും പിന്തുടരുന്നുവെന്ന് നാം യഥാർത്ഥത്തിൽ അനുമാനിക്കുന്നില്ല.

ഓരോ പ്രദേശവും ലോക്കലായി ലീനിയർ ആണെന്ന് നമ്മൾ അനുമാനിച്ചാൽ എന്തുണ്ടാകും? അപ്പോൾ, നമുക്ക് ലീസ്റ്റ് സ്ക്വയർ ഫിറ്റ് പരിഹരിക്കാനും സ്വതന്ത്രമായി ഇന്റർപോളേറ്റ് ചെയ്യാനും കഴിയും!

പ്രദേശം: $k$-NN

നമുക്ക് നമ്മുടെ പ്രാദേശിക പ്രദേശം നമ്മുടെ ഇൻപുട്ടിന്റെ k അടുത്തുള്ള അയൽക്കാരായി നിർവചിക്കാം. X=[Nk​(x0​)​1​] എന്നും Y അതിനോടനുബന്ധിച്ച y മൂല്യങ്ങളായും എടുക്കാം. ലീസ്റ്റ് സ്ക്വയർ ഫിറ്റ് കോഫിഫിഷ്യന്റുകൾ ഇവയാണ്:

β=(X⊤X)−1XY
Loading...
Loading...
പ്ലോട്ടിംഗ് കോഡ്
from pathlib import Path

import numpy as np
import plotly.graph_objects as go

# Generate data
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

# True function
x_true = np.linspace(0, 1, 500)
y_true = np.sin(4 * x_true)


# k-NN Local Linear Regression
def knn_linear_regression(X, Y, x_curve, k_range):
    y_curves = {}
    for k in k_range:
        y_curve = []
        for x in x_curve:
            # Find k nearest neighbors
            distances = np.abs(X - x)
            nearest_indices = np.argsort(distances)[:k]

            # Select k nearest neighbors
            X_knn = X[nearest_indices]
            Y_knn = Y[nearest_indices]

            # Create design matrix for k-nearest neighbors
            X_design = np.vstack((np.ones_like(X_knn), X_knn)).T

            # Solve for beta using ordinary least squares
            beta = np.linalg.pinv(X_design.T @ X_design) @ X_design.T @ Y_knn

            # Predict y-value
            y_curve.append(beta[0] + beta[1] * x)
        y_curves[k] = y_curve
    return y_curves


# Common variables
x_curve = np.arange(0, 1, 0.01)
k_range = range(1, 21)  # Values of k from 1 to 20
initial_k = 10  # Default value of k

# Compute LLR using k-NN
y_curves_knn = knn_linear_regression(X, Y, x_curve, k_range)

# Create the Plotly figure
fig = go.Figure()

# Add static traces
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")
    )
)

# Add the first k-NN curve (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"),
    )
)

# Define slider steps
steps = []
for k in k_range:
    step = dict(
        method="update",
        args=[
            {"y": [Y, y_true, y_curves_knn[k]]},  # Update y-data for the traces
            {
                "title": f"k-NN Local Linear Regression Curve with k = {k}"
            },  # Update the title dynamically
        ],
        label=f"{k}",
    )
    steps.append(step)

# Add slider to the layout
sliders = [
    dict(
        active=k_range.index(initial_k),  # Use the index of initial_k
        currentvalue={"prefix": "k = "},
        pad={"t": 50},
        steps=steps,
    )
]

fig.update_layout(
    autosize=True,
    sliders=sliders,
    title=f"k-NN Local Linear Regression Curve with k = {initial_k}",
    xaxis_title="X",
    yaxis_title="Y",
)

themes = [
    {
        "name": "light",
        "template": "plotly_white",
        "font_color": "#141413",
        "background": "#f0efea",
        "axis_color": "#141413",
        "gridcolor": "rgba(20, 20, 19, 0.2)",
    },
    {
        "name": "dark",
        "template": "plotly_dark",
        "font_color": "#f0efea",
        "background": "#141413",
        "axis_color": "#f0efea",
        "gridcolor": "rgba(240, 239, 234, 0.2)",
    },
]

output_dir = Path(__file__).resolve().parents[3] / "static"
output_dir.mkdir(parents=True, exist_ok=True)

for theme in themes:
    themed_fig = go.Figure(fig)
    themed_fig.update_layout(
        template=theme["template"],
        font=dict(color=theme["font_color"]),
        paper_bgcolor=theme["background"],
        plot_bgcolor=theme["background"],
    )
    themed_fig.update_xaxes(
        showline=True,
        linecolor=theme["axis_color"],
        tickcolor=theme["axis_color"],
        tickfont=dict(color=theme["axis_color"]),
        title_font=dict(color=theme["axis_color"]),
        gridcolor=theme["gridcolor"],
        zeroline=False,
    )
    themed_fig.update_yaxes(
        showline=True,
        linecolor=theme["axis_color"],
        tickcolor=theme["axis_color"],
        tickfont=dict(color=theme["axis_color"]),
        title_font=dict(color=theme["axis_color"]),
        gridcolor=theme["gridcolor"],
        zeroline=False,
    )

    html_path = output_dir / f"knn_slider_llr_{theme['name']}.html"
    themed_fig.write_html(html_path)
    print(f"Saved interactive k-NN plot to {html_path}")

# Show the plot
fig.show()

ചെറിയ k മൂല്യങ്ങൾക്ക് ഔട്ട്പുട്ട് വളരെ പരുക്കനായിരിക്കുമെന്ന് നമുക്ക് കാണാം.

പ്രദേശം: കെർണൽ ഫംഗ്ഷൻ

ഒരുപക്ഷേ നാദരായ-വാട്സൺ കെർണലിൽ നിന്ന് ചില ആശയങ്ങൾ പുനരുപയോഗിക്കാം. പരിശീലന സെറ്റിലെ എല്ലാ പോയിന്റുകളും വ്യത്യസ്ത അളവിൽ പരിഗണിക്കാൻ ഞങ്ങൾ ആഗ്രഹിക്കുന്നു, ലോക്കൽ പ്രദേശത്ത് ഉയർന്ന ഭാരങ്ങളും പുറത്ത് കുറഞ്ഞ ഭാരങ്ങളും ഉപയോഗിച്ച്.

ഇതിനായി, ഞങ്ങൾക്ക് ഭാരം കൊടുത്ത ലീസ്റ്റ് സ്ക്വയേഴ്സ് ലക്ഷ്യം ഉപയോഗിക്കാം, ഭാരങ്ങൾ W(x0​)=diag(Kλ​(x0​,xi​)). ഇതിന് പരിഹാരം ഉണ്ട്

β=(X⊤WX)−1X⊤WY

വിവിധ കെർണൽ ഫംഗ്ഷനുകൾ D യുടെ ഫലങ്ങൾ പ്ലോട്ട് ചെയ്യുന്നു:

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
പ്ലോട്ടിംഗ് കോഡ്
from pathlib import Path

import numpy as np
import plotly.graph_objects as go

# Generate data
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

# True function
x_true = np.linspace(0, 1, 500)
y_true = np.sin(4 * x_true)


# Kernels
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)


# Local Linear Regression for a specific kernel
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:
            # Calculate weights using the specified kernel
            distances = (X - x) / λ
            weights = kernel(distances)
            W = np.diag(weights)

            # Create design matrix
            X_design = np.vstack((np.ones_like(X), X)).T

            # Solve for beta using weighted least squares
            beta = np.linalg.pinv(X_design.T @ W @ X_design) @ X_design.T @ W @ Y

            # Predict y-value
            y_curve.append(beta[0] + beta[1] * x)
        y_curves[λ_rounded] = y_curve
    return y_curves


# Common variables
x_curve = np.arange(0, 1, 0.01)
bandwidths = np.linspace(0.05, 0.5, 20)
initial_λ = bandwidths[len(bandwidths) // 2]

# Generate plots for each kernel
kernels = {
    "Gaussian Kernel": gaussian_kernel,
    "Epanechnikov Kernel": epanechnikov_kernel,
    "Tricube Kernel": tricube_kernel,
}
plots = []

for kernel_name, kernel_func in kernels.items():
    # Compute LLR with the specified kernel
    y_curves = local_linear_regression(X, Y, x_curve, bandwidths, kernel_func)

    # Create the Plotly figure
    fig = go.Figure()

    # Add static traces
    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"),
        )
    )

    # Add the first LLR curve (using the middle value of bandwidths)
    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"),
        )
    )

    # Define slider steps
    steps = []
    for λ in bandwidths:
        λ_rounded = round(λ, 2)
        step = dict(
            method="update",
            args=[
                {"y": [Y, y_true, y_curves[λ_rounded]]},  # Update y-data for the traces
                {
                    "title": f"LLR: {kernel_name} with Bandwidth λ = {λ_rounded}"
                },  # Update the title dynamically
            ],
            label=f"{λ_rounded}",
        )
        steps.append(step)

    # Add slider to the layout
    sliders = [
        dict(
            active=len(bandwidths) // 2,  # Use the index of the middle bandwidth
            currentvalue={"prefix": "λ = "},
            pad={"t": 50},
            steps=steps,
        )
    ]

    fig.update_layout(
        autosize=True,
        sliders=sliders,
        title=f"LLR: {kernel_name} with Bandwidth λ = {round(initial_λ, 2)}",
        xaxis_title="X",
        yaxis_title="Y",
    )

    plots.append(fig)

# Show and save the plots with themed backgrounds
themes = [
    {
        "name": "light",
        "template": "plotly_white",
        "font_color": "#141413",
        "background": "#f0efea",
        "axis_color": "#141413",
        "gridcolor": "rgba(20, 20, 19, 0.2)",
    },
    {
        "name": "dark",
        "template": "plotly_dark",
        "font_color": "#f0efea",
        "background": "#141413",
        "axis_color": "#f0efea",
        "gridcolor": "rgba(240, 239, 234, 0.2)",
    },
]

output_dir = Path(__file__).resolve().parents[3] / "static"
output_dir.mkdir(parents=True, exist_ok=True)

for kernel_name, fig in zip(kernels.keys(), plots):
    fig.show()
    for theme in themes:
        themed_fig = go.Figure(fig)
        themed_fig.update_layout(
            template=theme["template"],
            font=dict(color=theme["font_color"]),
            paper_bgcolor=theme["background"],
            plot_bgcolor=theme["background"],
        )
        themed_fig.update_xaxes(
            showline=True,
            linecolor=theme["axis_color"],
            tickcolor=theme["axis_color"],
            tickfont=dict(color=theme["axis_color"]),
            title_font=dict(color=theme["axis_color"]),
            gridcolor=theme["gridcolor"],
            zeroline=False,
        )
        themed_fig.update_yaxes(
            showline=True,
            linecolor=theme["axis_color"],
            tickcolor=theme["axis_color"],
            tickfont=dict(color=theme["axis_color"]),
            title_font=dict(color=theme["axis_color"]),
            gridcolor=theme["gridcolor"],
            zeroline=False,
        )

        filename = (
            output_dir
            / f"llr_{kernel_name.lower().replace(' ', '_')}_{theme['name']}.html"
        )
        themed_fig.write_html(filename)
        print(f"Saved interactive plot for {kernel_name} to {filename}")

ഫലങ്ങൾ വളരെ മിനുസമാർന്നതായി തോന്നുന്നു!

അവലംബങ്ങൾ

  • ദ എലമെന്റ്സ് ഓഫ് സ്റ്റാറ്റിസ്റ്റിക്കൽ ലേണിംഗ് - ഹാസ്റ്റി, ടിബ്ഷിറാനി, ഫ്രീഡ്മാൻ (2009). ഡാറ്റാ മൈനിംഗ്, അനുമാനം, പ്രവചനം എന്നിവയെക്കുറിച്ചുള്ള ഒരു സമഗ്ര ഗൈഡ്. കൂടുതൽ വായിക്കുക.

←
കാരണാത്മക സ്വയം ശ്രദ്ധയുടെ യാന്ത്രികത
ഇന്ററാക്ടീവ് ഗൗസിയൻ മിശ്രണ മോഡലുകൾ
→

back to top