{"cells": [{"cell_type": "markdown", "metadata": {}, "source": ["# S\u00e9ries temporelles et map reduce\n", "\n", "Map/Reduce est un concept qui permet de distribuer les donn\u00e9es facilement si elles sont ind\u00e9pendantes. C'est une condition qu'une s\u00e9rie temporelle ne v\u00e9rifie pas du fait de la d\u00e9pendance temporelle. Voyons ce que cela change."]}, {"cell_type": "code", "execution_count": 1, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T15:12:27.577069", "start_time": "2016-11-06T15:12:27.568568"}}, "outputs": [{"data": {"text/html": ["
run previous cell, wait for 2 seconds
\n", ""], "text/plain": [""]}, "execution_count": 2, "metadata": {}, "output_type": "execute_result"}], "source": ["from jyquickhelper import add_notebook_menu\n", "add_notebook_menu()"]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": ["# R\u00e9pare une incompatibilit\u00e9 entre scipy 1.0 et statsmodels 0.8.\n", "from pymyinstall.fix import fix_scipy10_for_statsmodels08\n", "fix_scipy10_for_statsmodels08()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["On souhaite simplement calculer la d\u00e9riv\u00e9e de la s\u00e9rie temporelle : $\\Delta Y_t = Y_t - Y_{t-1}$."]}, {"cell_type": "code", "execution_count": 3, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:23:09.162438", "start_time": "2016-11-06T13:23:08.659707"}}, "outputs": [], "source": ["%matplotlib inline"]}, {"cell_type": "markdown", "metadata": {"ExecuteTime": {"end_time": "2016-11-05T23:12:25.652561", "start_time": "2016-11-05T23:12:25.627558"}}, "source": ["## Data"]}, {"cell_type": "code", "execution_count": 4, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:23:09.625559", "start_time": "2016-11-06T13:23:09.167444"}}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
DateHighLowOpenCloseVolumeAdj Close
Date
2020-12-242020-12-24223.610001221.199997221.419998222.75000010550600.0222.750000
2020-12-282020-12-28226.029999223.020004224.449997224.96000717933500.0224.960007
2020-12-292020-12-29227.179993223.580002226.309998224.14999417403200.0224.149994
2020-12-302020-12-30225.630005221.470001225.229996221.67999320272300.0221.679993
2020-12-312020-12-31223.000000219.679993221.699997222.41999820926900.0222.419998
\n", "
"], "text/plain": [" Date High Low Open Close \\\n", "Date \n", "2020-12-24 2020-12-24 223.610001 221.199997 221.419998 222.750000 \n", "2020-12-28 2020-12-28 226.029999 223.020004 224.449997 224.960007 \n", "2020-12-29 2020-12-29 227.179993 223.580002 226.309998 224.149994 \n", "2020-12-30 2020-12-30 225.630005 221.470001 225.229996 221.679993 \n", "2020-12-31 2020-12-31 223.000000 219.679993 221.699997 222.419998 \n", "\n", " Volume Adj Close \n", "Date \n", "2020-12-24 10550600.0 222.750000 \n", "2020-12-28 17933500.0 224.960007 \n", "2020-12-29 17403200.0 224.149994 \n", "2020-12-30 20272300.0 221.679993 \n", "2020-12-31 20926900.0 222.419998 "]}, "execution_count": 5, "metadata": {}, "output_type": "execute_result"}], "source": ["from pyensae.finance import StockPrices\n", "stock = StockPrices(\"MSFT\", folder=\".\", url=\"yahoo\")\n", "stock.tail()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["On cr\u00e9e une colonne suppl\u00e9mentaire pour l'indice $t$ de la s\u00e9rie temporelle :"]}, {"cell_type": "code", "execution_count": 5, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:23:09.646555", "start_time": "2016-11-06T13:23:09.629556"}}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Close
5279222.750000
5280224.960007
5281224.149994
5282221.679993
5283222.419998
\n", "
"], "text/plain": [" Close\n", "5279 222.750000\n", "5280 224.960007\n", "5281 224.149994\n", "5282 221.679993\n", "5283 222.419998"]}, "execution_count": 6, "metadata": {}, "output_type": "execute_result"}], "source": ["dt = stock.df()\n", "dt = dt[[\"Close\"]]\n", "dt = dt.reset_index(drop=True)\n", "data = dt\n", "dt.tail()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["La fonction [shift](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.shift.html) rend le calcul tr\u00e8s simple avec pandas."]}, {"cell_type": "code", "execution_count": 6, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:23:09.686066", "start_time": "2016-11-06T13:23:09.650558"}}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
CloseClose2delta
5279222.750000221.0200041.729996
5280224.960007222.7500002.210007
5281224.149994224.960007-0.810013
5282221.679993224.149994-2.470001
5283222.419998221.6799930.740005
\n", "
"], "text/plain": [" Close Close2 delta\n", "5279 222.750000 221.020004 1.729996\n", "5280 224.960007 222.750000 2.210007\n", "5281 224.149994 224.960007 -0.810013\n", "5282 221.679993 224.149994 -2.470001\n", "5283 222.419998 221.679993 0.740005"]}, "execution_count": 7, "metadata": {}, "output_type": "execute_result"}], "source": ["data_pandas = data.copy()\n", "data_pandas[\"Close2\"] = data.shift(1)\n", "data_pandas[\"delta\"] = data_pandas[\"Close\"] - data_pandas[\"Close2\"]\n", "data_pandas.tail()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["La fonction est tr\u00e8s rapide car elle utilise l'ordre des donn\u00e9es et son index. Pour s'en passer, on ajoute une colonne qui contient l'index original puis on m\u00e9lange pour simuler le fait qu'en map/reduce, l'ordre des informations n'est pas connu \u00e0 l'avance."]}, {"cell_type": "code", "execution_count": 7, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:23:09.719069", "start_time": "2016-11-06T13:23:09.689067"}}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
tclose
52794660104.190002
528047631.870001
5281352236.910000
5282286724.670000
5283434865.480003
\n", "
"], "text/plain": [" t close\n", "5279 4660 104.190002\n", "5280 476 31.870001\n", "5281 3522 36.910000\n", "5282 2867 24.670000\n", "5283 4348 65.480003"]}, "execution_count": 8, "metadata": {}, "output_type": "execute_result"}], "source": ["import numpy\n", "data = dt.reindex(numpy.random.permutation(data.index))\n", "data = data.reset_index(drop=False)\n", "data.columns = [\"t\", \"close\"]\n", "data.tail()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## D\u00e9riv\u00e9e avec pandas"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Le traitement de chaque ligne est ind\u00e9pendant et ne doit pas prendre en compte aucune autre ligne mais on a besoin de $Y_{t-1}$ pour calculer $\\Delta Y_t$. "]}, {"cell_type": "code", "execution_count": 8, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:23:09.744065", "start_time": "2016-11-06T13:23:09.723070"}}, "outputs": [], "source": ["data[\"tt\"] = data[\"t\"] - 1 "]}, {"cell_type": "markdown", "metadata": {}, "source": ["### m\u00e9thode efficace\n", "\n", "Lors d'une jointure, [pandas](http://pandas.pydata.org/) va trier chaque c\u00f4t\u00e9 de la jointure par ordre croissant de cl\u00e9. S'il y a $N$ observations, cela a un co\u00fbt de $N\\ln N$, il r\u00e9alise ensuite une fusion des deux bases en ne consid\u00e9rant que les lignes partageant la m\u00eame cl\u00e9. Cette fa\u00e7on de faire ne convient que lorsqu'on fait une jointure avec une condition n'incluant que des ET logique et des \u00e9galit\u00e9s."]}, {"cell_type": "code", "execution_count": 9, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:23:09.782092", "start_time": "2016-11-06T13:23:09.747575"}}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
tclosettt2close2tt2
52784660104.19000246594661105.4300004660
527947631.87000147547731.400000476
5280352236.9100003521352336.1300013522
5281286724.6700002866286824.7600002867
5282434865.4800034347434965.3899994348
\n", "
"], "text/plain": [" t close tt t2 close2 tt2\n", "5278 4660 104.190002 4659 4661 105.430000 4660\n", "5279 476 31.870001 475 477 31.400000 476\n", "5280 3522 36.910000 3521 3523 36.130001 3522\n", "5281 2867 24.670000 2866 2868 24.760000 2867\n", "5282 4348 65.480003 4347 4349 65.389999 4348"]}, "execution_count": 10, "metadata": {}, "output_type": "execute_result"}], "source": ["join = data.merge(data, left_on=\"t\", right_on=\"tt\", suffixes=(\"\", \"2\"))\n", "join.tail()"]}, {"cell_type": "code", "execution_count": 10, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:23:09.815090", "start_time": "2016-11-06T13:23:09.786095"}}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
tclosettt2close2tt2derivee
52784660104.19000246594661105.4300004660-1.239998
527947631.87000147547731.4000004760.470001
5280352236.9100003521352336.13000135220.779999
5281286724.6700002866286824.7600002867-0.090000
5282434865.4800034347434965.38999943480.090004
\n", "
"], "text/plain": [" t close tt t2 close2 tt2 derivee\n", "5278 4660 104.190002 4659 4661 105.430000 4660 -1.239998\n", "5279 476 31.870001 475 477 31.400000 476 0.470001\n", "5280 3522 36.910000 3521 3523 36.130001 3522 0.779999\n", "5281 2867 24.670000 2866 2868 24.760000 2867 -0.090000\n", "5282 4348 65.480003 4347 4349 65.389999 4348 0.090004"]}, "execution_count": 11, "metadata": {}, "output_type": "execute_result"}], "source": ["derivee = join.copy()\n", "derivee[\"derivee\"] = derivee[\"close\"] - derivee[\"close2\"]\n", "derivee.tail()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["En r\u00e9sum\u00e9 :"]}, {"cell_type": "code", "execution_count": 11, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:23:09.866116", "start_time": "2016-11-06T13:23:09.821092"}}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["(5283, 7)\n"]}, {"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
tclosettt2close2tt2derivee
52784660104.19000246614659101.98000346602.209999
527947631.87000147747532.570000476-0.699999
5280352236.9100003523352137.1600003522-0.250000
5281286724.6700002868286624.19000128670.480000
5282434865.4800034349434764.94999743480.530006
\n", "
"], "text/plain": [" t close tt t2 close2 tt2 derivee\n", "5278 4660 104.190002 4661 4659 101.980003 4660 2.209999\n", "5279 476 31.870001 477 475 32.570000 476 -0.699999\n", "5280 3522 36.910000 3523 3521 37.160000 3522 -0.250000\n", "5281 2867 24.670000 2868 2866 24.190001 2867 0.480000\n", "5282 4348 65.480003 4349 4347 64.949997 4348 0.530006"]}, "execution_count": 12, "metadata": {}, "output_type": "execute_result"}], "source": ["new_data = data.copy()\n", "new_data[\"tt\"] = new_data[\"t\"] + 1 # MAP\n", "new_data = new_data.merge(new_data, left_on=\"t\", right_on=\"tt\", suffixes=(\"\", \"2\")) # JOIN = SORT + MAP + REDUCE\n", "new_data[\"derivee\"] = new_data[\"close\"] - new_data[\"close2\"] # MAP\n", "print(new_data.shape)\n", "new_data.tail()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### mesure de co\u00fbt\n", "\n", "La s\u00e9rie n'est pas assez longue pour observer la relation entre le temps de calcul et le nombre d'observations."]}, {"cell_type": "code", "execution_count": 12, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:23:09.882625", "start_time": "2016-11-06T13:23:09.872114"}}, "outputs": [], "source": ["def derive(data):\n", " new_data = data.copy()\n", " new_data[\"tt\"] = new_data[\"t\"] + 1 # MAP\n", " new_data = new_data.merge(new_data, left_on=\"t\", right_on=\"tt\", suffixes=(\"\", \"2\")) # JOIN = MAP + REDUCE\n", " new_data[\"derivee\"] = new_data[\"close\"] - new_data[\"close2\"] # MAP\n", " return new_data"]}, {"cell_type": "markdown", "metadata": {}, "source": ["On choisit une r\u00e9gression lin\u00e9aire de type [HuberRegressor](http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.HuberRegressor.html#sklearn.linear_model.HuberRegressor) pour r\u00e9gresser $C(N) \\sim a N + b \\ln N + c N \\ln N + d$. Ce mod\u00e8le est beaucoup moins sensible aux points aberrants que les autres formes de r\u00e9gressions. On utilise cette r\u00e9gression avec le module [RobustLinearModels](http://statsmodels.sourceforge.net/stable/rlm.html) du module *statsmodels* pour calculer les p-values"]}, {"cell_type": "code", "execution_count": 13, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:23:15.446580", "start_time": "2016-11-06T13:23:09.886624"}, "scrolled": false}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["(92,) \n", " Robust linear Model Regression Results \n", "==============================================================================\n", "Dep. Variable: processing time No. Observations: 92\n", "Model: RLM Df Residuals: 88\n", "Method: IRLS Df Model: 3\n", "Norm: HuberT \n", "Scale Est.: mad \n", "Cov Type: H1 \n", "Date: Fri, 01 Jan 2021 \n", "Time: 03:27:54 \n", "No. Iterations: 50 \n", "==============================================================================\n", " coef std err z P>|z| [0.025 0.975]\n", "------------------------------------------------------------------------------\n", "logN 0.0035 0.001 2.661 0.008 0.001 0.006\n", "N -8.829e-06 2.77e-06 -3.191 0.001 -1.43e-05 -3.41e-06\n", "NlogN 2.117e-06 6.56e-07 3.228 0.001 8.31e-07 3.4e-06\n", "one -0.0049 0.003 -1.544 0.123 -0.011 0.001\n", "==============================================================================\n", "\n", "If the model instance has been used for another fit with different fit parameters, then the fit options might not be the correct ones anymore .\n"]}, {"data": {"image/png": "iVBORw0KGgoAAAANSUhEUgAAAYAAAAEJCAYAAACdePCvAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAAsTAAALEwEAmpwYAABXJUlEQVR4nO2deZxcZZnvv2+tvXcnnc4eyErIRgKEEPZdUFHQgZFt1JERR2FEHRG4oqPeywgzjssdYRxGGJUrOypRkMUBBCQs2SA72SHpLJ3u9N61v/ePc07VqVOnlu6upKpTz/fzqU+qTp1z6pxK1/u8z+9ZXqW1RhAEQag8PKW+AEEQBKE0iAEQBEGoUMQACIIgVChiAARBECoUMQCCIAgVihgAQRCECqUgA6CUukQptVkptVUpdZvL+0Gl1KPm+28qpaba3rvd3L5ZKXWxbftXlVLrlVLrlFIPK6WqinJHgiAIQkHkNQBKKS9wD/BhYC5wtVJqrmO364FDWuuZwI+Au81j5wJXAfOAS4B7lVJepdQk4MvAYq31fMBr7icIgiAcIXwF7LME2Kq13g6glHoEuAzYYNvnMuA75vMngJ8qpZS5/RGtdRjYoZTaap7vffOzq5VSUaAGaM13IWPGjNFTp04t4JIFQRAEgJUrVx7UWre4vVeIAZgEfGB7vRs4Nds+WuuYUqoLaDa3v+E4dpLWerlS6gcYhmAAeF5r/Xy+C5k6dSorVqwo4JIFQRAEAKXUrmzvlSQIrJQaheEdTAMmArVKqeuy7HuDUmqFUmpFW1vbkbxMQRCEo5pCDMAeYIrt9WRzm+s+Sikf0Ai05zj2QmCH1rpNax0FfgOc7vbhWuv7tNaLtdaLW1pcvRhBEARhCBRiAN4GZimlpimlAhjB2mWOfZYBnzGfXwG8qI0uc8uAq8wsoWnALOAtDOlnqVKqxowVXABsHP7tCIIgCIWSNwZgavo3Ac9hZOs8oLVer5T6HrBCa70MuB940AzydmBm9Jj7PYYRMI4BN2qt48CbSqkngFXm9tXAfcW/PUEQ8hGNRtm9ezehUKjUlyIMg6qqKiZPnozf7y/4GDWS2kEvXrxYSxBYEIrLjh07qK+vp7m5GcMhF0YaWmva29vp6elh2rRpae8ppVZqrRe7HSeVwIJQ4YRCIRn8RzhKKZqbmwftxYkBEARBBv+jgKH8H4oBEADoDcf4zardpb4MQRCOIGIABACWrWnla4+9w672vlJfiiCUDX/3d3/Hhg0b8u+Yh87OTu69997k69bWVq644ophn3e4iAEQANjXbWiHHX2REl+JILgTj8eP+Gf+/Oc/Z+5cZ+uzweM0ABMnTuSJJ54Y9nmHixgAAYC2HsMAdA5ES3wlQqWxc+dOjj/+eK699lrmzJnDFVdcQX9/P2C0f7n11ls56aSTePzxx3n44YdZsGAB8+fP59Zbb02e49lnn+Wkk05i4cKFXHDBBQD09fXxuc99jiVLlnDiiSfy1FNPAbB+/XqWLFnCokWLOOGEE9iyZQt9fX189KMfZeHChcyfP59HH30UgHPPPTfZfqauro5vfvObLFy4kKVLl7J//34Atm3bxtKlS1mwYAF33HEHdXV1Gfd42223sW3bNhYtWsQtt9zCzp07mT9/PgC/+MUvuPzyy7nooouYOnUqP/3pT/nhD3/IiSeeyNKlS+no6Eh+ziWXXMLJJ5/MWWedxaZNm4b93RfSC0ioANp6wgB09YsBqGS++/v1bGjtLuo5505s4J8+Ni/nPps3b+b+++/njDPO4HOf+xz33nsvX//61wFobm5m1apVtLa2snTpUlauXMmoUaP40Ic+xO9+9zvOOOMMPv/5z/PKK68wbdq05IB55513cv755/PAAw/Q2dnJkiVLuPDCC/nZz37GzTffzLXXXkskEiEej/PMM88wceJEnn76aQC6uroyrrGvr4+lS5dy55138o1vfIP/+q//4o477uDmm2/m5ptv5uqrr+ZnP/uZ6/3dddddrFu3jjVr1gCG0bOzbt06Vq9eTSgUYubMmdx9992sXr2ar371q/zqV7/iK1/5CjfccAM/+9nPmDVrFm+++SZf+tKXePHFFwfzX5GBeAACAAdMA9DZLxKQcOSZMmUKZ5xxBgDXXXcdr732WvK9T33qUwC8/fbbnHvuubS0tODz+bj22mt55ZVXeOONNzj77LOT+e+jR48G4Pnnn+euu+5i0aJFnHvuuYRCId5//31OO+00/vmf/5m7776bXbt2UV1dzYIFC3jhhRe49dZbefXVV2lsbMy4xkAgwKWXXgrAySefnBzEly9fzpVXXgnANddcM6T7P++886ivr6elpYXGxkY+9rGPAbBgwQJ27txJb28vr7/+OldeeSWLFi3iC1/4Anv37h3SZ9kR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\n", "text/plain": ["
"]}, "metadata": {"needs_background": "light"}, "output_type": "display_data"}], "source": ["import time, pandas, numpy, sklearn.linear_model as lin\n", "import matplotlib.pyplot as plt\n", "import statsmodels.api as smapi\n", "from random import randint\n", "\n", "def graph_cout(data, h=100, nb=10, add_n2=False, derive=derive):\n", " dh = len(data) // h\n", " res = []\n", " for n in range(max(dh, 500), len(data), dh):\n", " df = data[0:n+randint(-10,10)]\n", " mean = []\n", " for i in range(0, nb):\n", " t = time.perf_counter()\n", " derive(df)\n", " dt = time.perf_counter() - t\n", " mean.append(dt)\n", " res.append((n, mean[len(mean)//2]))\n", " # stat\n", " stat = pandas.DataFrame(res, columns=[\"N\", \"processing time\"])\n", " stat[\"logN\"] = numpy.log(stat[\"N\"]) / numpy.log(10)\n", " stat[\"NlogN\"] = stat[\"N\"] * stat[\"logN\"]\n", " stat[\"N2\"] = stat[\"N\"] * stat[\"N\"]\n", " # statsmodels\n", " stat[\"one\"] = 1\n", " X = stat[[\"logN\", \"N\", \"NlogN\", \"N2\", \"one\"]]\n", " if not add_n2:\n", " X = X.drop(\"N2\", axis=1)\n", " rlm_model = smapi.RLM(stat[\"processing time\"], X, M=smapi.robust.norms.HuberT())\n", " rlm_results = rlm_model.fit()\n", " yp = rlm_results.predict(X)\n", " print(yp.shape, type(yp))\n", " stat[\"smooth\"] = yp\n", " # graph\n", " fig, ax = plt.subplots()\n", " stat.plot(x=\"N\", y=[\"processing time\", \"smooth\"], ax=ax)\n", " return ax, rlm_results\n", "\n", "ax, results = graph_cout(data)\n", "print(results.summary())\n", "ax;"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Le co\u00fbt de l'algorithme est au moins lin\u00e9aire. Cela signifie que le co\u00fbt du calcul qu'on cherche \u00e0 mesurer est noy\u00e9 dans plein d'autres choses non n\u00e9gligeable. La valeur des coefficients n'indique pas grand chose car les variables $N$, $Nlog N$ \u00e9voluent sur des \u00e9chelles diff\u00e9rentes."]}, {"cell_type": "code", "execution_count": 14, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:24:13.215086", "start_time": "2016-11-06T13:23:15.449584"}}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["(24,) \n", " Robust linear Model Regression Results \n", "==============================================================================\n", "Dep. Variable: processing time No. Observations: 24\n", "Model: RLM Df Residuals: 20\n", "Method: IRLS Df Model: 3\n", "Norm: HuberT \n", "Scale Est.: mad \n", "Cov Type: H1 \n", "Date: Fri, 01 Jan 2021 \n", "Time: 03:28:04 \n", "No. Iterations: 47 \n", "==============================================================================\n", " coef std err z P>|z| [0.025 0.975]\n", "------------------------------------------------------------------------------\n", "logN -0.0396 0.017 -2.327 0.020 -0.073 -0.006\n", "N 5.63e-06 1.75e-06 3.213 0.001 2.2e-06 9.06e-06\n", "NlogN -9.342e-07 3.08e-07 -3.036 0.002 -1.54e-06 -3.31e-07\n", "one 0.1434 0.064 2.232 0.026 0.017 0.269\n", "==============================================================================\n", "\n", "If the model instance has been used for another fit with different fit parameters, then the fit options might not be the correct ones anymore .\n"]}, {"data": {"image/png": "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\n", "text/plain": ["
"]}, "metadata": {"needs_background": "light"}, "output_type": "display_data"}], "source": ["N = 200000\n", "from random import random\n", "data2 = pandas.DataFrame({\"t\":range(0,N), \"close\": [random() for i in range(0, N)]})\n", "ax, stats = graph_cout(data2, h=25)\n", "print(stats.summary())\n", "ax;"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Les r\u00e9sultats sont assez volatiles. Il faut regarder les intervalles de confiance et regarder lesquels n'incluent pas 0."]}, {"cell_type": "markdown", "metadata": {}, "source": ["### m\u00e9thode inefficace\n", "\n", "Dans ce cas, on fait un produit en croix de toutes les lignes de la bases avec elles-m\u00eame puis on filtre le r\u00e9sultat pour ne garder que les lignes qui v\u00e9rifient la condition souhait\u00e9e quelle qu'elle soit. Le temps d'ex\u00e9cution est en $O(N^2)$ et la diff\u00e9rence est vite significative."]}, {"cell_type": "code", "execution_count": 15, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:24:15.953347", "start_time": "2016-11-06T13:24:13.219084"}}, "outputs": [{"data": {"text/plain": ["(27920656, 7)"]}, "execution_count": 16, "metadata": {}, "output_type": "execute_result"}], "source": ["new_data2 = data.copy()\n", "new_data2[\"tt\"] = new_data2[\"t\"] + 1 # MAP\n", "new_data2[\"key\"] = 1\n", "new_data2 = new_data2.merge(new_data2, on=\"key\", suffixes=(\"\", \"2\")) # JOIN = MAP^2\n", "new_data2.shape"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [{"data": {"text/plain": ["(5284, 7)"]}, "execution_count": 17, "metadata": {}, "output_type": "execute_result"}], "source": ["mapind = new_data2.t == new_data2.t2\n", "new_data2 = new_data2[mapind] # MAP\n", "new_data2.shape"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
tclosettkeyt2close2tt2derivee
278995154660104.190002466114660104.19000246610
2790480047631.870001477147631.8700014770
27910085352236.91000035231352236.91000035230
27915370286724.67000028681286724.67000028680
27920655434865.48000343491434865.48000343490
\n", "
"], "text/plain": [" t close tt key t2 close2 tt2 derivee\n", "27899515 4660 104.190002 4661 1 4660 104.190002 4661 0\n", "27904800 476 31.870001 477 1 476 31.870001 477 0\n", "27910085 3522 36.910000 3523 1 3522 36.910000 3523 0\n", "27915370 2867 24.670000 2868 1 2867 24.670000 2868 0\n", "27920655 4348 65.480003 4349 1 4348 65.480003 4349 0"]}, "execution_count": 18, "metadata": {}, "output_type": "execute_result"}], "source": ["new_data2[\"derivee\"] = new_data2[\"t\"] - new_data2[\"t2\"] # MAP\n", "new_data2.tail()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### mesure de co\u00fbt inefficace"]}, {"cell_type": "code", "execution_count": 18, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:24:58.448545", "start_time": "2016-11-06T13:24:15.957346"}}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["(10,) \n", " Robust linear Model Regression Results \n", "==============================================================================\n", "Dep. Variable: processing time No. Observations: 10\n", "Model: RLM Df Residuals: 5\n", "Method: IRLS Df Model: 4\n", "Norm: HuberT \n", "Scale Est.: mad \n", "Cov Type: H1 \n", "Date: Fri, 01 Jan 2021 \n", "Time: 03:29:44 \n", "No. Iterations: 50 \n", "==============================================================================\n", " coef std err z P>|z| [0.025 0.975]\n", "------------------------------------------------------------------------------\n", "logN -3.5525 6.675 -0.532 0.595 -16.635 9.530\n", "N 0.0226 0.027 0.837 0.403 -0.030 0.076\n", "NlogN -0.0064 0.007 -0.889 0.374 -0.021 0.008\n", "N2 6.411e-07 3.49e-07 1.836 0.066 -4.32e-08 1.33e-06\n", "one 6.8518 14.218 0.482 0.630 -21.015 34.718\n", "==============================================================================\n", "\n", "If the model instance has been used for another fit with different fit parameters, then the fit options might not be the correct ones anymore .\n"]}, {"data": {"image/png": "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\n", "text/plain": ["
"]}, "metadata": {"needs_background": "light"}, "output_type": "display_data"}], "source": ["def derive_inefficace(data):\n", " new_data2 = data.copy()\n", " new_data2[\"tt\"] = new_data2[\"t\"] + 1\n", " new_data2[\"key\"] = 1\n", " new_data2 = new_data2.merge(new_data2, on=\"key\", suffixes=(\"\", \"2\"))\n", " new_data2 = new_data2[new_data2.t == new_data2.t2]\n", " new_data2[\"derivee\"] = new_data2[\"t\"] - new_data2[\"t2\"] # MAP\n", " return new_data2\n", "\n", "ax, stats = graph_cout(data, h=10, nb=5, derive=derive_inefficace, add_n2=True)\n", "print(stats.summary())\n", "ax;"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## avec des it\u00e9rateurs"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### version efficace"]}, {"cell_type": "code", "execution_count": 19, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T14:28:54.413236", "start_time": "2016-11-06T14:28:54.393235"}}, "outputs": [{"data": {"text/plain": ["[Pandas(Index=0, t=1726, close=29.350000381469727),\n", " Pandas(Index=1, t=1244, close=27.11000061035156)]"]}, "execution_count": 20, "metadata": {}, "output_type": "execute_result"}], "source": ["rows = data[[\"t\", \"close\"]].itertuples()\n", "list(rows)[:2]"]}, {"cell_type": "code", "execution_count": 20, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T14:30:53.321677", "start_time": "2016-11-06T14:30:53.295149"}}, "outputs": [{"data": {"text/plain": ["[(1726, 29.350000381469727, 1727), (1244, 27.11000061035156, 1245)]"]}, "execution_count": 21, "metadata": {}, "output_type": "execute_result"}], "source": ["rows = data[[\"t\", \"close\"]].itertuples()\n", "rows = map(lambda r: (r.t, r.close, r.t+1), rows)\n", "list(rows)[:2]"]}, {"cell_type": "code", "execution_count": 21, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T14:57:34.789576", "start_time": "2016-11-06T14:57:34.640557"}}, "outputs": [{"data": {"text/plain": ["[(1725, 0.1100006103515625),\n", " (1243, -0.11999893188476918),\n", " (3128, -0.75),\n", " (4095, 0.29000091552734375)]"]}, "execution_count": 22, "metadata": {}, "output_type": "execute_result"}], "source": ["import copy\n", "from cytoolz.itertoolz import join\n", "\n", "def get_iterrows():\n", " rows_as_tuple = data[[\"t\", \"close\"]].itertuples()\n", " rows = map(lambda r: (r.t, r.close, r.t+1), rows_as_tuple)\n", " return rows\n", "\n", "rows1 = get_iterrows()\n", "rows2 = get_iterrows()\n", "rows = join(lambda t: t[2], rows1, lambda t: t[0], rows2)\n", "rows = map(lambda tu: tu[0] + tu[1], rows)\n", "rows = map(lambda row: (row[0], row[4] - row[1]), rows)\n", "results = list(rows)\n", "results[:4]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### version inefficace\n", "\n", "La m\u00e9thode inefficace avec *pandas* est particuli\u00e8rement inefficace car elle n\u00e9cessite de stocker un tableau interm\u00e9diaire qui contient $N^2$ lignes."]}, {"cell_type": "code", "execution_count": 22, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T15:12:15.082471", "start_time": "2016-11-06T15:12:04.361340"}}, "outputs": [{"data": {"text/plain": ["[(1725, 0.1100006103515625),\n", " (1243, -0.11999893188476918),\n", " (3128, -0.75),\n", " (4095, 0.29000091552734375)]"]}, "execution_count": 23, "metadata": {}, "output_type": "execute_result"}], "source": ["import copy\n", "from cytoolz.itertoolz import join\n", "\n", "def get_iterrows():\n", " rows_as_tuple = data[[\"t\", \"close\"]].itertuples()\n", " rows = map(lambda r: (r.t, r.close, r.t+1, 1), rows_as_tuple) # on ajoute 1\n", " return rows\n", "\n", "rows1 = get_iterrows()\n", "rows2 = get_iterrows()\n", "rows = join(lambda t: t[-1], rows1, lambda t: t[-1], rows2) # on fait un produit crois\u00e9\n", "rows = map(lambda tu: tu[0] + tu[1], rows)\n", "rows = filter(lambda t: t[2] == t[4], rows) # on filtre les lignes qui nous int\u00e9resse\n", "rows = map(lambda row: (row[0], row[5] - row[1]), rows)\n", "results = list(rows) # c'est tr\u00e8s lent\n", "results[:4]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## avec SQL"]}, {"cell_type": "markdown", "metadata": {"collapsed": true}, "source": ["### conversion du dataframe au format SQL"]}, {"cell_type": "code", "execution_count": 23, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:24:58.489537", "start_time": "2016-11-06T13:24:58.452506"}}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
tDateHighLowOpenCloseVolumeAdj_Close
002000-01-0359.312556.0000058.6875058.2812553228400.037.102634
112000-01-0458.562556.1250056.7812556.3125054119000.035.849308
222000-01-0558.187554.6875055.5625056.9062564059600.036.227283
332000-01-0656.937554.1875056.0937555.0000054976600.035.013741
442000-01-0756.125053.6562554.3125055.7187562013600.035.471302
\n", "
"], "text/plain": [" t Date High Low Open Close Volume Adj_Close\n", "0 0 2000-01-03 59.3125 56.00000 58.68750 58.28125 53228400.0 37.102634\n", "1 1 2000-01-04 58.5625 56.12500 56.78125 56.31250 54119000.0 35.849308\n", "2 2 2000-01-05 58.1875 54.68750 55.56250 56.90625 64059600.0 36.227283\n", "3 3 2000-01-06 56.9375 54.18750 56.09375 55.00000 54976600.0 35.013741\n", "4 4 2000-01-07 56.1250 53.65625 54.31250 55.71875 62013600.0 35.471302"]}, "execution_count": 24, "metadata": {}, "output_type": "execute_result"}], "source": ["data = stock.df()\n", "data.columns = [_.replace(\" \", \"_\") for _ in data.columns]\n", "data = data.reset_index(drop=True).reset_index(drop=False)\n", "data.columns = [\"t\"] + list(data.columns[1:])\n", "data.head()"]}, {"cell_type": "code", "execution_count": 24, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:24:58.636631", "start_time": "2016-11-06T13:24:58.493037"}}, "outputs": [], "source": ["import sqlite3\n", "con = sqlite3.connect(\":memory:\")\n", "tbl = data.to_sql(\"stock\", con, index=False)"]}, {"cell_type": "code", "execution_count": 25, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:24:59.346212", "start_time": "2016-11-06T13:24:58.640635"}}, "outputs": [], "source": ["%load_ext pyensae"]}, {"cell_type": "code", "execution_count": 26, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:24:59.365223", "start_time": "2016-11-06T13:24:59.349206"}}, "outputs": [{"data": {"text/plain": ["['stock']"]}, "execution_count": 27, "metadata": {}, "output_type": "execute_result"}], "source": ["%SQL_tables -v con"]}, {"cell_type": "code", "execution_count": 27, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:24:59.411221", "start_time": "2016-11-06T13:24:59.369223"}}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
tDateHighLowOpenCloseVolumeAdj_Close
002000-01-0359.312556.0000058.6875058.2812553228400.037.102634
112000-01-0458.562556.1250056.7812556.3125054119000.035.849308
222000-01-0558.187554.6875055.5625056.9062564059600.036.227283
332000-01-0656.937554.1875056.0937555.0000054976600.035.013741
442000-01-0756.125053.6562554.3125055.7187562013600.035.471302
\n", "
"], "text/plain": [" t Date High Low Open Close Volume Adj_Close\n", "0 0 2000-01-03 59.3125 56.00000 58.68750 58.28125 53228400.0 37.102634\n", "1 1 2000-01-04 58.5625 56.12500 56.78125 56.31250 54119000.0 35.849308\n", "2 2 2000-01-05 58.1875 54.68750 55.56250 56.90625 64059600.0 36.227283\n", "3 3 2000-01-06 56.9375 54.18750 56.09375 55.00000 54976600.0 35.013741\n", "4 4 2000-01-07 56.1250 53.65625 54.31250 55.71875 62013600.0 35.471302"]}, "execution_count": 28, "metadata": {}, "output_type": "execute_result"}], "source": ["%%SQL -v con\n", "\n", "SELECT * FROM stock LIMIT 5"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### version efficace\n", "\n", "L'instruction ``ON`` pr\u00e9cise sur quelle ou quelles colonnes op\u00e9rer la fusion. "]}, {"cell_type": "code", "execution_count": 28, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T13:27:01.936905", "start_time": "2016-11-06T13:27:01.874362"}}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
tClosettt2Close2tt2
0058.281251156.312502
1156.312502256.906253
2256.906253355.000004
3355.000004455.718755
4455.718755556.125006
5556.125006654.687507
6654.687507752.906258
7752.906258853.906259
8853.906259956.1250010
9956.12500101057.6562511
\n", "
"], "text/plain": [" t Close tt t2 Close2 tt2\n", "0 0 58.28125 1 1 56.31250 2\n", "1 1 56.31250 2 2 56.90625 3\n", "2 2 56.90625 3 3 55.00000 4\n", "3 3 55.00000 4 4 55.71875 5\n", "4 4 55.71875 5 5 56.12500 6\n", "5 5 56.12500 6 6 54.68750 7\n", "6 6 54.68750 7 7 52.90625 8\n", "7 7 52.90625 8 8 53.90625 9\n", "8 8 53.90625 9 9 56.12500 10\n", "9 9 56.12500 10 10 57.65625 11"]}, "execution_count": 29, "metadata": {}, "output_type": "execute_result"}], "source": ["%%SQL -v con\n", "\n", "SELECT A.t AS t, A.Close AS Close, A.tt AS tt,\n", " B.t AS t2, B.Close AS Close2, B.tt AS tt2\n", "FROM (\n", " SELECT t, Close, t+1 AS tt FROM stock\n", " ) AS A\n", "INNER JOIN (\n", " SELECT t, Close, t+1 AS tt FROM stock\n", " ) AS B\n", "ON A.tt == B.t"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### version inefficace\n", "\n", "Pour la version inefficace, l'instruction ``JOIN`` effectue tous les combinaisons de lignes possibles, soit $N^2$. Le mot-cl\u00e9 ``WHERE`` garde les couples de lignes qui nous int\u00e9resse."]}, {"cell_type": "code", "execution_count": 29, "metadata": {"ExecuteTime": {"end_time": "2016-11-06T14:08:43.948081", "start_time": "2016-11-06T14:08:41.336898"}}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
tClosettt2Close2tt2
0058.281251156.312502
1156.312502256.906253
2256.906253355.000004
3355.000004455.718755
4455.718755556.125006
5556.125006654.687507
6654.687507752.906258
7752.906258853.906259
8853.906259956.1250010
9956.12500101057.6562511
\n", "
"], "text/plain": [" t Close tt t2 Close2 tt2\n", "0 0 58.28125 1 1 56.31250 2\n", "1 1 56.31250 2 2 56.90625 3\n", "2 2 56.90625 3 3 55.00000 4\n", "3 3 55.00000 4 4 55.71875 5\n", "4 4 55.71875 5 5 56.12500 6\n", "5 5 56.12500 6 6 54.68750 7\n", "6 6 54.68750 7 7 52.90625 8\n", "7 7 52.90625 8 8 53.90625 9\n", "8 8 53.90625 9 9 56.12500 10\n", "9 9 56.12500 10 10 57.65625 11"]}, "execution_count": 30, "metadata": {}, "output_type": "execute_result"}], "source": ["%%SQL -v con\n", "\n", "SELECT A.t AS t, A.Close AS Close, A.tt AS tt,\n", " B.t AS t2, B.Close AS Close2, B.tt AS tt2\n", "FROM (\n", " SELECT t, Close, t+1 AS tt FROM stock\n", " ) AS A\n", "INNER JOIN (\n", " SELECT t, Close, t+1 AS tt FROM stock\n", " ) AS B\n", "WHERE A.tt >= B.t AND A.tt <= B.t -- on \u00e9crit l'\u00e9galit\u00e9 comme ceci pour contourner les optimisations\n", " -- r\u00e9alis\u00e9e par SQLlite"]}, {"cell_type": "code", "execution_count": 30, "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.9.1"}}, "nbformat": 4, "nbformat_minor": 2}