{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from scipy.linalg import inv\n", "from sklearn.datasets import load_boston\n", "from sklearn.kernel_ridge import KernelRidge as skKernelRidge\n", "from sklearn.linear_model import Ridge as skRidge" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Implementation 1\n", "- linear kernel\n", "- similar to sklearn kernel='linear'" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "class KernelRidge():\n", " def __init__(self, alpha=1.0):\n", " self.alpha = alpha\n", "\n", " \"\"\"\n", " @staticmethod\n", " def _linear_kernel(X, Y):\n", " K = np.zeros((X.shape[0], Y.shape[0]))\n", " for i in range(X.shape[0]):\n", " for j in range(Y.shape[0]):\n", " K[i, j] = np.dot(X[i], Y[j])\n", " return K\n", " \"\"\"\n", "\n", " @staticmethod\n", " def _linear_kernel(X, Y):\n", " K = np.dot(X, Y.T)\n", " return K\n", "\n", " def fit(self, X, y):\n", " A = self._linear_kernel(X, X) + np.diag(np.full(X.shape[0], self.alpha))\n", " self.dual_coef_ = np.dot(inv(A), y)\n", " self.X_fit_ = X\n", " return self\n", "\n", " def predict(self, X):\n", " K = self._linear_kernel(X, self.X_fit_)\n", " return np.dot(K, self.dual_coef_)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "for alpha in [0.1, 1, 10]:\n", " X, y = load_boston(return_X_y = True)\n", " clf1 = KernelRidge(alpha=alpha).fit(X, y)\n", " clf2 = skKernelRidge(alpha=alpha).fit(X, y)\n", " assert np.allclose(clf1.dual_coef_, clf2.dual_coef_, atol=1e-5)\n", " assert np.allclose(clf1.X_fit_, clf2.X_fit_)\n", " pred1 = clf1.predict(X)\n", " pred2 = clf2.predict(X)\n", " assert np.allclose(pred1, pred2)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# KernelRidge kernel='linear' is equivalant to Ridge\n", "X, y = load_boston(return_X_y = True)\n", "X = X - X.mean(axis=0)\n", "y = y - y.mean()\n", "clf1 = skKernelRidge().fit(X, y)\n", "clf2 = skRidge().fit(X, y)\n", "assert np.allclose(np.dot(X.T, clf1.dual_coef_), clf2.coef_)\n", "pred1 = clf1.predict(X)\n", "pred2 = clf2.predict(X)\n", "assert np.allclose(pred1, pred2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Implementation 2\n", "- rbf kernel\n", "- similar to sklearn kernel='rbf'" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "class KernelRidge():\n", " def __init__(self, alpha=1.0, gamma=None):\n", " self.alpha = alpha\n", " self.gamma = gamma\n", "\n", " @staticmethod\n", " def _rbf_kernel(X, Y, gamma):\n", " if gamma is None:\n", " gamma = 1 / X.shape[1]\n", " K = np.zeros((X.shape[0], Y.shape[0]))\n", " for i in range(X.shape[0]):\n", " for j in range(Y.shape[0]):\n", " K[i, j] = np.exp(-gamma * np.sum(np.square(X[i] - Y[j])))\n", " return K\n", "\n", " def fit(self, X, y):\n", " A = self._rbf_kernel(X, X, self.gamma) + np.diag(np.full(X.shape[0], self.alpha))\n", " self.dual_coef_ = np.dot(inv(A), y)\n", " self.X_fit_ = X\n", " return self\n", "\n", " def predict(self, X):\n", " K = self._rbf_kernel(X, self.X_fit_, self.gamma)\n", " return np.dot(K, self.dual_coef_)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "for gamma in [0.1, 1, 10, None]:\n", " X, y = load_boston(return_X_y = True)\n", " clf1 = KernelRidge(gamma=gamma).fit(X, y)\n", " clf2 = skKernelRidge(kernel='rbf', gamma=gamma).fit(X, y)\n", " assert np.allclose(clf1.dual_coef_, clf2.dual_coef_)\n", " assert np.allclose(clf1.X_fit_, clf2.X_fit_)\n", " pred1 = clf1.predict(X)\n", " pred2 = clf2.predict(X)\n", " assert np.allclose(pred1, pred2)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.8" } }, "nbformat": 4, "nbformat_minor": 2 }