{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import pandas as pd" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Error reading the parquet file\n" ] } ], "source": [ "try:\n", " markets = pd.read_parquet(\"../data/fpmms.parquet\")\n", "except Exception:\n", " print(\"Error reading the parquet file\")\n", "\n", "# markets[\"currentAnswer\"] = markets[\"currentAnswer\"].apply(lambda x: x.lower())\n", "# # filter only markets with yes, no answers\n", "# valid_answers = [\"yes\", \"no\"]\n", "# markets = markets.loc[markets[\"currentAnswer\"].isin(valid_answers)]" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "try:\n", " markets_df = pd.read_parquet(\"../data/fpmmTrades.parquet\")\n", "except Exception:\n", " print(\"Error reading the parquet file\")" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "RangeIndex: 85876 entries, 0 to 85875\n", "Data columns (total 24 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 collateralAmount 85876 non-null object\n", " 1 collateralAmountUSD 85876 non-null object\n", " 2 collateralToken 85876 non-null object\n", " 3 creationTimestamp 85876 non-null object\n", " 4 trader_address 85876 non-null object\n", " 5 feeAmount 85876 non-null object\n", " 6 id 85876 non-null object\n", " 7 oldOutcomeTokenMarginalPrice 85876 non-null object\n", " 8 outcomeIndex 85876 non-null object\n", " 9 outcomeTokenMarginalPrice 85876 non-null object\n", " 10 outcomeTokensTraded 85876 non-null object\n", " 11 title 85876 non-null object\n", " 12 transactionHash 85876 non-null object\n", " 13 type 85876 non-null object\n", " 14 market_creator 85876 non-null object\n", " 15 fpmm.answerFinalizedTimestamp 54399 non-null object\n", " 16 fpmm.arbitrationOccurred 85876 non-null bool \n", " 17 fpmm.currentAnswer 54399 non-null object\n", " 18 fpmm.id 85876 non-null object\n", " 19 fpmm.isPendingArbitration 85876 non-null bool \n", " 20 fpmm.openingTimestamp 85876 non-null object\n", " 21 fpmm.outcomes 85876 non-null object\n", " 22 fpmm.title 85876 non-null object\n", " 23 fpmm.condition.id 85876 non-null object\n", "dtypes: bool(2), object(22)\n", "memory usage: 14.6+ MB\n" ] } ], "source": [ "markets_df.info()" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['collateralAmount', 'collateralAmountUSD', 'collateralToken',\n", " 'creationTimestamp', 'trader_address', 'feeAmount', 'id',\n", " 'oldOutcomeTokenMarginalPrice', 'outcomeIndex',\n", " 'outcomeTokenMarginalPrice', 'outcomeTokensTraded', 'title',\n", " 'transactionHash', 'type', 'market_creator',\n", " 'fpmm.answerFinalizedTimestamp', 'fpmm.arbitrationOccurred',\n", " 'fpmm.currentAnswer', 'fpmm.id', 'fpmm.isPendingArbitration',\n", " 'fpmm.openingTimestamp', 'fpmm.outcomes', 'fpmm.title',\n", " 'fpmm.condition.id'],\n", " dtype='object')" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "markets_df.columns" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "len(markets.id.unique())" ] }, { "cell_type": "code", "execution_count": 5, "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", "
currentAnsweridtitlemarket_creator
0no0x0017cd58d6a7ee1451388c7d5b1051b4c0a041f5Will the first floating offshore wind research...quickstart
1no0x0020d13c89140b47e10db54cbd53852b90bc1391Will the Francis Scott Key Bridge in Baltimore...quickstart
2no0x003ae5e007cc38b3f86b0ed7c82f938a1285ac07Will FC Saarbrucken reach the final of the Ger...quickstart
3yes0x004c8d4c619dc6b9caa940f5ea7ef699ae85359cWill the pro-life activists convicted for 'con...quickstart
4yes0x005e3f7a90585acbec807425a750fbba1d0c2b5cWill Apple announce the release of a new M4 ch...quickstart
\n", "
" ], "text/plain": [ " currentAnswer id \\\n", "0 no 0x0017cd58d6a7ee1451388c7d5b1051b4c0a041f5 \n", "1 no 0x0020d13c89140b47e10db54cbd53852b90bc1391 \n", "2 no 0x003ae5e007cc38b3f86b0ed7c82f938a1285ac07 \n", "3 yes 0x004c8d4c619dc6b9caa940f5ea7ef699ae85359c \n", "4 yes 0x005e3f7a90585acbec807425a750fbba1d0c2b5c \n", "\n", " title market_creator \n", "0 Will the first floating offshore wind research... quickstart \n", "1 Will the Francis Scott Key Bridge in Baltimore... quickstart \n", "2 Will FC Saarbrucken reach the final of the Ger... quickstart \n", "3 Will the pro-life activists convicted for 'con... quickstart \n", "4 Will Apple announce the release of a new M4 ch... quickstart " ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "markets.head()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "trades = pd.read_parquet(\"../data/fpmmTrades.parquet\")" ] }, { "cell_type": "code", "execution_count": 9, "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
collateralAmountcollateralAmountUSDcollateralTokencreationTimestamptrader_addressfeeAmountidoldOutcomeTokenMarginalPriceoutcomeIndexoutcomeTokenMarginalPrice...market_creatorfpmm.answerFinalizedTimestampfpmm.arbitrationOccurredfpmm.currentAnswerfpmm.idfpmm.isPendingArbitrationfpmm.openingTimestampfpmm.outcomesfpmm.titlefpmm.condition.id
09305967650456174080.93059779934117533864348280336664730xe91d153e0b41518a2ce8dd3d7944fa863463a97d17285966050x01274796ce41aa8e8312e05a427ffb4b0d2148f693059676504561740x007068173910cf8719b6f2e66a18b6825c9dde820x01...0.558111979762980196833836180241856400.611825749650855211231211687533889...quickstart1728822710False0x00000000000000000000000000000000000000000000...0x007068173910cf8719b6f2e66a18b6825c9dde82False1728691200[Yes, No]Will the emergency public warning tests planne...0xa610166e379c42404bd27bf12a16119fdb5171990c3e...
110332472347961938001.0332501260033394937910329936745250xe91d153e0b41518a2ce8dd3d7944fa863463a97d17285055750x034c4ad84f7ac6638bf19300d5bbe7d9b981e736103324723479619380x007068173910cf8719b6f2e66a18b6825c9dde820x03...0.660208990298303445124446130809070700.7034159692833852946883644485233207...quickstart1728822710False0x00000000000000000000000000000000000000000000...0x007068173910cf8719b6f2e66a18b6825c9dde82False1728691200[Yes, No]Will the emergency public warning tests planne...0xa610166e379c42404bd27bf12a16119fdb5171990c3e...
212066923688428983001.2066915962481879683670637170788840xe91d153e0b41518a2ce8dd3d7944fa863463a97d17285628950x05e8bbdb89c84a14d05194bbbae81caf2340db72120669236884289830x007068173910cf8719b6f2e66a18b6825c9dde820x05...0.193145918304372186430986421068454610.3033804066591317111055858533563476...quickstart1728822710False0x00000000000000000000000000000000000000000000...0x007068173910cf8719b6f2e66a18b6825c9dde82False1728691200[Yes, No]Will the emergency public warning tests planne...0xa610166e379c42404bd27bf12a16119fdb5171990c3e...
39305982032745443840.93059923757170080912179287297934220xe91d153e0b41518a2ce8dd3d7944fa863463a97d17285966450x17c17ca981b7e244d0bad80b632a082dc1db36e593059820327454430x007068173910cf8719b6f2e66a18b6825c9dde820x17...0.61182574965085521123121168753388900.6579972404391247884756597316198778...quickstart1728822710False0x00000000000000000000000000000000000000000000...0x007068173910cf8719b6f2e66a18b6825c9dde82False1728691200[Yes, No]Will the emergency public warning tests planne...0xa610166e379c42404bd27bf12a16119fdb5171990c3e...
417986959651029184001.7986967959313423139361257822752250xe91d153e0b41518a2ce8dd3d7944fa863463a97d17283377800x1d942103400c1f1657dcbffd5e08904787ea936b179869596510291840x007068173910cf8719b6f2e66a18b6825c9dde820x1d...0.763615736941978768175557728675570300.8080447772492735383356100969932859...quickstart1728822710False0x00000000000000000000000000000000000000000000...0x007068173910cf8719b6f2e66a18b6825c9dde82False1728691200[Yes, No]Will the emergency public warning tests planne...0xa610166e379c42404bd27bf12a16119fdb5171990c3e...
\n", "

5 rows × 24 columns

\n", "
" ], "text/plain": [ " collateralAmount collateralAmountUSD \\\n", "0 930596765045617408 0.9305977993411753386434828033666473 \n", "1 1033247234796193800 1.033250126003339493791032993674525 \n", "2 1206692368842898300 1.206691596248187968367063717078884 \n", "3 930598203274544384 0.9305992375717008091217928729793422 \n", "4 1798695965102918400 1.798696795931342313936125782275225 \n", "\n", " collateralToken creationTimestamp \\\n", "0 0xe91d153e0b41518a2ce8dd3d7944fa863463a97d 1728596605 \n", "1 0xe91d153e0b41518a2ce8dd3d7944fa863463a97d 1728505575 \n", "2 0xe91d153e0b41518a2ce8dd3d7944fa863463a97d 1728562895 \n", "3 0xe91d153e0b41518a2ce8dd3d7944fa863463a97d 1728596645 \n", "4 0xe91d153e0b41518a2ce8dd3d7944fa863463a97d 1728337780 \n", "\n", " trader_address feeAmount \\\n", "0 0x01274796ce41aa8e8312e05a427ffb4b0d2148f6 9305967650456174 \n", "1 0x034c4ad84f7ac6638bf19300d5bbe7d9b981e736 10332472347961938 \n", "2 0x05e8bbdb89c84a14d05194bbbae81caf2340db72 12066923688428983 \n", "3 0x17c17ca981b7e244d0bad80b632a082dc1db36e5 9305982032745443 \n", "4 0x1d942103400c1f1657dcbffd5e08904787ea936b 17986959651029184 \n", "\n", " id \\\n", "0 0x007068173910cf8719b6f2e66a18b6825c9dde820x01... \n", "1 0x007068173910cf8719b6f2e66a18b6825c9dde820x03... \n", "2 0x007068173910cf8719b6f2e66a18b6825c9dde820x05... \n", "3 0x007068173910cf8719b6f2e66a18b6825c9dde820x17... \n", "4 0x007068173910cf8719b6f2e66a18b6825c9dde820x1d... \n", "\n", " oldOutcomeTokenMarginalPrice outcomeIndex \\\n", "0 0.5581119797629801968338361802418564 0 \n", "1 0.6602089902983034451244461308090707 0 \n", "2 0.1931459183043721864309864210684546 1 \n", "3 0.611825749650855211231211687533889 0 \n", "4 0.7636157369419787681755577286755703 0 \n", "\n", " outcomeTokenMarginalPrice ... market_creator \\\n", "0 0.611825749650855211231211687533889 ... quickstart \n", "1 0.7034159692833852946883644485233207 ... quickstart \n", "2 0.3033804066591317111055858533563476 ... quickstart \n", "3 0.6579972404391247884756597316198778 ... quickstart \n", "4 0.8080447772492735383356100969932859 ... quickstart \n", "\n", " fpmm.answerFinalizedTimestamp fpmm.arbitrationOccurred \\\n", "0 1728822710 False \n", "1 1728822710 False \n", "2 1728822710 False \n", "3 1728822710 False \n", "4 1728822710 False \n", "\n", " fpmm.currentAnswer \\\n", "0 0x00000000000000000000000000000000000000000000... \n", "1 0x00000000000000000000000000000000000000000000... \n", "2 0x00000000000000000000000000000000000000000000... \n", "3 0x00000000000000000000000000000000000000000000... \n", "4 0x00000000000000000000000000000000000000000000... \n", "\n", " fpmm.id fpmm.isPendingArbitration \\\n", "0 0x007068173910cf8719b6f2e66a18b6825c9dde82 False \n", "1 0x007068173910cf8719b6f2e66a18b6825c9dde82 False \n", "2 0x007068173910cf8719b6f2e66a18b6825c9dde82 False \n", "3 0x007068173910cf8719b6f2e66a18b6825c9dde82 False \n", "4 0x007068173910cf8719b6f2e66a18b6825c9dde82 False \n", "\n", " fpmm.openingTimestamp fpmm.outcomes \\\n", "0 1728691200 [Yes, No] \n", "1 1728691200 [Yes, No] \n", "2 1728691200 [Yes, No] \n", "3 1728691200 [Yes, No] \n", "4 1728691200 [Yes, No] \n", "\n", " fpmm.title \\\n", "0 Will the emergency public warning tests planne... \n", "1 Will the emergency public warning tests planne... \n", "2 Will the emergency public warning tests planne... \n", "3 Will the emergency public warning tests planne... \n", "4 Will the emergency public warning tests planne... \n", "\n", " fpmm.condition.id \n", "0 0xa610166e379c42404bd27bf12a16119fdb5171990c3e... \n", "1 0xa610166e379c42404bd27bf12a16119fdb5171990c3e... \n", "2 0xa610166e379c42404bd27bf12a16119fdb5171990c3e... \n", "3 0xa610166e379c42404bd27bf12a16119fdb5171990c3e... \n", "4 0xa610166e379c42404bd27bf12a16119fdb5171990c3e... \n", "\n", "[5 rows x 24 columns]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "trades.head()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "RangeIndex: 26835 entries, 0 to 26834\n", "Data columns (total 24 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 collateralAmount 26835 non-null object\n", " 1 collateralAmountUSD 26835 non-null object\n", " 2 collateralToken 26835 non-null object\n", " 3 creationTimestamp 26835 non-null object\n", " 4 trader_address 26835 non-null object\n", " 5 feeAmount 26835 non-null object\n", " 6 id 26835 non-null object\n", " 7 oldOutcomeTokenMarginalPrice 26835 non-null object\n", " 8 outcomeIndex 26835 non-null object\n", " 9 outcomeTokenMarginalPrice 26835 non-null object\n", " 10 outcomeTokensTraded 26835 non-null object\n", " 11 title 26835 non-null object\n", " 12 transactionHash 26835 non-null object\n", " 13 type 26835 non-null object\n", " 14 market_creator 26835 non-null object\n", " 15 fpmm.answerFinalizedTimestamp 24829 non-null object\n", " 16 fpmm.arbitrationOccurred 26835 non-null bool \n", " 17 fpmm.currentAnswer 24829 non-null object\n", " 18 fpmm.id 26835 non-null object\n", " 19 fpmm.isPendingArbitration 26835 non-null bool \n", " 20 fpmm.openingTimestamp 26835 non-null object\n", " 21 fpmm.outcomes 26835 non-null object\n", " 22 fpmm.title 26835 non-null object\n", " 23 fpmm.condition.id 26835 non-null object\n", "dtypes: bool(2), object(22)\n", "memory usage: 4.6+ MB\n" ] } ], "source": [ "trades.info()" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['collateralAmount', 'collateralAmountUSD', 'collateralToken',\n", " 'creationTimestamp', 'trader_address', 'feeAmount', 'id',\n", " 'oldOutcomeTokenMarginalPrice', 'outcomeIndex',\n", " 'outcomeTokenMarginalPrice', 'outcomeTokensTraded', 'title',\n", " 'transactionHash', 'type', 'market_creator',\n", " 'fpmm.answerFinalizedTimestamp', 'fpmm.arbitrationOccurred',\n", " 'fpmm.currentAnswer', 'fpmm.id', 'fpmm.isPendingArbitration',\n", " 'fpmm.openingTimestamp', 'fpmm.outcomes', 'fpmm.title',\n", " 'fpmm.condition.id'],\n", " dtype='object')" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "trades.columns" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "markets = list(trades[\"fpmm.id\"].unique())" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "803" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(markets)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/var/folders/gp/02mb1d514ng739czlxw1lhh00000gn/T/ipykernel_3094/2495807215.py:12: SettingWithCopyWarning: \n", "A value is trying to be set on a copy of a slice from a DataFrame\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", " trade_markets.rename(\n" ] } ], "source": [ "from datetime import datetime\n", "INVALID_ANSWER_HEX = (\n", " \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"\n", ")\n", "columns_of_interest = [\n", " \"fpmm.currentAnswer\",\n", " \"fpmm.id\",\n", " \"fpmm.openingTimestamp\",\n", " \"market_creator\",\n", " ]\n", "trade_markets = trades[columns_of_interest]\n", "trade_markets.rename(\n", " columns={\n", " \"fpmm.currentAnswer\": \"currentAnswer\",\n", " \"fpmm.openingTimestamp\": \"openingTimestamp\",\n", " \"fpmm.id\": \"id\",\n", " },\n", " inplace=True,\n", ")\n", "trade_markets = trade_markets.drop_duplicates(subset=['id'], keep='last')\n", "# remove invalid answers\n", "\n", "trade_markets = trade_markets.loc[trade_markets[\"currentAnswer\"]!= INVALID_ANSWER_HEX]\n", "trade_markets[\"currentAnswer\"] = trade_markets[\"currentAnswer\"].apply(\n", " lambda x: convert_hex_to_int(x)\n", ")\n", "trade_markets[\"opening_datetime\"] = trade_markets[\"openingTimestamp\"].apply(\n", " lambda x: datetime.fromtimestamp(int(x))\n", ")\n", "trade_markets = trade_markets.sort_values(by=\"opening_datetime\", ascending=True)" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "648" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(trade_markets.id.unique())" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "648" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(trade_markets)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "trade_markets.tail()" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "719" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(trade_markets)" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [], "source": [ "trade_markets.dropna(inplace=True)" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "648" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(trade_markets)" ] }, { "cell_type": "code", "execution_count": 56, "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", "
currentAnsweridopeningTimestampmarket_creatoropening_datetime
207921.00xcc9c26a86dd55aa04dcb0066c9b8fca2983f407d1727136000quickstart2024-09-24 02:00:00
211301.00xd1bd18d7601d106639f922f1b5d2eda025c26be71727136000quickstart2024-09-24 02:00:00
74940.00x4eba0ec2464ec7c746e8872078165c8ad52d346f1727136000quickstart2024-09-24 02:00:00
99111.00x61065f131e2ec851c40765bb0b078a318a36f53e1727136000quickstart2024-09-24 02:00:00
261820.00x7e191324f0efb8aa20b8c702d95e812e55b4179c1727136000pearl2024-09-24 02:00:00
\n", "
" ], "text/plain": [ " currentAnswer id \\\n", "20792 1.0 0xcc9c26a86dd55aa04dcb0066c9b8fca2983f407d \n", "21130 1.0 0xd1bd18d7601d106639f922f1b5d2eda025c26be7 \n", "7494 0.0 0x4eba0ec2464ec7c746e8872078165c8ad52d346f \n", "9911 1.0 0x61065f131e2ec851c40765bb0b078a318a36f53e \n", "26182 0.0 0x7e191324f0efb8aa20b8c702d95e812e55b4179c \n", "\n", " openingTimestamp market_creator opening_datetime \n", "20792 1727136000 quickstart 2024-09-24 02:00:00 \n", "21130 1727136000 quickstart 2024-09-24 02:00:00 \n", "7494 1727136000 quickstart 2024-09-24 02:00:00 \n", "9911 1727136000 quickstart 2024-09-24 02:00:00 \n", "26182 1727136000 pearl 2024-09-24 02:00:00 " ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "trade_markets.tail()" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [], "source": [ "import math\n", "def market_KL_divergence(market_row: pd.DataFrame) -> float:\n", " \"\"\"Function to compute the divergence based on the formula\n", " Formula in https://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence\"\"\"\n", " current_answer = market_row.currentAnswer # \"yes\", \"no\"\n", " target_prob = 1 # = 100%\n", " if current_answer == \"yes\":\n", " candidate_prob = market_row.first_outcome_prob\n", " else: # \"no\"\n", " candidate_prob = market_row.second_outcome_prob\n", "\n", " # we have only one sample, the final probability based on tokens\n", " kl_divergence = candidate_prob * round(math.log(candidate_prob / target_prob), 4)\n", " return kl_divergence" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "719" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(list(trade_markets.id.unique()))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "trade_markets.currentAnswer.value_counts()" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "INVALID_ANSWER_HEX = (\n", " \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"\n", ")" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "def convert_hex_to_int(x):\n", " \"\"\"Convert hex to int\"\"\"\n", " if isinstance(x, float):\n", " return np.nan\n", " if isinstance(x, str):\n", " if x == INVALID_ANSWER_HEX:\n", " return -1\n", " answer = int(x, 16)\n", " return answer\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "market_ids = list(markets.id.unique())\n", "for i in range(len(trade_markets)):\n", " market = trade_markets.iloc[i]\n", " if market.id in market_ids:\n", " current_answer = convert_hex_to_int(market.currentAnswer)\n", " market_answer = markets.loc[markets[\"id\"]==market.id].currentAnswer.values[0]\n", " print(f\"current answer = {current_answer} and market answer {market_answer}\")\n", " trade_markets.at[i, \"currentAnswer\"] = market_answer" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "markets[\"currentAnswer\"] = markets[\"currentAnswer\"].apply(lambda x: convert_hex_to_int(x))" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "currentAnswer\n", " 1.0 407\n", " 0.0 241\n", "-1.0 84\n", "Name: count, dtype: int64" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "markets.currentAnswer.value_counts()" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.0769610411361284" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import math\n", "\n", "candidate_prob = 9/25\n", "target_prob = 1/3\n", "math.log(candidate_prob/target_prob)" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "KL divergence: 6.296890976997244\n" ] } ], "source": [ "import numpy as np\n", "\n", "def kl_divergence(p, q):\n", " \"\"\"\n", " Compute KL divergence for a single sample with two probabilities.\n", " \n", " :param p: First probability (true distribution)\n", " :param q: Second probability (approximating distribution)\n", " :return: KL divergence value\n", " \"\"\"\n", " # Ensure probabilities sum to 1\n", " p = np.array([p, 1-p])\n", " q = np.array([q, 1-q])\n", " \n", " # Avoid division by zero\n", " epsilon = 1e-10\n", " q = np.clip(q, epsilon, 1-epsilon)\n", " \n", " # Compute KL divergence\n", " kl_div = np.sum(p * np.log(p / q))\n", " \n", " return kl_div\n", "\n", "# Example usage\n", "p = 0.7 # probability from true distribution\n", "q = 1.0 # probability from approximating distribution\n", "\n", "result = kl_divergence(p, q)\n", "print(f\"KL divergence: {result}\")" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "KL divergence: inf\n" ] } ], "source": [ "from scipy.special import kl_div\n", "\n", "# For multiple probabilities\n", "p = np.array([0.3, 0.7])\n", "q = np.array([0.0, 1.0])\n", "\n", "kl = np.sum(kl_div(p, q))\n", "print(f\"KL divergence: {kl}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This library is not useful if we have extreme values" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
currentAnsweridopeningTimestampmarket_creatoropening_datetimefirst_outcome_probsecond_outcome_probkl_divergenceoff_by_perc
\n", "
" ], "text/plain": [ "Empty DataFrame\n", "Columns: [currentAnswer, id, openingTimestamp, market_creator, opening_datetime, first_outcome_prob, second_outcome_prob, kl_divergence, off_by_perc]\n", "Index: []" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "markets_div = pd.read_parquet(\"../data/closed_markets_div.parquet\")\n", "markets_div.head()" ] }, { "cell_type": "code", "execution_count": 76, "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", "
currentAnsweridopeningTimestampmarket_creatoropening_datetimefirst_outcome_probsecond_outcome_probkl_divergence
642yes0x4eba0ec2464ec7c746e8872078165c8ad52d346f1727136000quickstart2024-09-24 02:00:000.53920.46089.920241
643no0x3535b4cea3ea7b1862fbe1af5a458702cc1c0dad1727136000quickstart2024-09-24 02:00:000.28120.71885.880786
644yes0x7e191324f0efb8aa20b8c702d95e812e55b4179c1727136000pearl2024-09-24 02:00:000.50000.500010.819778
645no0xd1bd18d7601d106639f922f1b5d2eda025c26be71727136000quickstart2024-09-24 02:00:000.50000.500010.819778
646no0x61065f131e2ec851c40765bb0b078a318a36f53e1727136000quickstart2024-09-24 02:00:000.50000.500010.819778
\n", "
" ], "text/plain": [ " currentAnswer id \\\n", "642 yes 0x4eba0ec2464ec7c746e8872078165c8ad52d346f \n", "643 no 0x3535b4cea3ea7b1862fbe1af5a458702cc1c0dad \n", "644 yes 0x7e191324f0efb8aa20b8c702d95e812e55b4179c \n", "645 no 0xd1bd18d7601d106639f922f1b5d2eda025c26be7 \n", "646 no 0x61065f131e2ec851c40765bb0b078a318a36f53e \n", "\n", " openingTimestamp market_creator opening_datetime first_outcome_prob \\\n", "642 1727136000 quickstart 2024-09-24 02:00:00 0.5392 \n", "643 1727136000 quickstart 2024-09-24 02:00:00 0.2812 \n", "644 1727136000 pearl 2024-09-24 02:00:00 0.5000 \n", "645 1727136000 quickstart 2024-09-24 02:00:00 0.5000 \n", "646 1727136000 quickstart 2024-09-24 02:00:00 0.5000 \n", "\n", " second_outcome_prob kl_divergence \n", "642 0.4608 9.920241 \n", "643 0.7188 5.880786 \n", "644 0.5000 10.819778 \n", "645 0.5000 10.819778 \n", "646 0.5000 10.819778 " ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "markets_div.tail()" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "647" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(markets_div)" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import math" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "def kl_divergence(p, q):\n", " \"\"\"\n", " Compute KL divergence for a single sample with two probabilities.\n", "\n", " :param p: First probability (true distribution)\n", " :param q: Second probability (approximating distribution)\n", " :return: KL divergence value\n", " \"\"\"\n", " # Ensure probabilities sum to 1\n", " p = np.array([p, 1 - p])\n", " q = np.array([q, 1 - q])\n", "\n", " # Avoid division by zero\n", " epsilon = 1e-10\n", " q = np.clip(q, epsilon, 1 - epsilon)\n", " print(q)\n", "\n", " # Compute KL divergence\n", " kl_div = np.sum(p * np.log(p / q))\n", "\n", " return kl_div" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-22.82067008, 1.6847004 ])" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p= 0\n", "q = 0.8145\n", "p = np.array([p, 1 - p])\n", "q = np.array([q, 1 - q])\n", "epsilon = 1e-10\n", "p = np.clip(p, epsilon, 1 - epsilon)\n", "np.log(p/q)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-2.28206701e-09, 1.68470040e+00])" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p*np.log(p/q)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.6847003943841101" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sum(p * np.log(p / q))" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.791663620863367" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = 0.8145\n", "q = 1.0\n", "kl_divergence(p,q)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.16397451204513597" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = 0.99\n", "q = 0.8145\n", "kl_divergence(p, q)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "KL divergence: 0.16397451204513597\n" ] } ], "source": [ "from scipy.special import kl_div\n", "\n", "# For multiple probabilities\n", "p = np.array([0.99, 0.01])\n", "q = np.array([0.8145, 0.1855])\n", "\n", "kl = np.sum(kl_div(p, q))\n", "print(f\"KL divergence: {kl}\")" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.2051808486854041" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p= 1\n", "q = 0.8145\n", "kl_divergence(p, q)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "KL divergence: 0.20518085094003724\n" ] } ], "source": [ "# For multiple probabilities\n", "p = np.array([1.0, 0.0])\n", "q = np.array([0.8145, 0.1855])\n", "\n", "kl = np.sum(kl_div(p, q))\n", "print(f\"KL divergence: {kl}\")" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1.e+00 1.e-10]\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/var/folders/gp/02mb1d514ng739czlxw1lhh00000gn/T/ipykernel_28964/3714966623.py:19: RuntimeWarning: divide by zero encountered in log\n", " kl_div = np.sum(p * np.log(p / q))\n", "/var/folders/gp/02mb1d514ng739czlxw1lhh00000gn/T/ipykernel_28964/3714966623.py:19: RuntimeWarning: invalid value encountered in multiply\n", " kl_div = np.sum(p * np.log(p / q))\n" ] }, { "data": { "text/plain": [ "nan" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = 0\n", "q = 1\n", "kl_divergence(p, q)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "KL divergence: 0.010050335853501449\n" ] } ], "source": [ "p = np.array([0.0, 1.0])\n", "q = np.array([0.01, 0.99])\n", "\n", "kl = np.sum(kl_div(p, q))\n", "print(f\"KL divergence: {kl}\")" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.17425697504355725" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = 0.01\n", "q = 0\n", "kl_divergence(p, q)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "KL divergence: inf\n" ] } ], "source": [ "p = np.array([0.01, 0.99])\n", "q = np.array([0.0, 1.0])\n", "\n", "kl = np.sum(kl_div(p, q))\n", "print(f\"KL divergence: {kl}\")" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.01, 0.99])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "epsilon = 1e-10\n", "q = 0\n", "q = np.clip(p, epsilon, 1 - epsilon)\n", "q" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# New function" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def kl_divergence(P, Q):\n", " \"\"\"\n", " Compute KL divergence for a single sample with two prob distributions.\n", "\n", " :param P: True distribution)\n", " :param Q: Approximating distribution)\n", " :return: KL divergence value\n", " \"\"\"\n", " # Review edge cases\n", " if P[0] == Q[0]:\n", " return 0.0\n", " # If P is complete opposite of Q, divergence is some max value.\n", " # Here set to 20--allows for Q [\\mu, 1-\\mu] or Q[1-\\mu, \\mu] where \\mu = 10^-8\n", " if P[0] == Q[1]:\n", " return 20\n", "\n", " nonzero = P > 0.0\n", " # Compute KL divergence\n", " kl_div = np.sum(P[nonzero] * np.log(P[nonzero] / Q[nonzero]))\n", "\n", " return kl_div" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.0\n" ] } ], "source": [ "P = np.array([0.0, 1.0])\n", "Q = np.array([0.0, 1.0])\n", "print(kl_divergence(P,Q))" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "20\n" ] } ], "source": [ "P = np.array([0.0, 1.0])\n", "Q = np.array([1.0, 0.0])\n", "print(kl_divergence(P,Q))" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "20\n" ] } ], "source": [ "P = np.array([1.0, 0.0])\n", "Q = np.array([0.0, 1.0])\n", "print(kl_divergence(P,Q))" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.010050335853501506\n" ] } ], "source": [ "P = np.array([0.0, 1.0])\n", "Q = np.array([0.01, 0.99])\n", "print(kl_divergence(P,Q))" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.010050335853501506" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1 * np.log(1 / 0.99)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.5108256237659907\n" ] } ], "source": [ "P = np.array([1.0, 0.0])\n", "Q = np.array([0.60, 0.05])\n", "print(kl_divergence(P,Q))" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "13.815510557964274\n" ] } ], "source": [ "Q = np.array([1e-6, 0.999999])#or [0.99, 0.01]\n", "P = np.array([1.0, 0.0])\n", "print(kl_divergence(P,Q))" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4.605170185988092" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.log(1/0.01)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAJOCAYAAACqS2TfAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAB7lUlEQVR4nO3deVwV9f7H8fcBBFwQNAQEFVRcckFNk2vuSaKVpdlNvd1c8uqvrno1stLKXSPNyrqaS2WabbZpt80yEs0yLU3NTFMyyQXcAgEVlfP9/UGcPAIKyHAAX8/H4zxkvjPznc8AR32f78x3bMYYIwAAAAAAUOzcXF0AAAAAAADlFaEbAAAAAACLELoBAAAAALAIoRsAAAAAAIsQugEAAAAAsAihGwAAAAAAixC6AQAAAACwCKEbAAAAAACLELoBAAAAALAIoRsALPDbb7/JZrNpyZIlri4FLjJ58mTZbDZXl5GvJUuWyGaz6bfffivwtt9//731hV1g1apVatmypby9vWWz2ZSSkiJJWrZsmRo3bqwKFSrIz88v3/3DwsJ06623lkyxAADkg9ANoEzLLwykpqaqbdu28vb21qpVqyT9FYKOHTtW6OPYbDbHy8PDQ9WrV1fr1q01evRo7dy5s1jOBQUXFhbm9DPx9vZWgwYN9NBDD+nEiROuLu+KvfDCCy75wMbq43799dfq06ePAgMD5eXlpbCwMP3f//2fEhMTc217/Phx3XXXXapYsaLmzZunZcuWqXLlytq1a5cGDx6s+vXr68UXX9SiRYssq7cgcj5gy3m5u7urTp066tOnj7Zu3erS2orDqVOnNHnyZMXHx7u6FAAoszxcXQAAFLeTJ0+qe/fu2r59u1asWKEePXoUS7833XSTBg4cKGOMUlNTtW3bNi1dulQvvPCCZs6cqZiYGMe2oaGhOn36tCpUqFAsx0ZuLVu21IMPPihJOnPmjDZv3qw5c+Zo7dq12rRpk4uruzIvvPCC/P39NXjwYMuOcc8996h///7y8vIqkeP+97//1ejRo1WvXj2NGjVKNWvW1M8//6yXXnpJy5cv1yeffKIbbrjBsf13332ntLQ0TZs2TVFRUY72+Ph42e12PffccwoPDy/2OotqwIABuvnmm5WVlaWff/5Z8+fP16effqpvv/1WLVu2dHV5RXbq1ClNmTJFktSlSxfXFgMAZRShG0C5kpaWpujoaG3dulXvv/++evbsWWx9N2zYUP/85z+d2p588kn16tVLDz74oBo3bqybb75ZkhyjryUtIyNDlStXLvHjukJISIjTz+Nf//qXqlSpotmzZ2vPnj1q0KCBC6sr/dzd3eXu7l4ix/r66681ZswYdejQQatWrVKlSpUc6+6//361b99ed955p3766SdVq1ZNknTkyBFJynX5eH7trnbdddc5/T62b99et912m+bPn6+FCxdeUd9X0/saAMojLi8HUG6kp6erR48e2rJli9577z3dcsstlh/zmmuu0VtvvSUPDw/NmDHD0X7xPd2zZ8+WzWbT/v37c/Uxfvx4eXp66o8//nC0bdy4UT169JCvr68qVaqkzp076+uvv3baL+dy+Z07d+of//iHqlWrpg4dOkiS7Ha7Jk+erODgYFWqVEldu3bVzp07FRYWlmsUMyUlRWPGjFHt2rXl5eWl8PBwzZw5U3a7Pdf5zJ49W4sWLVL9+vXl5eWl66+/Xt99912uc9q1a5fuuusu1ahRQxUrVlSjRo302GOPOW1z8OBB3XvvvY5LjZs2barFixcX7Bufj6CgIEmSh4fzZ8pffvmlOnbsqMqVK8vPz0+33367fv75Z8f6V155RTabLdfxn3jiCdlsNn3yySe5vg/PPvusQkNDVbFiRXXu3Fk7duy4bH3nz5/XtGnTHN+/sLAwPfroo8rMzHRsExYWpp9++klr1651XLJ8qRHG6667TnfccYdTW/PmzWWz2bR9+3ZH2/Lly2Wz2RznffE93QU5bmZmpmJiYlSjRg1VrlxZffr00dGjRy973tOmTZPNZtPSpUudArck1a9fX7NmzdLhw4cd4bRLly4aNGiQJOn666+XzWbT4MGDFRYWpkmTJkmSatSoIZvNpsmTJ1/2+J9//rnj3vAmTZro/fffd6z79ddfZbPZ9Oyzz+ba75tvvpHNZtObb7552WNc7MYbb5Qk7du3z9F2pe9rSXrttdfUtm1bVapUSdWqVVOnTp30+eefO/Xx6aefOn7ffXx8dMstt+inn35y2mbw4MGqUqWKDh48qN69e6tKlSqqUaOGxo4dq6ysLEnZv+81atSQJE2ZMsXxe5HzPd++fbsGDx6sevXqydvbW0FBQbr33nt1/PjxXN+P+Ph4tWnTRt7e3qpfv74WLlyY77wHr732mlq3bq2KFSuqevXq6t+/v37//feCfusBoPQxAFCGvfLKK0aSiY+PNx06dDAVKlQwH3zwQZ7bTpo0yUgyR48eLfRxJJkRI0bku75bt27Gzc3NpKamGmOM2bdvn5FkXnnlFWOMMfv37zc2m83MmjUr17716tUzt9xyi2M5Li7OeHp6mnbt2pmnn37aPPvssyYiIsJ4enqajRs35jqfJk2amNtvv9288MILZt68ecYYYx5++GEjyfTq1cvMnTvXDBs2zNSqVcv4+/ubQYMGOfrIyMgwERER5pprrjGPPvqoWbBggRk4cKCx2Wxm9OjRju1yzqdVq1YmPDzczJw508yaNcv4+/ubWrVqmbNnzzq23bZtm6lataq55pprzPjx483ChQvNww8/bJo3b+7YJikpydSqVcvUrl3bTJ061cyfP9/cdtttRpJ59tlnL/vzCA0NNd27dzdHjx41R48eNb///rv53//+Z4KDg02nTp2ctl29erXx8PAwDRs2NLNmzTJTpkwx/v7+plq1ambfvn2O7W699Vbj6+trEhMTjTHGbN++3Xh6epqhQ4fm+j40b97chIWFmZkzZ5opU6aY6tWrmxo1apikpKRcP58LDRo0yEgyd955p5k3b54ZOHCgkWR69+7t2GbFihWmVq1apnHjxmbZsmVm2bJl5vPPP8/3e/Gf//zH1KhRw7F8/PhxY7PZjJubm5k7d66jfcSIEU7b5bx3cr4HlzpuzratWrUyN954o/nvf/9rHnzwQePu7m7uuuuufGszJvt3zMPDw3Tp0iXfbc6cOWO8vLxM+/btjTHGfP7552b48OFGkpk6dapZtmyZ+eabb8yKFStMnz59jCQzf/58s2zZMrNt27Z8+w0NDTUNGzY0fn5+Zty4ceaZZ54xzZs3N25ubk7f0/bt25vWrVvn2v/f//638fHxMRkZGfkeI+d34qmnnnJq37Ztm5Fk+vfvb4wpnvf15MmTjSRzww03mKeeeso899xz5h//+Id55JFHHPu/+uqrxmazmR49epj//ve/ZubMmSYsLMz4+fk5/b4PGjTIeHt7m6ZNm5p7773XzJ8/3/Tt29dIMi+88IIxxpj09HQzf/58I8n06dPH8XuR8z2fPXu26dixo5k6dapZtGiRGT16tKlYsaJp27atsdvtjmNt2bLFeHl5mbCwMPPkk0+aGTNmmODgYNOiRYtc75Hp06cbm81m+vXrZ1544QXH+zUsLMz88ccf+f4cAKA0I3QDKNNywkBoaKipUKGCWblyZb7bWhm6R48ebSQ5/jN6ceg2xph27drl+o/9pk2bjCTz6quvGmOMsdvtpkGDBiY6OtrpP62nTp0ydevWNTfddFOu8xkwYIBTn0lJScbDw8MpyBnz13/YLwzd06ZNM5UrVza//PKL07bjxo0z7u7ujgCacz7XXHONOXHihGO7Dz74wEgyH374oaOtU6dOxsfHx+zfv9+pzwvPZ+jQoaZmzZrm2LFjTtv079/f+Pr6mlOnTplLCQ0NNZJyvdq3b5+rz5YtW5qAgABz/PhxR9u2bduMm5ubGThwoKPt8OHDpnr16uamm24ymZmZplWrVqZOnTqOD1Iu/D5UrFjRHDhwwNG+ceNGI8k88MADjraLQ/fWrVuNJPOvf/3Lqb6xY8caSebLL790tDVt2tR07tz5kt+DHO+8846RZHbu3GmMMeZ///uf8fLyMrfddpvp16+fY7uIiAjTp08fx/LFoftSx83ZNioqyunn+MADDxh3d3eTkpKSb305533hhzh5iYiIMNWrV891zO+++85pu8K8j3N+T9577z1HW2pqqqlZs6Zp1aqVo23hwoVGkvn5558dbWfPns31IVVecn4npkyZYo4ePWqSkpJMfHy8adWqlePYxfG+3rNnj3FzczN9+vQxWVlZTuty+kxLSzN+fn5m2LBhTuuTkpKMr6+vU3vOB0BTp0512rZVq1ZOf08dPXrUSDKTJk3Kde55vU/ffPNNI8msW7fO0darVy9TqVIlc/DgQafz8fDwcHqP/Pbbb8bd3d3MmDHDqc8ff/zReHh45GoHgLKCy8sBlAvJycny9vZW7dq1XXL8KlWqSMq+pzw//fr10+bNm5WQkOBoW758uby8vHT77bdLkrZu3ao9e/boH//4h44fP65jx47p2LFjysjIULdu3bRu3Tqny74l6b777nNajouL0/nz5/Xvf//bqX3UqFG5anrnnXfUsWNHVatWzXGsY8eOKSoqSllZWVq3bl2uc8i551aSOnbsKCn7El1JOnr0qNatW6d7771XderUcdo35zJSY4zee+899erVS8YYp+NGR0crNTVVW7Zsyff7mCMyMlKrV6/W6tWr9dFHH2nGjBn66aefdNttt+n06dOSpMOHD2vr1q0aPHiwqlev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k09q3Lhx6t+/vx5//HFHQLvQypUrdfDgQcfypk2btHHjxks+Fz7nWHPmzHFqf+aZZyTJ6RF3lStXdqr3cnIuG585c6YiIiLk6+vraI+Li9P3339foEvLC3vcgnr88cdljNHgwYMd99vn2Ldvnx5++GHVrFlT//d//1fovuvVq6eoqCjHq3379k7rDx06pBUrVjiWT548qVdffVUtW7Z0Gg328PDQgAED9Pbbb2vJkiVq3rx5ka+4uFhxvK979+4tNzc3TZ06Ndcocs57Kzo6WlWrVtUTTzyhc+fOFek4F8t5xNvFvxc5H+BcfJXDxb/f7u7uioqK0sqVK3Xo0CFH+969e/Xpp586bXvHHXfI3d1dU6ZMydWvMSbPR5EBQFnASDeAcqdPnz568cUXde+99+q2227TqlWr5O3t7Vj/zDPP5HpWsJubmx599NFL9vvLL7/otddekzFGJ0+e1LZt2/TOO+8oPT1dzzzzjHr06HHZ2gICAtS1a1c988wzSktLU79+/XLV8dJLL6lnz55q2rSphgwZopCQEB08eFBr1qxR1apVHcEyP4GBgRo9erSefvpp3XbbberRo4e2bdumTz/9VP7+/k4jVw899JD+97//6dZbb9XgwYPVunVrZWRk6Mcff9S7776r3377Tf7+/pc9rws9//zz6tChg6677joNHz5cdevW1W+//aaPP/5YW7dulSQ9+eSTWrNmjSIjIzVs2DA1adJEJ06c0JYtW/TFF1/oxIkTlz3OwYMH9dprr0mSzp49q23btmnhwoXy9/d3urT8qaeeUs+ePdWuXTsNHTpUp0+f1n//+1/5+vo6njd85MgR3X///eratatGjhwpKftDijVr1mjw4MFav36902XG4eHh6tChg+6//35lZmZqzpw5uuaaa/K9TF/K/iBg0KBBWrRokVJSUtS5c2dt2rRJS5cuVe/evdW1a1fHtq1bt9b8+fM1ffp0hYeHKyAg4JL3FoeHhysoKEi7d+92OvdOnTrpkUcekaQChe7CHregOnXqpNmzZysmJkYREREaPHiwatasqV27dunFF1+U3W7XJ598kmvOgeLQsGFDDR06VN99950CAwO1ePFiJScn65VXXsm17cCBA/X8889rzZo1Trd9XKnieF+Hh4frscce07Rp09SxY0fdcccd8vLy0nfffafg4GDFxsaqatWqmj9/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ooWio6N15MiRS+7322+/aezYserYsWOe63v06KHDhw87Xm+++aYV5QMAAAAAimDt2rUaMWKEvv32W61evVrnzp1T9+7dlZGRIUk6dOiQDh06pNmzZ2vHjh1asmSJVq1apaFDh16279KUBz1cduQ/PfPMMxo2bJiGDBkiSVqwYIE+/vhjLV68WOPGjctzn6ysLN19992aMmWKvvrqK6WkpOTaxsvLS0FBQVaWDgAAAAAoolWrVjktL1myRAEBAdq8ebM6deqkZs2a6b333nOsr1+/vmbMmKF//vOfOn/+vDw88o+zpSkPunSk++zZs9q8ebOioqIcbW5uboqKitKGDRvy3W/q1KkKCAi45Ccc8fHxCggIUKNGjXT//ffr+PHjxVo7AAAAAKD45Fw2Xr169UtuU7Vq1UsGbql05UGXjnQfO3ZMWVlZCgwMdGoPDAzUrl278txn/fr1evnll7V169Z8++3Ro4fuuOMO1a1bVwkJCXr00UfVs2dPbdiwQe7u7rm2z8zMVGZmpmM5LS2taCcEAABwFXM7neLqEoByryy8z9LS0nTy5EnHspeXl7y8vC65j91u15gxY9S+fXs1a9Ysz22OHTumadOmafjw4Zfsq7B50Gouv7y8MNLS0nTPPffoxRdflL+/f77b9e/f3/F18+bNFRERofr16ys+Pl7dunXLtX1sbKymTJliSc0AAABXi4r71rm6BAClQJMmTZyWJ02apMmTJ19ynxEjRmjHjh1av359nutPnjypW265RU2aNLlsX4XNg1Zzaej29/eXu7u7kpOTndqTk5PzvP4+ISFBv/32m3r16uVos9vtkiQPDw/t3r1b9evXz7VfvXr15O/vr7179+b5TR4/frxiYmIcywcPHsz1iwIAAIBLO123k+wV/VxdBlCuuZ1OKfUfcO3cuVMhISGO5cuNco8cOVIfffSR1q1bp1q1auVan5aWph49esjHx0crVqxQhQoVClXP5fKg1Vwauj09PdW6dWvFxcU5Hvtlt9sVFxenkSNH5tq+cePG+vHHH53aHn/8caWlpem5555T7dq18zzOgQMHdPz4cdWsWTPP9Rdf7nDhpRAAAAAoGHtFP9kr5381IoCrg4+Pj6pWrXrZ7YwxGjVqlFasWKH4+HjVrVs31zYnT55UdHS0vLy89L///U/e3t6FrudyedBqLr+8PCYmRoMG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lJvbXwPyGRkZ+ve//60DBw6oYsWKaty4sV577TX169dPkuTu7q7t27dr6dKlSklJUXBwsLp3765p06YVy70EAAAAAIAr9/3336tr166O5Zx5tgYNGqQlS5ZIkt566y0ZY/INzQkJCTp27Jhj+cCBAxowYICOHz+uGjVqqEOHDvr2229Vo0YN607kMmzGGOOyo5dSBw4cUO3atfX777+rVq1ari4HAACHX375RcOHD2eGbwBAqVMeclS1atVks9lytdtsNnl7eys8PFyDBw92XJldEC4f6QYAAAAAoDSYOHGiZsyYoZ49e6pt27aSpE2bNmnVqlUaMWKE9u3bp/vvv1/nz5/XsGHDCtQnoRsAAAAAAEnr16/X9OnTdd999zm1L1y4UJ9//rnee+89RURE6Pnnny9w6C7S7OUpKSl66aWXNH78eJ04cUKStGXLFh08eLAo3QEAAAAA4HKfffaZoqKicrV369ZNn332mSTp5ptv1q+//lrgPgsdurdv366GDRtq5syZmj17tlJSUiRJ77//vsaPH1/Y7gAAAAAAKBWqV6+uDz/8MFf7hx9+qOrVq0vKntzbx8enwH0W+vLymJgYDR48WLNmzXI60M0336x//OMfhe0OAAAAAIBSYcKECbr//vu1Zs0axz3d3333nT755BMtWLBAkrR69Wp17ty5wH0WOnR/9913WrhwYa72kJAQJSUlFbY7AAAAAABKhWHDhqlJkyaaO3eu3n//fUlSo0aNtHbtWt1www2SpAcffLBQfRY6dHt5eenkyZO52n/55ReXPvsMAAAAAIAr1b59e7Vv377Y+iv0Pd233Xabpk6dqnPnzknKfl5ZYmKiHnnkEfXt27fYCgMAAAAAwFXOnDmjkydPOr2KotCh++mnn1Z6eroCAgJ0+vRpde7cWeHh4fLx8dGMGTOKVAQAAAAAAK526tQpjRw5UgEBAapcubKqVavm9CqKQl9e7uvrq9WrV+vrr7/Wtm3blJ6eruuuuy7PadUBAAAAACgrHnroIa1Zs0bz58/XPffco3nz5ungwYNauHChnnzyySL1WejQnaO4r3MHAAAAAMCVPvzwQ7366qvq0qWLhgwZoo4dOyo8PFyhoaF6/fXXdffddxe6z0JfXv6f//xHzz//fK72uXPnasyYMYUuAAAAAACA0uDEiROqV6+eJKlq1ao6ceKEJKlD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6GjHPt26dVOfPn0cofpy+fJyVq5cqeXLl+tvf/ub01wqTZs2VUJCQpHOs9Che9iwYRo9erQWL14sm82mQ4cOacOGDRo7dqwmTJhQ6AL69euno0ePauLEiUpKSlLLli21atUqx83viYmJcrvg0/uMjAz9+9//1oEDB1SxYkU1btxYr732mvr16+fY5uGHH1ZGRoaGDx+ulJQUdejQQatWrZK3t3eh6wMAwOVs2Y8Fc/vzMWE5z+Y2NrfswE3oBgCUQd9//726du3qWM655XfQoEGaP3++tm/frqVLlyolJUXBwcHq3r27pk2b5nSVckJCgo4dO+ZYvly+vJyjR48qICAgV3tGRkbeE5oWgM2YP//lLiBjjJ544gnFxsbq1KlTkrIvzx47dqymTZtWpCJKmwMHDqh27dr6/fffVatWLVeXAwCW+OWXXzR8+HBlNLmNy8vLkgv/2SZslxluGcdUeef/tGjRIjVs2NDV5QCAJcpDjurUqZP+/ve/a9SoUfLx8dH27dtVt25djRo1Snv27NGqVasK3WehR7ptNpsee+wxPfTQQ9q7d6/S09PVpEkTValSpdAHBwAAhUTQBgDAMk888YR69uypnTt36vz583ruuee0c+dOffPNN1q7dm2R+iz0rCuvvfaaTp06JU9PTzVp0kRt27YlcAMAAAAAyrwOHTpo27ZtOn/+vJo3b67PP/9cAQEB2rBhg1q3bl2kPgs90v3AAw/ovvvu02233aZ//vOfio6OzvPB5AAAAAAAlBU5T706e/asnnjiCdWoUaNY+i30SPfhw4f11ltvyWaz6a677lLNmjU1YsQIffPNN8VSEAAAAAAAJWnr1q1q3LixevTooV69eik8PFyfffZZsfRd6NDt4eGhW2+9Va+//rqOHDmiZ599Vr/99pu6du2q+vXrF0tRAAAAAACUlEceeUR169bV+vXrtXnzZnXr1q3Az/a+nEJfXn6hSpUqKTo6Wn/88Yf279+vn3/+uViKAgAAAACgpGzevFmff/65rrvuOknS4sWLVb16dZ08eVJVq1a9or4LPdItSadOndLrr7+um2++WSEhIZozZ4769Omjn3766YqKAQAAAACgpJ04ccLpMWd+fn6qXLmyjh8/fsV9F3qku3///vroo49UqVIl3XXXXZowYYLatWt3xYUAAAAAAOAqO3fuVFJSkmPZGKOff/5ZaWlpjraIiIhC91vo0O3u7q63336bWcsBAAAAAOVGt27dZIxxarv11ltls9lkjJHNZlNWVlah+y106H799dcLfRAAAAAAAEqrffv2WdZ3gUL3888/r+HDh8vb21vPP//8Jbf9z3/+UyyFAQAAAABQEkJDQy3ru0Ch+9lnn9Xdd98tb29vPfvss/luZ7PZCN0AAAAAAPypQKH7wqF2K4fdAQAAAAAoT4r0yDAAAAAAAHB5hQrdGRkZmjhxopo1a6YqVarIx8dHERERmjp1qk6dOmVVjQAAAAAAlEkFnr387Nmz6ty5s3bs2KGePXuqV69ejueWzZgxQ59++qnWrVunChUqWFkvAAAAAACWmDRpku69995inVitwKF7/vz5OnDggLZt26ZGjRo5rdu1a5e6dOmiBQsWaNSoUcVWHAAAAAAAJeWDDz7QjBkz1LlzZw0dOlR9+/aVl5fXFfVZ4MvL33//fU2YMCFX4Jakxo0b67HHHtO77757RcUAAAAAAOAqW7du1XfffaemTZtq9OjRCgoK0v3336/vvvuuyH0WOHTv3LlTXbp0yXd9165dtXPnziIXAgAAAACAq7Vq1UrPP/+8Dh06pJdfflkHDhxQ+/btFRERoeeee06pqamF6q/AoTslJUXXXHNNvuuvueaaQh8cAAAAAIDSyBijc+fO6ezZszLGqFq1apo7d65q166t5cuXF7ifAoduu90ud3f3/Dtyc1NWVlaBDwwAAAAAQGmzefNmjRw5UjVr1tQDDzygVq1a6eeff9batWu1Z88ezZgxQ//5z38K3F+BJ1Izxqhbt27y8Mh7l/Pnzxf4oACA0sPtDFcpAVbjfQYAZUPz5s21a9cude/eXS+//LJ69eqVa/B5wIABGj16dIH7LHDonjRp0mW36du3b4EPDABwLV9fX1Xw9JJ+XevqUoCrQgVPL/n6+rq6DADAJdx111269957FRISku82/v7+stvtBe7TZowxxVFceXLgwAHVrl1bv//+u2rVquXqcgDAMsnJyczHUcbs379fM2bM0GOPPVaszxCF9Xx9fRUYGOjqMgDAMuUtR+VEZZvNdkX9FHikGwBQ/gQGBhICyqjQ0FA1bNjQ1WUAAFDuvPzyy3r22We1Z88eSVKDBg00ZswY/etf/ypSf4RuAAAAAAAkTZw4Uc8884xGjRqldu3aSZI2bNigBx54QImJiZo6dWqh+yR0AwAAAAAgaf78+XrxxRc1YMAAR9ttt92miIgIjRo1qkihu8CPDAMAAAAAoDw7d+6c2rRpk6u9devWRX5iV7GF7gMHDmj48OHF1R0AAAAAACXqnnvu0fz583O1L1q0SHfffXeR+iy2y8uPHz+ul19+WYsWLSquLgEAAAAAsFRMTIzja5vNppdeekmff/65/va3v0mSNm7cqMTERA0cOLBI/XNPNwAAAADgqvXDDz84Lbdu3VqSlJCQICn7udz+/v766aefitQ/oRsAAAAAcNVas2aNpf0zkRoAAAAAABd58803lZGRccX9FHik+4477rjk+pSUlCutBQAAAACAUuH//u//FBkZqXr16l1RPwUO3b6+vpddX9QbywEAAAAAKE2MMcXST4FD9yuvvHLZbdLT06+oGAAAAAAAStLJkydVtWpVy/ov8D3dzz777CXXp6WlKTo6+ooLAgAAAACgpFSrVk1HjhyRJN14442OW6c//fRTBQcHX3H/BQ7djz76qF599dU816Wnp6tHjx46fvz4FRcEAAAAAEBJqVKliiPLxsfH69y5c5KkDh06yNvb+4r7L/Dl5cuWLdM999wjPz8/3XbbbY72jIwM9ejRQ0ePHtXatWuvuCAAAAAAAEpKVFSUunbtqmuvvVaS1KdPH3l6eua57Zdfflno/gscuu+8806lpKRowIAB+vjjj9WlSxdH4E5OTtbatWtVs2bNQhcAAAAAAICrvPbaa1q6dKkSEhK0du1aNW3aVJUqVSq2/gscuiXpX//6l06cOKHbb79dH3zwgSZOnKhDhw5p7dq1xXKtOwAAAAAAJencuXO67777JEnff/+9Zs6cKT8/v2Lrv1ChW5IefvhhnThxQt26dVNYWJji4+NVq1atYisIAAAAAICSUq1aNR0+fFgBAQGy2WzF3n+BQ/cdd9zhtFyhQgX5+/tr9OjRTu3vv/9+8VQGAAAAAIDFciZSCwgI0Nq1ax0TqRWXAoduX19fp+UBAwYUayEAAAAAAJS0CydSM8a4biK1V155pdCdAwAAAABQmpWqidQAAAAAAChPKlasaOlEam7F1tMVmDdvnsLCwuTt7a3IyEht2rQp321ffPFFdezYUdWqVVO1atUUFRWVa/vBgwfLZrM5vXr06GH1aQAAAAAACmjdunXq1auXgoODZbPZtHLlSse6c+fO6ZFHHlHz5s1VuXJlBQcHa+DAgTp06NAl+5w8eXKuLNi4ceMC17RmzRr5+fnp2LFjOnbsWFFPzYnLQ/fy5csVExOjSZMmacuWLWrRooWio6N15MiRPLePj4/XgAEDtGbNGm3YsEG1a9dW9+7ddfDgQaftevToocOHDzteb775ZkmcDgAAAACgADIyMtSiRQvNmzcv17pTp05py5YtmjBhgrZs2aL3339fu3fv1m233XbZfps2beqUBdevX1+gelJSUjRixAj5+/srMDBQgYGB8vf318iRI5WSklLY03Nw+eXlzzzzjIYNG6YhQ4ZIkhYsWKCPP/5Yixcv1rhx43Jt//rrrzstv/TSS3rvvfcUFxengQMHOtq9vLwUFBRkbfEAAAAAgCLp2bOnevbsmec6X19frV692qlt7ty5atu2rRITE1WnTp18+/Xw8Ch0Fjxx4oTatWungwcP6u6779a1114rSdq5c6eWLFmiuLg4ffPNN6pWrVqh+pVcPNJ99uxZbd68WVFRUY42Nzc3RUVFacOGDQXq49SpUzp37pyqV6/u1B4fH6+AgAA1atRI999/v44fP16stQMAAAAASk5qaqpsNttl77fes2ePgoODVa9ePd19991KTEy8bN9Tp06Vp6enEhIStHDhQo0ZM0ZjxozRokWLtHfvXlWoUEFTp04tUt0uHek+duyYsrKyFBgY6NQeGBioXbt2FaiPRx55RMHBwU7BvUePHrrjjjtUt25dJSQk6NFHH1XPnj21YcMGubu75+ojMzNTmZmZjuW0tLQinhEAoDQ4c+ZMgf6BLYv279/v9Gd5VKdOHXl7e7u6DABAEaWlpenkyZOOZS8vL3l5eV1Rn2fOnNEjjzyiAQMGqGrVqvluFxkZqSVLlqhRo0Y6fPiwpkyZoo4dO2rHjh3y8fHJd7+VK1dq4cKFubKpJAUFBWnWrFm677779Oyzzxa6dpdfXn4lnnzySb311luKj493+se5f//+jq+bN2+uiIgI1a9fX/Hx8erWrVuufmJjYzVlypQSqRkAYL3ExEQNHz7c1WVYasaMGa4uwTKLFi1Sw4YNXV0GAKCImjRp4rQ8adIkTZ48ucj9nTt3TnfddZeMMZo/f/4lt73wcvWIiAhFRkYqNDRUb7/9toYOHZrvfocPH1bTpk3zXd+sWTMlJSUVvni5OHT7+/vL3d1dycnJTu3JycmXvQZ/9uzZevLJJ/XFF18oIiLiktvWq1dP/v7+2rt3b56he/z48YqJiXEsHzx4MNcvCgCg7KhTp44WLVrk6jJQRJe6Tw8AUPrt3LlTISEhjuUrGeXOCdz79+/Xl19+eclR7rz4+fmpYcOG2rt37yW38/f312+//aZatWrluX7fvn25bmkuKJeGbk9PT7Vu3VpxcXHq3bu3JMlutysuLk4jR47Md79Zs2ZpxowZ+uyzz9SmTZvLHufAgQM6fvy4atasmef6iy93uPBSCABA2ePt7c1IKQAALuLj41PocJyXnMC9Z88erVmzRtdcc02h+0hPT1dCQoLuueeeS24XHR2txx57TKtXr5anp6fTuszMTE2YMKHIj6F2+eXlMTExGjRokNq0aaO2bdtqzpw5ysjIcMxmPnDgQIWEhCg2NlaSNHPmTE2cOFFvvPGGwsLCHEP8VapUUZUqVZSenq4pU6aob9++CgoKUkJCgh5++GGFh4crOjraZecJAAAAAPhLenq60wj0vn37tHXrVlWvXl01a9bUnXfeqS1btuijjz5SVlaWI/tVr17dEYy7deumPn36OAZtx44dq169eik0NFSHDh3SpEmT5O7urgEDBlyylqlTp6pNmzZq0KCBRowYocaNG8sYo59//lkvvPCCMjMztWzZsiKdp8tDd79+/XT06FFNnDhRSUlJatmypVatWuW4gT0xMVFubn9Nsj5//nydPXtWd955p1M/OfcJuLu7a/v27Vq6dKlSUlIUHBys7t27a9q0aVd88z4AAAAAoHh8//336tq1q2M555bfQYMGafLkyfrf//4nSWrZsqXTfmvWrFGXLl0kSQkJCTp27Jhj3YEDBzRgwAAdP35cNWrUUIcOHfTtt9+qRo0al6ylVq1a2rBhg/79739r/PjxMsZIkmw2m2666SbNnTtXtWvXLtJ52kxOb3A4cOCAateurd9//z3fa/oBAAAAAH8pLznqjz/+0J49eyRJ4eHhRb6XO4fLR7oBAEAhXPhZuc3mujoAACinqlWrprZt2xZbf4RuAADKAmMkuz37lcPNLftF+AYAoNQidAMAUNoZI2VlZf9ps2W/ckK4MZK7O8EbAIBSyu3ymwAAAJfKCdcXjmrbbNnLOeEbAACUSoRuAABKs5xQnd9Its32VygHAAClDqEbAICy4FKhGwAA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AAAAsAihGwAAAAAAixC6AQAAAACwCKEbAAAAAACLELoBACjHunTpojFjxri6DAAArlqEbgAASsCCBQvk4+Oj8+fPO9rS09NVoUIFdenSxWnb+Ph42Ww2JSQklHCVAACguBG6AQAoAV27dlV6erq+//57R9tXX32loKAgbdy4UWfOnHG0r1mzRnXq1FH9+vVdUSoAAChGhG4AAEpAo0aNVLNmTcXHxzva4uPjdfvtt6tu3br69ttvndq7du0qu92u2NhY1a1bVxUrVlSLFi307rvvOvW7Y8cO9ezZU1WqVFFgYKDuueceHTt2LN86Pv74Y/n6+ur1118v9nMEAAC5EboBACghXbt21Zo1axzLa9asUZcuXdS5c2dH++nTp7Vx40Z17dpVsbGxevXVV7VgwQL99NNPeuCBB/TPf/5Ta9eulSSlpKToxhtvVKtWrfT9999r1apVSk5O1l133ZXn8d944w0NGDBAr7/+uu6++27rTxgAAMjD1QUAAHC16Nq1q8aMGaPz58/r9OnT+uGHH9S5c2edO3dOCxYskCRt2LBBmZmZ6tKli5o0aaIvvvhC7dq1kyTVq1dP69ev18KFC9W5c2fNnTtXrVq10hNPPOE4xuLFi1W7dm398ssvatiwoaN93rx5euyxx/Thhx+qc+fOJXviAABcxQjdAACUkC5duigjI0Pfffed/vjjDzVs2FA1atRQ586dNWTIEJ05c0bx8fGqV6+e0tPTderUKd10001OfZw9e1atWrWSJG3btk1r1qxRlSpVch0rISHBEbrfffddHTlyRF9//bWuv/56608UAAA4ELoBACgh4eHhqlWrltasWaM//vjDMeIcHBys2rVr65tvvtGaNWt04403Kj09XVL2PdghISFO/Xh5eUnKnv28V69emjlzZq5j1axZ0/F1q1attGXLFi1evFht2rSRzWaz6hQBAMBFCN0AAJSgrl27Kj4+Xn/88YceeughR3unTp306aefatOmTbr//vvVpEkTeXl5KTExMd/Lwa+77jq99957CgsLk4dH/v+k169fX08//bS6dOkid3d3zZ07t9jPCwAA5I2J1AAAKEFdu3bV+vXrtXXrVqcw3blzZy1cuFBnz55V165d5ePjo7Fjx+qBBx7Q0qVLlZCQoC1btui///2vli5dKkkaMWKETpw4oQEDBui7775TQkKCPvvsMw0ZMkRZWVlOx23YsKHWrFmj9957T2PGjCnJUwYA4KrGSDcAACWoa9euOn36tBo3bqzAwEBHe+fOnZWWluZ4tJgkTZs2TTVq1FBsbKx+/fVX+fn56brrrtOjjz4qKfuy9K+//lqPPPKIunfvrszMTIWGhqpHjx5yc8v9uXqjRo305ZdfOka8n3766ZI5aQAArmI2Y4xxdREAAAAAAJRHXF4OAAAAAIBFCN0AAAAAAFiE0A0AAAAAgEUI3QAAAAAAWITQDQAAAACARQjdAAAAAABYhNANAAAAAIBFCN0AAAAAAFiE0A0AAAAAgEUI3QAAAAAAWITQDQAAAACARQjdAAAAAABY5P8BuOFnE0nBsqwAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "\n", "# Assuming you have your dataframe as 'df'\n", "# If not, you can create a sample dataframe like this:\n", "df = pd.DataFrame({\n", " 'week': [1, 1, 1, 2, 2, 2, 3, 3, 3],\n", " 'kl_divergence': [0.1, 0.2, 0.15, 0.3, 0.25, 0.35, 0.4, 0.45, 0.5],\n", " 'off_by_perc': [5, 10, 7, 15, 12, 18, 20, 22, 25]\n", "})\n", "\n", "# Create the main figure and axis\n", "fig, ax1 = plt.subplots(figsize=(10, 6))\n", "\n", "# Create the boxplot using seaborn\n", "sns.boxplot(x='week', y='kl_divergence', data=df, ax=ax1)\n", "\n", "# Set labels and title for the main axis\n", "ax1.set_xlabel('Week')\n", "ax1.set_ylabel('KL Divergence')\n", "ax1.set_title('KL Divergence Boxplot with Off-by Percentage')\n", "\n", "# Create a secondary y-axis\n", "ax2 = ax1.twinx()\n", "\n", "# Plot the off_by_perc values on the secondary y-axis\n", "for i, week in enumerate(df['week'].unique()):\n", " off_by_perc = df[df['week'] == week]['off_by_perc']\n", " ax2.scatter([i] * len(off_by_perc), off_by_perc, color='red', alpha=0.01)\n", "\n", "# Set label for the secondary y-axis\n", "ax2.set_ylabel('Off-by Percentage')\n", "\n", "# Adjust the layout and display the plot\n", "plt.tight_layout()\n", "plt.show()" ] } ], "metadata": { "kernelspec": { "display_name": "hf_dashboards", "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.12.2" } }, "nbformat": 4, "nbformat_minor": 2 }