plr 0.3.1

Performs greedy or optimal error-bounded piecewise linear regression (PLR) and spline regression
Documentation
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from matplotlib import pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x7fbf1107bf90>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.linspace(0, 7, 1000)\n",
    "y = np.sin(x)\n",
    "data = list(zip(x, y))\n",
    "plt.scatter(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def slope(p1, p2):\n",
    "    x1, y1 = p1\n",
    "    x2, y2 = p2\n",
    "    return (y2 - y1) / (x2 - x1)\n",
    "\n",
    "# a x + b = y\n",
    "# ax + b - y = 0\n",
    "# ax - y = -b\n",
    "\n",
    "def line(p1, p2):\n",
    "    a = slope(p1, p2)\n",
    "    b = -a * p1[0] + p1[1]\n",
    "    return (a,b)\n",
    "\n",
    "def intersection(l1, l2):\n",
    "    a, c = l1\n",
    "    b, d = l2\n",
    "    \n",
    "    return ((d - c) / (a - b)), ((a*d - b*c)/(a - b))\n",
    "\n",
    "def above(pt, line):\n",
    "    return pt[1] > line[0] * pt[0] + line[1]\n",
    "\n",
    "def below(pt, line):\n",
    "        return pt[1] < line[0] * pt[0] + line[1]\n",
    "\n",
    "def upper_bound(pt, gamma):\n",
    "    return (pt[0], pt[1] + gamma)\n",
    "\n",
    "def lower_bound(pt, gamma):\n",
    "    return (pt[0], pt[1] - gamma)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class GreedyPLR:\n",
    "    def __init__(self, gamma):\n",
    "        self.__state = \"need2\"\n",
    "        self.__gamma = gamma\n",
    "        \n",
    "    def process(self, pt):\n",
    "        self.__last_pt = pt\n",
    "        if self.__state == \"need2\":\n",
    "            self.__s0 = pt\n",
    "            self.__state = \"need1\"\n",
    "        elif self.__state == \"need1\":\n",
    "            self.__s1 = pt\n",
    "            self.__setup()\n",
    "            self.__state = \"ready\"\n",
    "        elif self.__state == \"ready\":\n",
    "            return self.__process(pt)\n",
    "        else:\n",
    "            assert False\n",
    "    \n",
    "    def __setup(self):\n",
    "        self.__rho_lower = line(upper_bound(self.__s0, self.__gamma),\n",
    "                                lower_bound(self.__s1, self.__gamma))\n",
    "        self.__rho_upper = line(lower_bound(self.__s0, self.__gamma),\n",
    "                                upper_bound(self.__s1, self.__gamma))\n",
    "        \n",
    "        self.__sint = intersection(self.__rho_lower, self.__rho_upper)\n",
    "        \n",
    "    def __current_segment(self):\n",
    "        segment_start = self.__s0[0]\n",
    "        segment_stop = self.__last_pt[0]\n",
    "        avg_slope = (self.__rho_lower[0] + self.__rho_upper[0]) / 2\n",
    "        intercept = -avg_slope * self.__sint[0] + self.__sint[1]\n",
    "        return (segment_start, segment_stop, avg_slope, intercept)\n",
    "        \n",
    "    def __process(self, pt):\n",
    "        if not (above(pt, self.__rho_lower) and below(pt, self.__rho_upper)):\n",
    "            # we have to start a new segment.\n",
    "            prev_segment = self.__current_segment()\n",
    "            \n",
    "            self.__s0 = pt\n",
    "            self.__state = \"need1\"\n",
    "            \n",
    "            # return the previous segment\n",
    "            return prev_segment\n",
    "        \n",
    "        # we can tweak our extreme slopes to account for this point.\n",
    "        # if this point's upper bound is below the current rho_upper,\n",
    "        # we have to change rho_upper.\n",
    "\n",
    "        s_upper = upper_bound(pt, self.__gamma)\n",
    "        s_lower = lower_bound(pt, self.__gamma)\n",
    "        if below(s_upper, self.__rho_upper):\n",
    "            self.__rho_upper = line(self.__sint, s_upper)\n",
    "        \n",
    "        # if this point's lower bound is above the current rho_lower,\n",
    "        # we have to change rho_lower\n",
    "        if above(s_lower, self.__rho_lower):\n",
    "            self.__rho_lower = line(self.__sint, s_lower)\n",
    "            \n",
    "        return None\n",
    "    \n",
    "    def finish(self):\n",
    "        if self.__state == \"need2\":\n",
    "            self.__state = \"finished\"\n",
    "            return None\n",
    "        elif self.__state == \"need1\":\n",
    "            self.__state = \"finished\"\n",
    "            return (self.__s0[0], self.__s0[0] + 1, 0, self.__s0[1])\n",
    "        elif self.__state == \"ready\":\n",
    "            self.__state = \"finished\"\n",
    "            return self.__current_segment()\n",
    "        else:\n",
    "            assert False\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "77"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "plr = GreedyPLR(0.0005)\n",
    "lines = []\n",
    "for pt in data:\n",
    "    l = plr.process(pt)\n",
    "    if l:\n",
    "        lines.append(l)\n",
    "    \n",
    "last = plr.finish()\n",
    "if last:\n",
    "    lines.append(last)\n",
    "    \n",
    "len(lines)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.scatter(x, y)\n",
    "for l in lines:\n",
    "    xl = np.linspace(l[0], l[1], 100)\n",
    "    yl = l[2] * xl + l[3]\n",
    "    plt.scatter(xl, yl)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(1, 1), (3, 3), (4, 3)]"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def update_hull(hull, upper=True):\n",
    "    # update an upper or lower convex hull using the triangle update rule\n",
    "    # assume the hull is sorted by x coordinate already.\n",
    "    \n",
    "    # take the last three points of the hull. If the middle point is\n",
    "    # above the line connecting the other two points, remove it. If not,\n",
    "    # repeat. When updating the lower hull, check if below the line.\n",
    "    reversed_hull = list(reversed(hull))\n",
    "    kept_points = []\n",
    "    while True:\n",
    "        if len(reversed_hull) < 3:\n",
    "            break\n",
    "            \n",
    "        pt1, pt2, pt3, *_ = reversed_hull\n",
    "                \n",
    "        l = line(pt1, pt3)\n",
    "        if upper and above(pt2, l):\n",
    "            del reversed_hull[1]\n",
    "            continue\n",
    "            \n",
    "        if not upper and below(pt2, l):\n",
    "            del reversed_hull[1]\n",
    "            continue\n",
    "            \n",
    "        # otherwise, pt1 gets to stay!\n",
    "        kept_points.insert(0, reversed_hull.pop(0))\n",
    "        \n",
    "        \n",
    "    while reversed_hull:\n",
    "        kept_points.insert(0, reversed_hull.pop(0))\n",
    "\n",
    "    return kept_points\n",
    "\n",
    "current_hull = [(1, 1), (2, 1), (3, 3), (4, 3)]\n",
    "current_hull = update_hull(current_hull, upper=False)\n",
    "current_hull"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def argmax(l):\n",
    "    return max(enumerate(l), key=lambda x: x[1])[0]\n",
    "\n",
    "def argmin(l):\n",
    "    return min(enumerate(l), key=lambda x: x[1])[0]\n",
    "        \n",
    "\n",
    "class OptimalPLR:\n",
    "    def __init__(self, gamma):\n",
    "        self.__state = \"need2\"\n",
    "        self.__gamma = gamma\n",
    "        \n",
    "    def process(self, pt):\n",
    "        self.__last_pt = pt\n",
    "        if self.__state == \"need2\":\n",
    "            self.__s0 = pt\n",
    "            self.__state = \"need1\"\n",
    "        elif self.__state == \"need1\":\n",
    "            self.__s1 = pt\n",
    "            self.__setup()\n",
    "            self.__state = \"ready\"\n",
    "        elif self.__state == \"ready\":\n",
    "            return self.__process(pt)\n",
    "        else:\n",
    "            assert False\n",
    "    \n",
    "    def __setup(self):\n",
    "        self.__rho_lower = line(upper_bound(self.__s0, self.__gamma),\n",
    "                                lower_bound(self.__s1, self.__gamma))\n",
    "        self.__rho_upper = line(lower_bound(self.__s0, self.__gamma),\n",
    "                                upper_bound(self.__s1, self.__gamma))\n",
    "        \n",
    "        self.__upper_hull = [upper_bound(self.__s0, self.__gamma),\n",
    "                             upper_bound(self.__s1, self.__gamma)]\n",
    "        self.__lower_hull = [lower_bound(self.__s0, self.__gamma),\n",
    "                             lower_bound(self.__s1, self.__gamma)]\n",
    "    def __current_segment(self):\n",
    "        sint = intersection(self.__rho_lower, self.__rho_upper)\n",
    "        segment_start = self.__s0[0]\n",
    "        segment_stop = self.__last_pt[0]\n",
    "        avg_slope = (self.__rho_lower[0] + self.__rho_upper[0]) / 2\n",
    "        intercept = -avg_slope * sint[0] + sint[1]\n",
    "        return (segment_start, segment_stop, avg_slope, intercept)\n",
    "        \n",
    "    def __process(self, pt):\n",
    "        if not (above(pt, self.__rho_lower) and below(pt, self.__rho_upper)):\n",
    "            # we have to start a new segment.\n",
    "            prev_segment = self.__current_segment()\n",
    "            \n",
    "            self.__s0 = pt\n",
    "            self.__state = \"need1\"\n",
    "            \n",
    "            # return the previous segment\n",
    "            return prev_segment\n",
    "        \n",
    "        # we can tweak our extreme slopes to account for this point.\n",
    "        # if this point's upper bound is below the current rho_upper,\n",
    "        # we have to change rho_upper.\n",
    "\n",
    "        s_upper = upper_bound(pt, self.__gamma)\n",
    "        s_lower = lower_bound(pt, self.__gamma)\n",
    "        if below(s_upper, self.__rho_upper):\n",
    "            # find the point in the lower hull that would minimize\n",
    "            # the slope between that point and s_upper. \n",
    "            resulting_slopes = [line(x, s_upper)[0] for x in self.__lower_hull]\n",
    "            idx = argmin(resulting_slopes)\n",
    "            self.__rho_upper = line(self.__lower_hull[idx], s_upper)\n",
    "            \n",
    "            # remove everything from the hull prior to that point, add new point\n",
    "            self.__lower_hull = self.__lower_hull[idx:]\n",
    "            self.__lower_hull.append(s_lower)\n",
    "            self.__lower_hull = update_hull(self.__lower_hull, upper=False)\n",
    "\n",
    "        \n",
    "        # if this point's lower bound is above the current rho_lower,\n",
    "        # we have to change rho_lower\n",
    "        if above(s_lower, self.__rho_lower):\n",
    "            # find the point in the upper hull that would maximize\n",
    "            # the slope between the point and s_lower\n",
    "            resulting_slopes = [line(x, s_lower)[0] for x in self.__upper_hull]\n",
    "            idx = argmax(resulting_slopes)\n",
    "            self.__rho_lower = line(self.__upper_hull[idx], s_lower)\n",
    "            \n",
    "            # remove everything from the hull prior to that point, add new point\n",
    "            self.__upper_hull = self.__upper_hull[idx:]\n",
    "            self.__upper_hull.append(s_upper)\n",
    "            self.__upper_hull = update_hull(self.__upper_hull)\n",
    "        \n",
    "        return None\n",
    "    \n",
    "    def finish(self):\n",
    "        if self.__state == \"need2\":\n",
    "            self.__state = \"finished\"\n",
    "            return None\n",
    "        elif self.__state == \"need1\":\n",
    "            self.__state = \"finished\"\n",
    "            return (self.__s0[0], self.__s0[0] + 1, 0, self.__s0[1])\n",
    "        elif self.__state == \"ready\":\n",
    "            self.__state = \"finished\"\n",
    "            return self.__current_segment()\n",
    "        else:\n",
    "            assert False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "plr = OptimalPLR(0.25)\n",
    "lines = []\n",
    "for pt in data:\n",
    "    l = plr.process(pt)\n",
    "    if l:\n",
    "        lines.append(l)\n",
    "    \n",
    "last = plr.finish()\n",
    "if last:\n",
    "    lines.append(last)\n",
    "len(lines)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "9"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "plr = OptimalPLR(0.025)\n",
    "lines2 = []\n",
    "for pt in data:\n",
    "    l = plr.process(pt)\n",
    "    if l:\n",
    "        lines2.append(l)\n",
    "    \n",
    "last = plr.finish()\n",
    "if last:\n",
    "    lines2.append(last)\n",
    "len(lines2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1440x360 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(20,5))\n",
    "\n",
    "\n",
    "plt.subplot(1, 3, 1)\n",
    "plt.scatter(x, y)\n",
    "plt.title(\"Original data (n=1000)\", size=20)\n",
    "plt.tick_params(axis='x', labelrotation=0, labelsize=16)\n",
    "plt.tick_params(axis='y', labelsize=16)\n",
    "\n",
    "plt.subplot(1, 3, 2)\n",
    "for l in lines:\n",
    "    xl = np.linspace(l[0], l[1], 100)\n",
    "    yl = l[2] * xl + l[3]\n",
    "    plt.scatter(xl, yl)\n",
    "plt.title(\"Optimal PLR, δ = 0.05 (7 segments)\", size=20)\n",
    "plt.tick_params(axis='x', labelrotation=0, labelsize=16)\n",
    "plt.tick_params(axis='y', labelsize=16)\n",
    "    \n",
    "plt.subplot(1, 3, 3)\n",
    "for l in lines2:\n",
    "    xl = np.linspace(l[0], l[1], 100)\n",
    "    yl = l[2] * xl + l[3]\n",
    "    plt.scatter(xl, yl)\n",
    "plt.title(\"Optimal PLR, δ = 0.005 (22 segments)\", size=20)\n",
    "plt.tick_params(axis='x', labelrotation=0, labelsize=16)\n",
    "plt.tick_params(axis='y', labelsize=16)\n",
    "plt.savefig(\"plot.png\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "from_rust = [\n",
    "(0, 0.224, 0.9925214438051018, 0.00014488723457774244),\n",
    "(0.224, 0.371, 0.9564359979470114, 0.00811544111468232),\n",
    "(0.371, 0.49000000000000005, 0.9098257927831952, 0.025184110625250444),\n",
    "(0.49000000000000005, 0.602, 0.8560902362553744, 0.051374096095132604),\n",
    "(0.602, 0.7000000000000001, 0.7973679477778012, 0.08644199332413038),\n",
    "(0.7000000000000001, 0.798, 0.7345403303455742, 0.13026493807044426),\n",
    "(0.798, 0.889, 0.6672938613391461, 0.18364968490552003),\n",
    "(0.889, 0.9800000000000001, 0.5968809282166496, 0.2460461759022603),\n",
    "(0.9800000000000001, 1.064, 0.52453963029918, 0.3166206305259157),\n",
    "(1.064, 1.1480000000000001, 0.4512773049507166, 0.3943392750949695),\n",
    "(1.1480000000000001, 1.232, 0.37483263881525447, 0.48185046990923225),\n",
    "(1.232, 1.316, 0.2957447083682151, 0.5790264497986415),\n",
    "(1.316, 1.4000000000000001, 0.21456509612801, 0.6855881183987156),\n",
    "(1.4000000000000001, 1.4769999999999999, 0.13535613338353905, 0.7961030925848586),\n",
    "(1.4769999999999999, 1.554, 0.05875237893886226, 0.9089827857523513),\n",
    "(1.554, 1.631, -0.018199546284158596, 1.0282975942267096),\n",
    "(1.631, 1.708, -0.09504361970083763, 1.153358954523449),\n",
    "(1.708, 1.792, -0.17476140876329194, 1.2893415834624926),\n",
    "(1.792, 1.8760000000000001, -0.25674332111792314, 1.4359537229597428),\n",
    "(1.8760000000000001, 1.9600000000000002, -0.3369097215772785, 1.5860507383639242),\n",
    "(1.9600000000000002, 2.044, -0.41470028452663665, 1.7382295287324734),\n",
    "(2.044, 2.128, -0.4895664424253739, 1.890971731375827),\n",
    "(2.128, 2.219, -0.5638422878887794, 2.0488442399382443),\n",
    "(2.219, 2.31, -0.6365330755574079, 2.20984715465532),\n",
    "(2.31, 2.408, -0.7064150208952986, 2.371076767650351),\n",
    "(2.408, 2.506, -0.7722395133713664, 2.529290458375451),\n",
    "(2.506, 2.6109999999999998, -0.832566340878024, 2.680265889786253),\n",
    "(2.6109999999999998, 2.73, -0.8890772083181679, 2.827667324426729),\n",
    "(2.73, 2.863, -0.9393402024298271, 2.9646838555034947),\n",
    "(2.863, 3.045, -0.980719181256966, 3.0830673326267295),\n",
    "(3.045, 3.346, -1.0587004536456222, 3.3386367109432715),\n",
    "(3.346, 3.5, -1.0194089527822754, 3.2163564540974594),\n",
    "(3.5, 3.6260000000000003, -0.969537899233178, 3.0490937912774494),\n",
    "(3.6260000000000003, 3.745, -0.9112648557380234, 2.8443939825940068),\n",
    "(3.745, 3.8500000000000005, -0.8470640051072593, 2.6097982889007594),\n",
    "(3.8500000000000005, 3.9549999999999996, -0.7778436510635867, 2.3488828625107105),\n",
    "(3.9549999999999996, 4.053, -0.7035404258383973, 2.0602635640493663),\n",
    "(4.053, 4.151, -0.6255241060600776, 1.7491566288953644),\n",
    "(4.151, 4.242, -0.5452012677617251, 1.420545750946877),\n",
    "(4.242, 4.333, -0.4637127145158647, 1.0795392357639941),\n",
    "(4.333, 4.424, -0.3788934556974868, 0.7166593459207461),\n",
    "(4.424, 4.515000000000001, -0.29144539501621314, 0.3344128066449319),\n",
    "(4.515000000000001, 4.606, -0.20211904114644377, -0.06428224649977465),\n",
    "(4.606, 4.69, -0.1151167858286416, -0.4606319398756733),\n",
    "(4.69, 4.774, -0.031174188126666322, -0.8500583320514762),\n",
    "(4.774, 4.858, 0.05256849223960554, -1.2455724883595696),\n",
    "(4.858, 4.949, 0.13893433546476147, -1.6606130712268432),\n",
    "(4.949, 5.04, 0.2271286146332705, -2.092412737173717),\n",
    "(5.04, 5.131, 0.3129166735955567, -2.520077948156951),\n",
    "(5.131, 5.2219999999999995, 0.3956086070533476, -2.939622030057251),\n",
    "(5.2219999999999995, 5.313, 0.4745201155249519, -3.346901263923985),\n",
    "(5.313, 5.4110000000000005, 0.5517095003597423, -3.751884706679768),\n",
    "(5.4110000000000005, 5.509, 0.6260229407482628, -4.148680392368301),\n",
    "(5.509, 5.614000000000001, 0.6958450294401022, -4.527636690886439),\n",
    "(5.614000000000001, 5.726, 0.761797755685506, -4.891664002832056),\n",
    "(5.726, 5.845, 0.8211801307009096, -5.224864212667721),\n",
    "(5.845, 5.984999999999999, 0.873255945628706, -5.52102481985113),\n",
    "(5.984999999999999, 6.167, 0.9148761058720644, -5.758745208484667),\n",
    "(6.167, 6.503, 0.9929896535897769, -6.239043539927865),\n",
    "(6.503, 6.6499999999999995, 0.9576396162376866, -6.009263861693788),\n",
    "(6.6499999999999995, 6.769, 0.9115503947797831, -5.702988862860086),\n",
    "(6.769, 6.881, 0.8582426830616655, -5.342287319093105),\n",
    "(6.881, 6.986, 0.7977272612145305, -4.926080687706908),\n",
    "(6.986, 6.993, 0.7607573751780505, -4.6682830946896905)\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.scatter(x, y)\n",
    "for l in from_rust:\n",
    "    xl = np.linspace(l[0], l[1], 100)\n",
    "    yl = l[2] * xl + l[3]\n",
    "    plt.scatter(xl, yl)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}