Distributed Machine Learning Model Sweeping#

There are two use cases for training machine learning models in a distributed setting. The dask-ml documentation does a good job of describing this. The first use case is more memory-bound problems. This is when the dataset has to be divided across multiple machines because it doesn’t fit in a single one. A single model is then training on the distributed dataset.

The second use case is for compute-bound problems. A data scientist has datasets that fit in memory, but they want to train multiple models and evaluate the performance in parallel. Extending this idea, big data often has logical groupings that can be used to partition the data. We can then train multiple models on each dataset.

This tutorial will focus on the compute-bound problem. For example, if we have a large dataset that spans 5 regions, we can train region-specific models. For each region, we can train 5 different models, which models in 25 model training runs. These 25 model trainings can be distributed on a cluster and run in parallel as they are independent.

Training Multiple Models for One Dataset#

Creating a Dataset

We start by creating a make_data() function using the sklearn make_regression() function. This function takes in a number of groups and for each group, generates a new dataset. This means that each group will have different properties when we generate multiple groups and benefit from separate models. For now though, we focus on the training logic for a single group.

import pandas as pd
from sklearn.datasets import make_regression

def make_data(groups=1):
    result = []
    for i in range(groups):
        X, y = make_regression(n_samples=100, n_features=8, n_informative=5, noise=10)
        df = pd.DataFrame({"group": [f"group{i}"]*100})
        df = pd.concat([df, pd.DataFrame(X, columns=[f"x{n}" for n in range(8)])], axis=1)
        df = df.assign(y=y)
        result.append(df)
    return pd.concat(result, axis=0)

Using this with one group gives us a dataset with 8 features and a target variable called y. The head of the DataFrame is shown below.

df = make_data(1)
df.head()
group x0 x1 x2 x3 x4 x5 x6 x7 y
0 group0 0.971978 -0.473416 -2.221027 2.066071 -0.371581 -1.806569 0.154867 -2.329968 -241.530733
1 group0 -1.178425 3.071536 -0.682251 2.039425 0.695598 0.340194 0.147516 -0.891319 -14.439953
2 group0 0.128803 -0.204161 0.581653 -0.769440 0.725207 0.192606 -1.250861 0.732403 78.005286
3 group0 -1.381550 1.391747 0.748421 0.187281 0.660580 1.665103 -1.303355 -1.869867 31.560241
4 group0 1.575359 0.926507 -1.364626 -0.267989 -1.179624 -1.589561 1.051079 -0.507540 -17.564240

Training Setup

We import some relevant libraries for model training.

from sklearn.linear_model import LinearRegression
from sklearn.svm import SVR
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error

feature_cols = [f"x{n}" for n in range(8)]
target = "y"

Creating the training manifest

For this single dataset, we create a new dataframe with the create_training_manifest() function below that will be responsible for orchestrating our training runs. We call this a training manifest as each row holds the metadata for one training run. The manifest contains metadata, the X and y of our dataset along with the model to use for training. For now, this may look like more work for a single dataset, but later on we’ll see how this can scale to Spark or Dask easily with this setup.

from typing import List, Dict, Any
import pickle

def create_training_manifest(df: pd.DataFrame, models: List[Any]) -> List[Dict[str,Any]]:
    group = df.iloc[0]["group"]
    X_cols = pickle.dumps(df[feature_cols])
    y_col = pickle.dumps(df[target])
    result = []
    for model in models:
        model_binary = pickle.dumps(model)
        model_name = type(model).__name__
        index = f"{group}-{model_name}"
        result.append({"index":index, "group": group, "X": X_cols, "y": y_col, "model_name": model_name,"model": model_binary})
    return result

Why use pickle to serialize?

There are multiple reasons to use pickle to serialize our data and model. First is that distributed operations are passed through a network. Using the serialized version reduces the memory footprint of the data we pass through the network. The second reason is that it lets us have a pd.DataFrame inside a cell of our training manifest. Last, the serialized binary type is also an acceptable data format for Pandas, Spark, and Dask.

We can test this function by simply invoking it.

create_training_manifest(df, models=[LinearRegression(), SVR()])
[{'index': 'group0-LinearRegression',
  'group': 'group0',
  'X': b'\x80\x03cpandas.core.frame\nDataFrame\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00_mgrq\x03cpandas.core.internals.managers\nBlockManager\nq\x04cfunctools\npartial\nq\x05cpandas.core.internals.blocks\nnew_block\nq\x06\x85q\x07Rq\x08(h\x06)}q\tX\x04\x00\x00\x00ndimq\nK\x02sNtq\x0bbcnumpy.core.multiarray\n_reconstruct\nq\x0ccnumpy\nndarray\nq\rK\x00\x85q\x0eC\x01bq\x0f\x87q\x10Rq\x11(K\x01K\x08Kd\x86q\x12cnumpy\ndtype\nq\x13X\x02\x00\x00\x00f8q\x14\x89\x88\x87q\x15Rq\x16(K\x03X\x01\x00\x00\x00<q\x17NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00tq\x18b\x89B\x00\x19\x00\x00\xfe*Sbr\x1a\xef?e\x18\xdf\x17\xd4\xda\xf2\xbf0tpr\xa1|\xc0?y\xa5\xb0\x89\xd4\x1a\xf6\xbf\x04\xda\n\xa9\xab4\xf9?H\x04<\xfc\xec[\xe7?\xaf4\xd7\xec\x81\x10\xed?\x8e\x13\xa6\x82\xb0\x81\xec\xbf\xde\xdf&m0\xc9\xf6?\x98+9\x04\xdf\xe0\xb8\xbf\xd0\x87\x0e\xa1\x86\x9b\xe6\xbf\xa8-\x9d\xb7\x82\xbf\xc3?\x83\\@\xdd8\xb9\xdb?\x96\xeaD\xaa*3\xe1?\xc2$~?\xaf7\xda?#\x82\xf4L\xb4:\xe1?\x9cD5\x01\x00\xc8\xe5?\xd6\xb3[\xc0\x03V\xd4?\xba\xdbJ\x1b7{\xf0\xbf\xe7\xf41\xe2\x12\xcc\xf2\xbf\xf8\xa9~\xfbK\x85\xdf?!\xe0\xfd\xe1\xe6\xa3\xcc?|=F7K\x0b\xd7\xbf\x1ewv\x84R\xf9\xf3\xbf\xbe\xb5\xcf4\xc8\xe0\xf0\xbf\x1dMkX\x8fI\xa4?D\xf1\x16R\x92\x01\xe2?\xfa\x90\\\xd0l\xfa\xc9?\xcd\xb9\xbc\xd0\xb0\xa0\xe0?\xd6\x96)0\xfe\xb1\x08\xc0\x16z\xb9\xa0./\xdd\xbf\xfah\x97\x1c+\xe7\x02\xc0\xfbX\xd4+\rT\xf3\xbf\x9e\x99\x15\x14\xae\xa3\xed?`\xd5\xea\x9149\xc6?\x0f\x13O\x82\xea\x92\xf5\xbf\xea\xde\x82\x0b\xbc\xc7\xe2\xbf\x9a\xb4\xc9\x9d3\x1a\xbd\xbf\xce\xcc\xca\x0f\xe8s\xdc?\xe0\xcd\xf3@Yn\xd0\xbf\xe0|3\xf8\t\xd3\xf5\xbf\xb1\xd2\x8f\xeap\xd8\xdc\xbf\xf8 \xd3\x86\x80\xb3\xcf\xbfp\r\x01#\x00p\xf4?:\x99x\x92m\xf0\xf1\xbf}a\x81\\L\x7f\xf9?1g\xf4\x1c\x10\xeb\xf6\xbf\xf9\x9a\xd7\xa6|\xa5\xed?)\xa2\xd7HW,\xdf\xbf\x135\xe8\x10\xcb\xe3\x03@"\xd1\x9c,2\x95\xd5?\xbb<\xb0C\xd6\xef\xa3?P\xfc\xafu\xba\xea\xc9?}\x12p\xfb\xe13\xea?j\xc8\x8a\xc0\xd4\xf4\xfc?vy\x93\xf3!\x92\xdc?\x9f\x89mt\xbf(\xe3?\xabH7\xd7\xc0s\x01@`Z;\xbf\x0b\x96\xc2\xbf6\x98\xb3\x98\xc0\x8d\xf3\xbf<\x84\xfc\xd8o\x91\xf5\xbfu\x9c%\x1c\xd1,\xed\xbf\t{\x1d4\xb6N\xdc?FYQ(\x05\xce\x8b\xbfn\x8d-\xfcg.\xd2\xbf\x9e\xde\x1c\xc4\x14:\xe5\xbf\xc9t/\xead\x1e\xde\xbf\xb3\x0b\xeeox\xef\xd3\xbf\xe5\xab\xe8\xdb?=\xec\xbf\xde\x16*\xa9\x83d\xf1\xbf\'2\x10\x7f\xcb9\xe3\xbf7e\x98s\x97\xe8\xec?l\x05\xf6\xe7\xd5\t\xee?,\xdc\xaet\x1d\x05\xd1?\xb1\xf6\xea\x86\x89;\xf4?\x17f\x93\x11\xe2n\xf4?X\x16h`e\x8b\xc8\xbf\xe9,u\xf9v\xda\xaf?\x82\x16\x1e\x02\x7f\xf4\xe4?\x14S\x00fge\xe3\xbf\xe2\xcf^\t\xd9\x91\xeb?\xdeh}+89\xec\xbf\xee\xd0\x83\x04c!\xe4\xbf\x84\x86\x04\x03m\xe6\xbb?\x1e\xf2A\x90\x8bi\xe4\xbf\xeco\xf5\xd1\xde%\xc1\xbf\xb2\rU\xf0\x02\xc2\xf7\xbf\xfa\x93\xa4\xc92\x8e\xed?\x9a\xad\xb7\xe0\x97\xce\xd6?!\x9aX\xee[\xcb\xf8\xbf\x9e\xbe\x8c\xa7&\xc8\xcd\xbf\xbdR\xae\xd6n\xf8\x92?p\x95\xc2\x01\x89\xdb\xdb?oa\xc5 \x83\xc2\xee?\x96u\x94.\x8a^\xe1?\xdb0\xfd`J\xf4\xd8?\xdf\xd8{FD8\xe0?\x84\xff\x92\x7fMQ\xb0\xbf\xc0c\xc1\xa5\xd3\xe3\xa6\xbf\xba\xdd\x1cM\xd2g\xfc?rd\xdb_sL\xde\xbf\x88\xf1\xda\x88\x81\x92\x08@\xd6n\x0ce\xef!\xca\xbf"\x92\xb7\x84\x98D\xf6?\xcc\xd7H\xa9\xf1\xa5\xed?\xc5\xab\x96\xf6\xff\xf0\xbf\xbf\xddk\x9b\xffAX\xf3\xbf\x83{\x8a\xd6>M\xd6?\xb1\xf1\x1d!\x95)\xff\xbf`\xfe\xdbQ*{\xd2\xbf`\x1bT`\\\x93\xec?^C\x1bp\xdc\xba\xb7?\xfcmv\xfa\xb33\xe7?r\x82\xce)\x84*\xf9?\xd7\x9f\xdf:0\xd6\x01@\x17s>\xe1\xebF\xf4?9.^\x9a\x8b\xb5\xa6?\xcc\xcd\x8a\xb9Qa\xbe\xbf\xdab\x03\x98\xbdK\xc1?l\xc6\xfa@6S\xe9?\x1b\xe6\xc5\x9f\x13*\xe6?)\x1aIl\xdf\x88\xe0\xbf\xebg\xe8\x01\x88\x91\xdf\xbf\xc6\xe9\xb3\xe8\x94\xef\xd7\xbf\xda\x1c\x17\x90\xf5\xd3\xa5\xbf\x91U\x9e\x9c\'\x86\xf2\xbfF\xb8\xea\x8c\x0f(\xe3\xbf}\xdc\x14\xfdvk\xf4?\xffJ\xe2c\x19\xc7\xc1?\xe2\x95\x86\x0clZ\xd5\xbf+\xb0\xa7\xc1\xb4\x98\xa3?\x94\xf7\xab\x95J\xa2\xf3\xbf\xc4\xef4\x1e\xb4\xa8\xef\xbf\xb4\x03>\x80\xc9\x04\xf5?\xbcm\x8f\xdc|;\xdd\xbf2\x10\xfc\xe1DF\x00@w\xff\x93\xa4\xea\x08\xa8?&[\x9b\xa8\xd0\xdb\xc3?\\>\xd9)\xbdo\xca?\x87L\x98\xda\xc2U\xfe?I@\xb5\xfdr\x17\xce\xbfB\xf2t\xb9\x19\xb1\x9a?:\xef\x82,=e\xe2\xbf\xfa\xb7n\xc7E\x95\xbc\xbf[oc\x94\xd8\x0b\xf9\xbf\xe4?$\x91z\n\xee?\x17\xbb\rG\xd6\xbe\xd3\xbff\xf0\x03B;\xda\xee\xbf\x90\xba\x8d\x8a\x82\xe5\xd0\xbf\x93aE\xa1.\x83\xe0\xbfT\xea\xd3;<B\xf2\xbf#\xa9Hn\xc3"\xea?U7\xe7\x0f\xdd\xfe\xcf\xbf,<?\x82\xe4\xe2\xdd\xbf\xb8\xda\xd9\xacJ\x1c\xdf?}lI\xb9\x96\xa4\x00\xc0\x96\x10\xbd\xad\x9f\xcd\xd6?2\xa6\x8d\xd0\x8fw\xe3\xbf\x99\xea\xa8\x9b99\xe1\xbf\x08\x19V\x85b\'\xdd\xbf\x14cq$\x0c\xd8\xe0\xbf\x0e\x99\xc77y\x9d\xe6?\xa2\xeb\x13\xb3X\x16\xe2?\xc0m\xaa\xa3\x00\x84\x01\xc0s\xd6y\xf9\x8e\x14\xda\xbf\x8e4Vf^7\xa3\xbf\'\x12\xacpK\xcd\xe0?\xe9\xf5\xc4"\xe0l\xac?\xfa\xa3)\xae\xf9C\xd4\xbf\xccI\x8aH"\x84\xeb\xbf,\xea\xde{@j\xb2?\xb1!L\x03\xdbAp?\xd7{\\0\xd4\x02\x03@\x1a\xa4\xa6Xjt\xc7\xbf\xdb\xdc\x17\x88~\xe8\xdf\xbfJ]\x88\xf9s9\xf8\xbf/2\xe1\xca]\xee\xb8\xbfK2\x8dAb.\x02\xc0l\xab\xbf9\xeb\xde\xcf\xbfvz\x8cH\xebe\xf0\xbf>\xe5\xd6\xcf\xde\x9f\xfb?"#\xc9\xfa\xce\x16\x1f\xbf\xee\xd6B\x87\xea\x11\x00@R\x85>\xb0 \x8c\xf2?b\x81\xe6~\x87\x83\xf6\xbf\xe3~5\xed\x96\xe9\xdf?\x97&~\x8cD\xba\xcb?W,\x04V\x13\x08\xf1?\x9c}\x1ff\x9dv\xcf\xbf9\x03\x86G\x03;\xf0?\xd4Nw\xe1"\x8a\xe3\xbf\xa9\xbe\x02\x8b\xde%\xd7?\xd6\x8cOA\xd0\x95\xd4\xbf\x00R\xe9\xbd\xf3_\xf8\xbfZju\xae\xc5\xea\xf1?\xb9\xf2N\xff\xec\x05\xd1\xbf\x99\xad\x84;\xcd\xee\xe3?\xaeJ\x9d\\\x8d8\xf6\xbf\xa7\x9el\xba\x9d\xb7\xfe?\xf2\xe0@\x88\xfc\x9e\xd8?\xa3jR\x96\xa9\xc4\x01\xc0\xbb\xcc\x12\xf8\xff\xd4\xe5\xbf\xca\xf5R\xcf\xe6\x9c\xe2?\x0b\x7f?\xbe\x0f\xf3\xe7?9?\xd2&\x82\xd5\xf5\xbf\x82\xcdd\xca\xd9t\xca\xbf\x84PVz\xe1N\xec\xbf\x04\xd3\x9bl<R\xcf?\xec\xbd\xff\x11w0\xd6\xbf\xcc\xbc\x95\x16\xc2w\xf1\xbf\xaa+\xa1\x92Ml\xac\xbfo\xcb.\xb7|\x86\xa8?\x00\x81B.\xec\xb0\xe3?8\xdf\xa4\xba\xcfk\xd0?\xa4\xc9\xf7l\x83\x93\xe4?\xef>v\xf1\t`\xe0?\xdc\x80\xb5\xce\xdb\xfc\xe4\xbf\xceG\x1b\xa7K\xcb|?\xf1\xfa\x9cB\xec\x90\xea?\x10\xe0\']\xd2\xf4\xe0\xbf\xcd9\xa2B\xeb\x8d\xc7\xbf\xa0\xac\xeb\xf2\xfd#\xf6?\xe5\xb1\xe1\t\xb2\x1f\xdf\xbfH$\xb6\x01C\xbd\xf6?z\xdf\x969\xfc\x1b\xf5\xbf\xba^\xd4h\xc4\xa2\xe4?\xf3,\x1e\x05-\x0e\xec?f\x98\xe6\xc9S,\xf0?%\x92Eh\xd3\x1a\xb4\xbfHj\x8d\x1a\xcd\xcap\xbf\xdb\x12C6\xd8\x15\xee?p\x86\xc6\xc0\xe2H\xda?\x0bb=^\xcf\xe0\xde?\xd8]\xa5\xa9dP\xf1\xbf\xd7f\xf1\xd9o\xe4\xd3?\x132\xfc\xd1\x90\x14\x03@\xfb\x15\xaa\x0f<\xfa\xd4\xbf\x8b\xf3;\xbeL\xac\xe5\xbf\xc7F\\/\xd7\x92\xfb?;\x05\x06\xd0s.\xc3\xbf\xa0\x8e:+\x99\xfb\xd7?V\x1fJ\xecN\xdb\xa5\xbf\xc5+\xd4\xf4\x924\xe5\xbfBi\x8f\xaa\x12\x15\xdb\xbffQ\xd8\xd1\x7f\xcd\xcc?\x90=J \xf6\n\xd5?\xdeq)+\x9c\xe5\x02@._\xb5\x1b\x15\xc3\xee?\xd4\x944\x92\x18<\xe9\xbf!\x94\xe8\xeer\xe7\xf1?;n!\x1aX8\xc7\xbfQ$\xa8v\x84\xc6\xe7?\xc9\x17\x92\xa7B\x01\xce?5eCM\xee\xad\xf3?R\xdeg\x947\xd7\xe6?@\xc2\r\xbb\xf2J\xe9?\t\xa9r\x0e\xd0\xaa\xd1\xbf4\x01"\xcb\xf5\x84\xcd\xbfm\x1b\xd0\x11\xd1\xfd\xf6\xbf\x10x\x9c~ \xab\xed?e\x9d\t\x84\x8eI\xeb\xbf\xad=\xf0f\x8f\xfe\x8c?\xea\x93\x14}"\xa6\xda\xbf\x98WU\xb7}c\xce\xbf\xcce\xa2w_i\xe1\xbf)\xef7L\xa5\x7f\xf5\xbf\x93=\x15k\x83\xf9\xce\xbfe9\xbd\xb6\xabx\xdc?\xa4\xcbE\xab\xc6\xc0\xbe?\xd2\xcbM\x8c\x1d\x94\xd3?\x9ct\xb0\x16\xe4A\xf1\xbf!d\xd2\x11sZ\xf4\xbf\xe3\x15P\x0eq\xf7\xee\xbf\x1e- \xab\x93\x96\xc3?\xae\xe0\xcf\xbe\xa68\xd7\xbf\xa6\xa9\xa9\xc3J\x0f\xaa\xbf\x17%+ZfJ\xb7?\x00\xc6Z\xf8\x82u\xf5?\x94\xf9#\x0e\x05\xe2\xe6?g\x9a\x0f\xb5\xbf\xf0\xea?h\xd5O\x92\x11\xa8\xf5\xbf\x94u_\xa3k\xfa\xf0?\xeei\xf2\x85\xb9h\xdb?\x13\xe9r\x1f\x8dI\xaa\xbf\xaf\xbc\x15\x81\x895\xea\xbf\x82M\xd6\xb3M\x0f\xf4\xbf\xb2n\xe2\x1c\x96\xf9\xe0\xbf<\xecT\xe8\xf9\xcf\xda\xbf\x04$\xb3a\x94\xbe\xf6\xbf\xa3\x85\xfcH\xe2\xad\xfc\xbf\xb7\xb1:\xd0\x16j\xf1?\xa4\xf3\xa7\x90\x92J\xf4?VqR\x06\x9e\xcc\xee\xbfCW\xc0XN\xb5\xd3?\xfd\xb4\xb4s_\x8f\xf8?\n\x0e\xa0\xf7\xeay\xfe?\x9f\x94JZ\xc8a\xe1\xbf\xc8\x8bC\xea[r\x02@\xfa\xcc\x03%\xef\xe6\xf3\xbf^\xe5\xdc\x874i\xd3\xbfj4\x19;P\x87\x00@i\xd6\xb7+\xbeP\x00@\xd1\x91\xc0\xf9?\x9f\xe8\xbf\x12\x02\x81\xfb\xcf\xf8\xc7?)a\xf1\x9c\xb9&\xd1\xbf\xd4\xdf@\xb2\xee\xb7\x00@=\x9c\xe9/\xf8m\xe2\xbf\x0b0\xea\\a`\xe9\xbf\x1a\x86\x85D,\xeb\xf1\xbf\xb4)\xe6\x08\'\xb8\xd9?\x8a\xb0EN\xcb\x99\xf2\xbfr\xf80\x93\x10\x99\x03@\x08\x83\xd66&\xaf\xdf\xbf$\n!\xdc\xaaz\xd8\xbf\x17\xd6\x04\t\xa3\xb0\x89\xbfPY\x85\xc8c=\xac?r\xff\xec5U\n\xdd?i\x03\xd5t#\xcd\xf3?\xf4kc\x04\xe5\xc4\xe5\xbf\x98\xb1\xbf=\x0b\r\xd8\xbf\xef\x11\xc2\xf7\xe7\xd2\xf3?\xe92SQ\x15`\xe6?6\xe6\x8aY\xe7\xc6\xe5\xbf\x97\xce|\xc2R\xd5\xe2\xbf\xca\x87\xe5\n\xb5\xc2\xb0?1gA\x0e\xc4(\xe5?"8\x02io\xbe\xe6\xbf\xae56\xa3-\xcf\xdf\xbf\x9a\xb5Vr\xa1 \xe0\xbf\xce\x9c\xee\x1aVB\xe9?\xc0Ub\xca\x99\xd6\xc2\xbf\xa8\xe7\xfa96\x03\xe3?h)\xfa\x0cQru\xbf\xe0\x8f\x89\x9d\x11T\xca?\xad\xb5\x99mo\x8b\xfd\xbf\t g0\x85\xb1\xe4\xbf:6\xf5\xe0\xba\x16\xe5\xbfP\x1fk\xb7\xa5\xee\xe4?v#=\xd2\x10\r\xe3\xbf\xd0ExU\x86\xfd\xf7?\xa5G\x7fH\xa3\xd1\xc3?\n\x85\x88o\xe1\xa0\xcf?\xeb\xa8uJO\xf0\x01@\xc2\x1c\xb8\x84\xcf\xd5\xfc\xbfS\x99t\xf51T\xfd?\x9e\xa5\xea\xde\xacP\xc2\xbf\x1f!Oy\xe1\xf0\xdd\xbf\xb7\xf7\xea\x0c\x8b\xba\xe2?9r\x0e\xc2\xa3O\xdb\xbf\x13\x80\xa5\x1ek-\xd3?h\xf9\xe7P!\r\x01\xc0\n&K&#s\xf1?\xa2;\xe3\xc9e\x86\xb4?\x95e3\xdf\x84\xbe\xd5?\x16Q;\xdf\xa5\xa8\xe2?!GO|\x8bh\xfb\xbfg\xc3\x11\xc4\xfaT\xd7?t\xd4\xc2M\x90?\xe2?\xce\xd5\x07\tu\xf3\xf1\xbf\xc6\xb9\r\x9b\xfd\x15\xf7\xbfz\xa0O|7l\xf0\xbf=\x1b\xf1\xef4\xc5\xed\xbf\xc7\x9a6,\xa5\x0c\xe3?\xa6\x05w\x98\xf5\xb9\xdd\xbfOb\xfb\xd0\xc3\xd4\xf9?\xfa\xdc\xdc\xae\x11\x87\xe3?\xa4\xd0v\x8f\x99:\xf3\xbf\xf9nBs\x8f]\xe6\xbf\xd5{\'C\xdb+\xf8?KO\xf4D@\xa7\xd4\xbf\xaa\x9aM\x17\xc2{\xf9?\xed3\xcf\xce1\x1c\xf1\xbf\x97\xd7g\xf3\x00\xfd\xd5\xbf\xb6\xc93\x98R\xad\xf6?\xd8\xdcG\x15\xda\xfb\xea?\x19\xbcM5h\x01\xf5\xbf\x91\x0b\x83\nQ1\xc4\xbf\x0f\xe5\xb3\xc3\x9c\x03\xed\xbfF\xa9y%&l\x9c\xbfK$\x1fZ\xf9\xd7\xe9?\x06\x7f\xba3\x94t\xfa\xbf(\xec\x88\x85\xa7\x88\xfa\xbf4\xd5Q]~F\xd4?C!\xa8\xd9\x0c%\xe1?\xe0\xcb\xcf^\x0c\xc7\xf1?d\x9dJ\x9fYF\xf4\xbfm\xc8\x0f\xb6t\xb9\xf2?\x8fu.\x02C^\xcc\xbfB`\xd8\xf9L\x98\xea?\xf7(3\xefm<\xcc\xbf\x8c\xfa\xe8\x9aC\x1a\xf2?hj\xfc\r:}\xd7?\xa9a\xb6\x98\xda\x0e\xe8?\x82\xb8J\xfe\x11\xd3\xe2?y\xd3q\x7f\xc6\x08\xe8\xbf[\r\xb8\xce\x0f\xd5\x93\xbf\x84U\xf3<y3\xe7\xbf\xbbJ\x8e\xb9\x89\t\xe7?j\xd6\xe8f\x8f\xca\xd1?\x9a\x8f\xf6\xa9\xa9\x06\xd3?\x1d+\xae\x06\xfd\xc7\xd7\xbfeQ\xa8\xf2VB\xe6?<\xb5\xb8\xbf\xe44\xe7?@RZ\xc8x#\xe5?m\'\xb6\xca\xbd\xdf\xf2\xbf\xd9\x1d\x94\xd2\xc4\x98\xf9?\x12\'h\xf0\xab\xc2\xe7\xbf\x08G\x0cMaD\xcd?\x08r\x1b`d8\xed\xbf^ M\x9a\xc0\xc5\xea?,X\xb3Q\x8f\xbe\xb7\xbf\x91\xa3\xa0h\x08\xc1\xc0\xbf\xddk\xd1\xf3i#\xf3\xbfGK\x85]I\xab\xf3\xbfg\x0b\x92\xb8\xef\xfc\xd2?\xb7\x92\x88\x9c%\x01\xe3?{Ty*\x00\xba\xee\xbfs\xeb\x81\xa5\x7f<\xfa?\xc2r\x8a\xd1]N\xee\xbf4\xe2k&\\\xd2\x9d?\xf8\t\xcb\xb5\xfa\x83\xd8\xbf\xbbCn\xa7^\x85\xe0\xbf\xee\x06\xdf6\xca\xc3\xd0\xbf\xba\xb0V\x8d\xad\xb3\xa1?s\xd0\xdbK>\xf7\xd6?\xe9\x8a\x80\xc17\xc8\xc8\xbf\xffM\xf1f\x1b(\xeb?\xbb\x05h\xe1F\xd5\xf7?#\x97\'\x99\x0c\xf5\xe4?\xfa\xea\xc4\xbc\x1c7\xfc\xbfp\xc4\xb3\x05B\x81\xbc?\xea\xd7rj\xb3&\xda?\xcd\xc2Ox\xe6\xb3\xd1\xbfK\xfd\xd3-\xf7\xf0\xe4?\xd1\xf1\xb3\xd8\xd8\xfe\xda\xbf\x9b}i\xd5,\xb7\xfd?*\x84\xa5z\xfc\xa6\xd3\xbf\xa9x\n\x9e\xd1\xe3\xf2?\xdejAd\xf3|\xb6\xbfI\x93nOK\xc7\xe2?\xb0\x04\xe2D\xa0\x80\xb9\xbfd\x0c\xab\xd8\xda\x98\xf6\xbfw\x8a\x87\xf2\x06\xa4\xdb\xbf\xe2\x0f\xfc\xf5\t\xc5\xe4?\x1ezx@9\xbc\xfa\xbf\xc67\xec\xd24 \xea?\xd2\xc5C\xb3c\x01\xea?F\xf4\xbe-\xad\x83\xfb?\xad\x00\x04\xc7\x98t\xb3\xbfz3\x8e\x87\x85\xf9\xde\xbf\n\xee8\xae\xff\x1c\xee\xbf\xe3\x84k\x1fSb\xd2\xbf\x12\xa5\xc2_\xa5\xcf\xd9?\x14F\x92\x19\x96\xe0\xe2?\xd9\x81$\xf3\xbd\xb4\xf4\xbfJ\xfda\xab\xe3{\xda\xbf!GM8\xdf\xa4\xfb?\xb8/9\xe0&\x95\xe2?\xc5\xe9"\xf7\xfa\xb7\x08\xc0N\xff;\xcdc\x0b\xef\xbfS&js\xedX\xcf?\xe1yq\xfaO\x80\xee\xbfg\x89-\t\xf8=\xe1\xbf\x85\x1e;\xcb\xa1\x11\xf7?G0\xf3\r\x03\x93\xfb?\xe68\xac\xb5\xda\xee\xf9?F\x9c\xa2\xb3M"\xe0\xbfb\x8ev_\xebR\xf8\xbf\xf8i\x1fR\x99\xe9\xfb?\x88\xdf\xd3\x19\x14\x14\xa7?\x82W\xe9\x96\xb4(\x03@\x89\xc3\x07\x9b\xad\xd9\xcb\xbfA:\x1e\xb3\xcb\x93\xeb\xbf\xb4\x87\xf8i\xbf\xf9\xb5\xbf\xf6\xe9\xa2\xebP\xa0\xa0?N,3T\x1f-\xfd?a`mL\x03\x14\xf7\xbf\xff\xd8\xf0\xbe\xa2\xed\xe7\xbfX\x8b\xcf?\xb6\xb7\xf6?\xd9\xf3\xd3\xf1\xdfF\xf6?\x18s\xdc\xdf\xe1\xf9\xd2?\xdbSb8\x7f=\xe4\xbf\xff\xa5b\x04\x91<\xeb\xbfl*\xee\xe4\xa2\x15\xd2\xbf%(\n\xf1\x916\xbd?UH\xfc\x95\x85,\xf1?\x05Y\x8dV\xcf\xe2\xf2?\xb5z\x10\xf8\xe8/\xf4?-\xd2\xd8\n\x84\x9d\xe1\xbfd\x05V\xd2c\xe4\xf9?U\x9f\x92/M\x18\xf5?\x15Y\xf2\xb0\xc1\xcc\xfb\xbf\x8fq-\xc9e\xf7\x04@\x8b\t\xb0f\x89Y\xe4?\xecV\x06\xb6\xd1\xbf\xa3?R\xd8\x02\xcf\xd2h\xec?\x02q\x84t\x0c8\xfa?\xaf,\x1b\x9a^\x14\xef\xbf\xd8\r\xa5\xed\x19\x86\xda?4e\xb7\x90\xf5\xaa\xe1?\xf1\xd0\xc0\x10\xb5\xe7\xfc\xbf"\xd9Z\x19\xbc\xc5\xd5?\xf9\xba\x7f\xb7L\xa7\xc8?\xb8\x00w\xe1B\xa4\xfa?W\x8f;\x8c\xd7n\xf9\xbf< _R\x158\xe4\xbf\t\x11\xff\xf8,q\xdb\xbf#\xd3\xb6q\xf3f\xd7\xbf\tF\x99$\xf0\x14\xf8\xbf5V\x18u\xb7<\xd3\xbfY\xe6$\x1b\xdd|\xd6?\x1cT\xb9\xe8\xcc\x82\xe5\xbf\x86c\xaa9^,\xec?\x82\xc7\x16U\x08s\xf7\xbf\xd1i\xcf\x08\xa0\x02\xe6?j\x0c\xcd\x93\x17E\xb7\xbfn\xdbl\x1b\xeb\xd8\xf8\xbf\xeb\x82p\xbf6\xfe\xe6?\xb7\x05+w\x01\xca\xf8?S\x8b\xcc\xea\xa8z\xe0\xbf\r\xe7:\xb8\xb6\xae\xe7?\x18\xc1\x0b\xecy(\xfd\xbfGG\x94:\xba\xb5\xea\xbfBJL\xc9\x84>\xdf?q\x11\xb5\xd8\xce\x12\xe5\xbf\xa3\xae\x0c#x?\n\xc0\xf5\xef\xa7_ys\xdb?)\xe7\xd2\xd7d\x9a\xfb?\xea\x855\xe0\xa9s\xe6?.\xec\xec\xdd\xe53\xcd?&\x86\xb8\xef\xefE\xf6?\x08\x83_(w\x88\xf9?\x15\xdagL\x0ej\xd2\xbf,\xd1O\xee\xdf\x03\xea\xbf\x8d\xe2\xcd`\x10W\xe8?\x8d\x97\xed\x94+\x18\xf2?\x81\x8aN\x1cN\x85\xf1?\xa6f\xa6\xed\x14m\xcd?\xf4\xb8\x80\xa7e{\xf8\xbf<2\xc2>\xac\xb2\xd8\xbfE\xc7U\xae\xce\xf1\xfd?\xbe\xd9\x14\'T\x93\xdd?8\xd4,\x87\x98o\x8a\xbf\x02\xfb\x14\'`;\xe3?\xa6\xfb\x03;\xbei\x88\xbf\xf3\xfe\xbe\xedp\x12\xfd?\xd5\x87\xc4$c(\xde?\xb6\xd8\xabb\x8e\x0f\xa3\xbf\xca\xdc\x9b\xa0\xf9\xd8\xf7?\xb0\xcd>\x17=q\xe7?(\x9aAL:\x14\xc7\xbf\x8c\xae\xdbH\x94\x94\xe1\xbf\xe7\xc7\xc5W\xa1\xa9\xe3\xbf^T\x82\x9arV\xcd\xbf\xab\xbdE\xd9\xaa0\xef?>\xd1\xeeNp\xdf\xe1\xbf\xad\xc7\xeb{\x08\xa8\xe4?\xa7r\xe0\xa8\xa2\x93\xe2\xbf7y\xe7,\x15H\xd9?25|\\\xda\xe2\xf3\xbf)\x9f\x16>\x8e\x04\xf8\xbf`U\xfe\x005\xd4\xef\xbf~\x01CQ\x07\xbe\xd4\xbf\x11\xb5\xd8\xed\x06\x94\xea?j\xe6\xa2r-\xa7\xfe\xbf\x0e\x15~\xcc\x97\x19\xed?\x11\xe45!\x14\xbd\xcc?>706M4\xf4\xbf\x16\x1d\xc6u\xb9\x1f\xe1?<\x17\xcb\x94\xd9\x9d\x03@\x04\x18\xd6\x1f\xec\xff\xaa?C6[\x1fc\xc5\xb2?Z\xef\xcd\xd4\xd5N\xf1\xbfR\xd7\x04J\xda\x0e\xe2?\x80]x\xc1\x01e\xdb?\xff\xf7\xf3\xb4\x11Y\xee\xbf\xd2\tH\xc1\xb8\x8f\xde?\x98\x8e\x05\x8e\x1b\x96\xec\xbf?\x14\xb9\x95\xe8-\xee?\x19\x92C\x97a\xc3\xc6?\x91\xe9.4f\xc3x\xbf\xf0!8\x95\xc9\xdf\xca\xbf\xdf\xe7iQtF\x9f?\x17\xb7\x91\xd6\xe5?\xe4\xbf\x07 2\xce\xc0_\xed?|\x99\x16\x14\xda\xc5\xf2?IoVi\x1d6\x02\xc0\xcfbq\xc0\x94\xcf\xec?.H\xde\x12\x89\x1a\xf1\xbf\x81\x9a\x940\xf9\x07\xf3?0\xfc\x8dzlW\xe0\xbf\x89\x95\x17\x84\x1b\xd7\xa5?\xdaq\xdax<\xac\xec?D\xb7\x13>\xd0\x97\xf1?\xde\x06\xf9\xb4\xb9\x96\xf7?\xf3\xfd\xe6kt<\xe7\xbf\x95\xcbn\xb1\xff\xbd\xe4?JI\xd4\x18\x97\r\x00@\xfa\xbc\xaa\xad/\x97\xfa\xbf-\r%\xc7\x1c\x1c\xd5?\xddq\xbe\xf9\xae\xd2\xc3?\x05E5h\xcd\xe1\xc2?\xc9\xef\x82B\x87\x03\xf4\xbf\xa7\xf3}\xa7\x8a\xda\xf4\xbf\x1b\x96\x1c\xc07\xd1\xf0?)\xa1\xa0u\x87\xf0\xe1?\x8b}\x90\xe1\x10s\xed?\xae-;\xfbu:\xd9\xbfI5\xd91w\xc8\xdd?T\xf0m\n\xadi\xf4?J\x0b\x02_\x81M\xd7?\xd6\xa2F\x9b\x9c\x9b\xc3\xbf\xfdq)I\xa2\x05\xe1?U8\x14\xdc\xee\xf3\xdc\xbfy\x12\x08\x92\xf5\xda\xed?V\x04N#\xbc\x82\xf7?\xe4\x07\xc4r\x88\x1a\xc0\xbf\xe5o!6f\x92\xf2?\xc0\xbc\x1b\xef\x80\xac\xe1\xbfA\xfeR\xd3v\xa3\xb8\xbf\xb2\xd6\x83\xa6\xcas\xe6\xbf\xcc\x0e4f\xe8\x1d\xf4\xbf\xbc@gb\xbf\xa9\xfb\xbf\xf5\x00\xf6a\x91\xd4\xf6?\x88\x90\x91\xb8-\'\x02\xc0\xa5A\x12\xb8\xd9\x0b\xe8\xbf10\x89\xd4\x0bz\x04\xc0\xee5S\xdc\x83Z\xe0?\t=H\x90\xea\x8d\xda\xbf.\x8b\x07\x8d\ri\xf9\xbf\xba\x01\xa5\xd3\xc0\\\xd1?\x13\xa8L\x9b\xc9\xa3\x01@nzG^\x16\xac\xe5\xbf\x9b\\L\x05\xde\xd3\xdd? \xc5\xb2\x08;\xc8\xce\xbf\xc0e:mx\xa7\xf5?\x1ch\xc8k\xa7P\xe9\xbf=\x86\xd5o\xfe\x00\xd2\xbf\x19\x8b\xd3\xd4[\xb9\xbe\xbf\x9c\x19\xea0=\xba\xdd\xbf.1K\x87\x00>\xe7?@\xc6\xa1\xbf]R\xcf?}\xa5\x0f\xeb\x83{\xa0\xbfQ\xc6\xd7\x1d2\x8e\xe3\xbf\xc7+\xe1\x80bu\xcd?\x97H\n\x11\x7f\xda\xd6?\xa4M 8\xb0\r\xe2?\xbb\xcb\xb2WK\x87\xeb\xbf\xf6\x8e\xbe\xd7\x07T\xe6\xbf\xe8\xc6\xe8@\xbf\x8d\xf9\xbf\xb6%\x98O#\xd2\xf3\xbf$6y\xd5P!\xc1?\xf4\xe5k\x17\xefw\xf1\xbfqU\xa7\xa5\xd4\xa7\xd6?J\xba}\x16\xfcw\xd6\xbf\x1a&\xb3\x02\xe8\xa1\xd6\xbfP\xc2\xf0\xc9\x8e\xd3\xea\xbf\xa4Y\xd3v\x9b\xf3\xc9\xbf\xbd!\x94\xc1a\x1f\xef\xbf\xb4L\x82\xad\x80.\xfb?\x91s\xe3\x06\xea\xac\xf0\xbf\xb4\xfd]\xe3\x13&\xc1?U\xa3\x96\xc7\xd9\x02\xe2\xbf\xfd\x04\x03i\x02\xbd\xc9\xbf\xee\xb6\xf3mF\x1c\xd9?\xf0o\x1cn \xd0\xe8?\xb9\n\xc0}\xbc!\xda\xbf\xe0\x06Y\xd1\xcd`\xf6\xbf\x1e{q\xa3\xe0r\xe2?\xc3 W\xe7\x88Q\xf5?\xc5O\xaf\x89\xf9\xe0\xde?P\x89\xf9|\xda7\x01@\xed\xce\xac\x04\xeb\xb7\xdc\xbf\x0e\x1f\x1fSd\x85\xd1?p\xff\xd6D\x91_\xe2\xbfmQu\xaf\x134\xba\xbf\xa9B,`W\\\xe3\xbf\x0f\xb0!\xfc\xf1o\xf1?\xcf\xe7{\xbbak\xd2\xbfTf\xf8\x83\t\xce\xeb?\xdf\x9a"\xc6\xb0o\xe1\xbfT\xb7a\xf0p\x8a\xe9\xbf"\x03\xd5\x1e\xaa\x1d\xf1?\x03w\xccd\x19\xfd\xf1\xbf\xdd\xfcfS\xbb\xbf\xe9?eP\x190\x8d.\xb4?X\x01d\x92\xc9\xba\xf4?Dw\x02\xc89\xea\xf2\xbfB\x81)>\x12\x16\xf1?n\xc9\xadKF\xc1\xe7\xbf\x84\xbb8Y-\x90\xeb?j\xb6\xf3A\xe6\x95\xcf?p\xe5\x9e+KV\xe3?\xee\xc1-\xe5I)\xe9\xbf\x18\x8b\x91\xc9\x89\xcc\xeb\xbfA\xbf\xb6}\xe4\x00\xeb\xbf4\xbb(\xe6\x01\xd0\xe6?\xfe\n\xf5Z\x9c\xf3\xd0?;\xf0A\xe8\x92\xe0\xf4?\xdf;\x95i\xad\x15\xc6\xbf\xcaZ\x0c\n\xc6\xa3\x02\xc0$\x06\xbam\xb0\x85\xec\xbf\x13=)U\xd9o\xe7?\xcd\xd1\xd1w\xf9\xea\xfd\xbf\xf4\xc4\x8b,\xc5=\xe0\xbf\xdf\xec\xb7\xa5\xd3\xd1\xf2\xbf\xe4\xb09P \xf4\xe1?S\xa6\xd9\xcdl\x87\xbe?\xa5\x8cE\x11(\x8f\xfa\xbf.GkY\xcd\xac\xf7\xbfbS\xef\xbb,z\xea\xbf\x1f\x82S\xd9\x900\xc1\xbf\xd8v/\xb4\xb0\xad\xc1\xbf\xe3\x02\xa6\x9b\t\x08\xc5\xbf2~\x8d\xbe=\xe4\xe2?uf\x8f\xfb:\x89\xff?\x1f\xee\x192\x84\x9d\xce\xbf@r\n\x96\x16\xf6\xad?\xb8\x9a\t\xff\xea\x87\xd2?q\r\xee$\xe7\x85\xe3?\xb0\xee\x19j}\x18\xf7?\xf6{\xbdlt\xff\xd1\xbf\x06Y\xd8\xf5\x17\xa7\xf3\xbf>\tl\xec\xc6>\xde\xbf\xd8.\x85v\x7f\xd7\xf3\xbf\xb3\xc4\x1c\x12\xab\xbe\xe9\xbf\xc2M\x8b\xbe\xb0\xd6\xd3?\xca=\xea\x13\xd0F\xe7?\x1e\x89\x8f\xe2P\x17\xb7?j\xc2\n\xa9\x10$\xd6\xbfr\x1b2\xee\xe7\xbf\xf4\xbf\xe5k\r\x9c}u\xdd\xbf\x83\xcdz\xe6\x9d\x88\xd9\xbf\xab\xea\xf78#\xc2\xf1?\xfb\x9b\xcc\xf3*&\xce?\xc3\x08z\x95k\x85\xb3?\xe2F\x14\xb0\x8e\xd6\xe4?\xfe\xa2\xb3\xc4\xea*\xde?\xd9\xfc\xbf\x86\xc0\xbe\xd1?\xec\xa8\xdc\x91Q\xa4\xe2?\x8dWR/n;\xea\xbf${\xac\x8e\x8e\x7f\xdc\xbf\xee\x87\tC6\xae\xdf?j\xfd\xec+7\xad\xd0?3_\xda\xc0]\x07\xf5?\x081\x1f\x83\xe5\xff\xeb\xbfS\xe9j\x96B\x86\xd5?\xab\r\xd9\xadj\xcf\xec?\xe7\xbdE\xaf*9\xf6?\xce$g\xcc\xb5\xb1\xcd\xbf\xc6R\xd0\xb3\xd1,\xf2?=;\x10\xe3\x92\xe3\xf8\xbf\xbc\x81\xd3x~\x12\xf0\xbf&\xfd\xc0\xcbr\x15\xd9?\xd8\x15\x9c\x9adv\xee?\xb5\xd3{#\x1a\x8a\xe6\xbf\xa0\x9e\x1e\x88\xeb\xf4\xb8?\xb3g\x1d\xf4\xa4\x89\xd8?\xeb\xddz\xf0h\xcc\xc7?\xfa8\x8b\xf8(\xca\x00@\xd6\x1fe]\xc4\xe3\xd1?\x0brOf\xbe\xf5\xca?\xe7&\xfa\x9c\xd6S\xe0?\n V&O\xed\xc3?\xd8\x19\x1b\x98\xf2\xeb\xef?\x8a3\xaf\xd5\xd7\x1c\xa1?\x03\xb3v\xfb_\xb3\xf0?\x8c\xbe\xd8\x884\x97\xf0?h~v\x97\xbd\x8d\xc3\xbf\xbbT\xaaZ\x10\x1e\xe3?\x1c"\xadU|\xa6\xe1?\xda\x962\x9a\xc6;\xf7\xbf\xef\xc4+ \xc5e\xc7\xbf[\xcf5F\xfa\x83\xb5\xbf\x129zk\x87k\xc2?E\x96]n\t \xe2?1\x02\x8d\xa7\xb67\xd6?K\xfa-\xed\x99g\xfc?\xccZ!A\xb6\x03\xca\xbf\xb2tV\xc5D\xfc\xdf\xbf\xbc\x00\x1f\x9dp\xcb\xf3?\xeb\xfb\xec\xa7\'c\x01\xc0:Y*\xc3\xb58\xd3?fD\xa6w\x1f\xac\xff\xbf\r\xde\x02\x11Y\xff\xec?\x90w\x80\x91s\x9b\xfe\xbf\x0e\x82\xef\x18=\x92\xe1\xbfd4\xb8\xb3\xb7\xf6\xac\xbf\xe6Td\xb1\xb1\xb8\xda?\xa5\x8fn\xc4\xa2\x80\xe9?%\x05\x86\xc4\x93\xfb\xde?GP\xba7\xde\xab\xfe?E?\xd0Fz\xb0\xb8?~\xb0M\xb1tE\xe1?P\xde\xf7\x0e\x8c>\xe3?\xd5\x96\x8c\x96\xc3\xeb\xd2\xbf\x02\xd2\x07.s\x06\xfc\xbf\xc1\xee.O\xa9\x05\xe6?}x\x8bPm\'\xf7?\x8d\x87\n\x0e\xee\x1c\x8d?q\x19tq\x1abcbuiltins\nslice\nq\x1bK\x00K\x08K\x01\x87q\x1cRq\x1d\x86q\x1eRq\x1f\x85q ]q!(cpandas.core.indexes.base\n_new_Index\nq"cpandas.core.indexes.base\nIndex\nq#}q$(X\x04\x00\x00\x00dataq%h\x0ch\rK\x00\x85q&h\x0f\x87q\'Rq((K\x01K\x08\x85q)h\x13X\x02\x00\x00\x00O8q*\x89\x88\x87q+Rq,(K\x03X\x01\x00\x00\x00|q-NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK?tq.b\x89]q/(X\x02\x00\x00\x00x0q0X\x02\x00\x00\x00x1q1X\x02\x00\x00\x00x2q2X\x02\x00\x00\x00x3q3X\x02\x00\x00\x00x4q4X\x02\x00\x00\x00x5q5X\x02\x00\x00\x00x6q6X\x02\x00\x00\x00x7q7etq8bX\x04\x00\x00\x00nameq9Nu\x86q:Rq;h"cpandas.core.indexes.range\nRangeIndex\nq<}q=(h9NX\x05\x00\x00\x00startq>K\x00X\x04\x00\x00\x00stopq?KdX\x04\x00\x00\x00stepq@K\x01u\x86qARqBe\x86qCRqDX\x04\x00\x00\x00_typqEX\t\x00\x00\x00dataframeqFX\t\x00\x00\x00_metadataqG]qHX\x05\x00\x00\x00attrsqI}qJX\x06\x00\x00\x00_flagsqK}qLX\x17\x00\x00\x00allows_duplicate_labelsqM\x88sub.',
  'y': b'\x80\x03cpandas.core.series\nSeries\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00_mgrq\x03cpandas.core.internals.managers\nSingleBlockManager\nq\x04)\x81q\x05(]q\x06cpandas.core.indexes.base\n_new_Index\nq\x07cpandas.core.indexes.range\nRangeIndex\nq\x08}q\t(X\x04\x00\x00\x00nameq\nNX\x05\x00\x00\x00startq\x0bK\x00X\x04\x00\x00\x00stopq\x0cKdX\x04\x00\x00\x00stepq\rK\x01u\x86q\x0eRq\x0fa]q\x10cnumpy.core.multiarray\n_reconstruct\nq\x11cnumpy\nndarray\nq\x12K\x00\x85q\x13C\x01bq\x14\x87q\x15Rq\x16(K\x01Kd\x85q\x17cnumpy\ndtype\nq\x18X\x02\x00\x00\x00f8q\x19\x89\x88\x87q\x1aRq\x1b(K\x03X\x01\x00\x00\x00<q\x1cNNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00tq\x1db\x89B \x03\x00\x00dE\xfd\xc3\xfb0n\xc0\xd9\x99\x8cvA\xe1,\xc0%.P\x9cV\x80S@a\x1a\xc0\xedk\x8f?@\xbae\xee\x05r\x901\xc0\xd2\xd7c\xd3L\x9b\x19@\x08\x9aBE \xe1P\xc0\xec\xa9\x18N\\C:\xc0o^~b\xc4BS\xc0XOS\x8d\xe7]d\xc0\xber\x94\x0c\xe2\xd54\xc0\xd6`Q\xea\x80\xc0$\xc0Q\xa5\xd7pB\'b@\xbfA{\xb8;\xe6W@\xed\xd6\x11!\xb8\x01i@\xc1\xa0\xcc\xaf\xf4\xe6d@\x9a,9\xce\x08\x19<\xc0\x9e%\xca\xb1\x1f@5@\x96\xad\x80\x16 \x83K@`_\x9dF\xec\x1dX\xc0\xae<\xe8\x06.\xe3X@\x83\xc6\x92\'\x12\xf3V@\xe4j\xdcFf/^\xc0k\xa1\x9af\xea\xc9E@*\x82\x8b\x9c\x08\x9cm\xc0r\xc8\x93V\xdb\xb8/\xc0\x8c\xb4Ll\xf8\xb2U@\xef\xf4\x05\x0c\x1e\x1ef@\x81\xaeMZ\xff\xaeD@\x07i\xc2\xde\x9d\x1bm\xc0\xfc?\xc3\xc1\xdc\x05J@\x12\xc9t\x06\x08\xbba\xc0\xc5R\xcer\xedrW\xc0\x13\xd7\xf9\xba\xa6\x98A@\x06\xe2\x02\x05\xae\xc5E@\xe62\xce(\xb4Vo@k\xbb\xd1`\xb3\xd8I\xc0}\xcdx\x01\xf1\xa4K\xc0\xe5\x84\xd3Z\x9e\x9bi@\x85iU`[_L@\xf9l\xca]\x91UM\xc0\xa9\x0200\xff\xbbA\xc0\xf0\x94>8\xccF\\\xc0\x9a\xb8&\xcb\x18\xa1M@f\x1e\xcb:\xf2\xabT\xc0\x0b\xbe;Jp\xeeh@\xf6\x0f\xbb\xa5\xcc\x18^@\x17\xe6 \xe8\xc7\xeba@\xd4F\xfc\xcf\xfb\x8e\\\xc0v\xbd\x16\xe4\xe2\xe7p@i\xb0`\xbc+\xc92\xc0:-f\x01f\xeeR@Hy\x8b\xbc\x89M\t\xc0/6j\x00\xca\xe5b@\xbd3\xac\xdb\x84yn@\xb4\xd1\xeb\x84\x8e)\x06@\xa4\x96\x82\xbe\xae\xadB@\x07\x8b\xdc\xc1\xd8LX@\xfe\x1e\x8cg\xc6&d\xc0\xf6\n{\x0e\xc2\x1b3@\x9b\xec\xdfIwRj\xc0\xa4\xa7\xa5\x04\xb1\x98D\xc0\x84\xee\x8f\xcdy\xd3\x17@zf5\xee5\x7fY\xc0\xb9\x01#\x02\xe3\xd1W\xc0\xf3\x82\x1cb\x81Ge\xc0>z)}\xfdJ9\xc0\x7f\x9fV\xa9$/9@\xb4\xfbn\x1dz\xd7H\xc0ug\x8e\x07\xa1\xfc@\xc0f\\\x0e\xc8\x8d\xaca\xc0X\xa7L\x10k\xfdP\xc0\x92\xe9\x8ca*\xccF@<\xcf\xe4\x92\xfc\xa9@@v\'\\\x93@\xa7=@\x9e\xbd\x19\xec\xd2H2@\xa26\xc1Q(T\x06@\x19&\xf0\xc3\xc2\x91M@\xfb\x8d\xbd\\A`]@\xc6\xf6\xd6\xbf\xc4\xb13\xc0\xfc/k\xc0\xb8\x90@@^yn\x8aQ\x82\x11\xc0\xd89\xd7y\xd8:W@k;\xb1@N\x91H@5\xce0`\x9aRf\xc0\xd9\xa6:\x0c\xa95_\xc0\xf8$\xe1\x80\xed\xd3f\xc0\xf5\x7f3Hd\x9fT@\x88\xe7\xe5\x02y\xf1_\xc0\xcc\xf3\xa0\xbb \x0bm\xc0&\x9dr\x8b\xb0iN@\x9e\xd8\x1dM\xf4\xe1f@\x18\xcf\xb8\\\xff}P\xc0\xf9\xe0V}u[E@\xe6t=R\xc5ip@\xea\xa3u\xac\xfd\x81e@\x00f\xa3j\x17\x82\xed?\xec\xba\xbds\xc6\\i@\x90\xd0\xb3\x16\x97\x14-\xc0\xf8\xfb\xd5\xe7\x92"^@q\x1etq\x1fba]q h\x07h\x08}q!(h\nNh\x0bK\x00h\x0cKdh\rK\x01u\x86q"Rq#a}q$X\x06\x00\x00\x000.14.1q%}q&(X\x04\x00\x00\x00axesq\'h\x06X\x06\x00\x00\x00blocksq(]q)}q*(X\x06\x00\x00\x00valuesq+h\x16X\x08\x00\x00\x00mgr_locsq,cbuiltins\nslice\nq-K\x00KdK\x01\x87q.Rq/uaustq0bX\x04\x00\x00\x00_typq1X\x06\x00\x00\x00seriesq2X\t\x00\x00\x00_metadataq3]q4h\naX\x05\x00\x00\x00attrsq5}q6X\x06\x00\x00\x00_flagsq7}q8X\x17\x00\x00\x00allows_duplicate_labelsq9\x88sh\nX\x01\x00\x00\x00yq:ub.',
  'model_name': 'LinearRegression',
  'model': b'\x80\x03csklearn.linear_model._base\nLinearRegression\nq\x00)\x81q\x01}q\x02(X\r\x00\x00\x00fit_interceptq\x03\x88X\t\x00\x00\x00normalizeq\x04\x89X\x06\x00\x00\x00copy_Xq\x05\x88X\x06\x00\x00\x00n_jobsq\x06NX\x08\x00\x00\x00positiveq\x07\x89X\x10\x00\x00\x00_sklearn_versionq\x08X\x06\x00\x00\x000.24.2q\tub.'},
 {'index': 'group0-SVR',
  'group': 'group0',
  'X': b'\x80\x03cpandas.core.frame\nDataFrame\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00_mgrq\x03cpandas.core.internals.managers\nBlockManager\nq\x04cfunctools\npartial\nq\x05cpandas.core.internals.blocks\nnew_block\nq\x06\x85q\x07Rq\x08(h\x06)}q\tX\x04\x00\x00\x00ndimq\nK\x02sNtq\x0bbcnumpy.core.multiarray\n_reconstruct\nq\x0ccnumpy\nndarray\nq\rK\x00\x85q\x0eC\x01bq\x0f\x87q\x10Rq\x11(K\x01K\x08Kd\x86q\x12cnumpy\ndtype\nq\x13X\x02\x00\x00\x00f8q\x14\x89\x88\x87q\x15Rq\x16(K\x03X\x01\x00\x00\x00<q\x17NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00tq\x18b\x89B\x00\x19\x00\x00\xfe*Sbr\x1a\xef?e\x18\xdf\x17\xd4\xda\xf2\xbf0tpr\xa1|\xc0?y\xa5\xb0\x89\xd4\x1a\xf6\xbf\x04\xda\n\xa9\xab4\xf9?H\x04<\xfc\xec[\xe7?\xaf4\xd7\xec\x81\x10\xed?\x8e\x13\xa6\x82\xb0\x81\xec\xbf\xde\xdf&m0\xc9\xf6?\x98+9\x04\xdf\xe0\xb8\xbf\xd0\x87\x0e\xa1\x86\x9b\xe6\xbf\xa8-\x9d\xb7\x82\xbf\xc3?\x83\\@\xdd8\xb9\xdb?\x96\xeaD\xaa*3\xe1?\xc2$~?\xaf7\xda?#\x82\xf4L\xb4:\xe1?\x9cD5\x01\x00\xc8\xe5?\xd6\xb3[\xc0\x03V\xd4?\xba\xdbJ\x1b7{\xf0\xbf\xe7\xf41\xe2\x12\xcc\xf2\xbf\xf8\xa9~\xfbK\x85\xdf?!\xe0\xfd\xe1\xe6\xa3\xcc?|=F7K\x0b\xd7\xbf\x1ewv\x84R\xf9\xf3\xbf\xbe\xb5\xcf4\xc8\xe0\xf0\xbf\x1dMkX\x8fI\xa4?D\xf1\x16R\x92\x01\xe2?\xfa\x90\\\xd0l\xfa\xc9?\xcd\xb9\xbc\xd0\xb0\xa0\xe0?\xd6\x96)0\xfe\xb1\x08\xc0\x16z\xb9\xa0./\xdd\xbf\xfah\x97\x1c+\xe7\x02\xc0\xfbX\xd4+\rT\xf3\xbf\x9e\x99\x15\x14\xae\xa3\xed?`\xd5\xea\x9149\xc6?\x0f\x13O\x82\xea\x92\xf5\xbf\xea\xde\x82\x0b\xbc\xc7\xe2\xbf\x9a\xb4\xc9\x9d3\x1a\xbd\xbf\xce\xcc\xca\x0f\xe8s\xdc?\xe0\xcd\xf3@Yn\xd0\xbf\xe0|3\xf8\t\xd3\xf5\xbf\xb1\xd2\x8f\xeap\xd8\xdc\xbf\xf8 \xd3\x86\x80\xb3\xcf\xbfp\r\x01#\x00p\xf4?:\x99x\x92m\xf0\xf1\xbf}a\x81\\L\x7f\xf9?1g\xf4\x1c\x10\xeb\xf6\xbf\xf9\x9a\xd7\xa6|\xa5\xed?)\xa2\xd7HW,\xdf\xbf\x135\xe8\x10\xcb\xe3\x03@"\xd1\x9c,2\x95\xd5?\xbb<\xb0C\xd6\xef\xa3?P\xfc\xafu\xba\xea\xc9?}\x12p\xfb\xe13\xea?j\xc8\x8a\xc0\xd4\xf4\xfc?vy\x93\xf3!\x92\xdc?\x9f\x89mt\xbf(\xe3?\xabH7\xd7\xc0s\x01@`Z;\xbf\x0b\x96\xc2\xbf6\x98\xb3\x98\xc0\x8d\xf3\xbf<\x84\xfc\xd8o\x91\xf5\xbfu\x9c%\x1c\xd1,\xed\xbf\t{\x1d4\xb6N\xdc?FYQ(\x05\xce\x8b\xbfn\x8d-\xfcg.\xd2\xbf\x9e\xde\x1c\xc4\x14:\xe5\xbf\xc9t/\xead\x1e\xde\xbf\xb3\x0b\xeeox\xef\xd3\xbf\xe5\xab\xe8\xdb?=\xec\xbf\xde\x16*\xa9\x83d\xf1\xbf\'2\x10\x7f\xcb9\xe3\xbf7e\x98s\x97\xe8\xec?l\x05\xf6\xe7\xd5\t\xee?,\xdc\xaet\x1d\x05\xd1?\xb1\xf6\xea\x86\x89;\xf4?\x17f\x93\x11\xe2n\xf4?X\x16h`e\x8b\xc8\xbf\xe9,u\xf9v\xda\xaf?\x82\x16\x1e\x02\x7f\xf4\xe4?\x14S\x00fge\xe3\xbf\xe2\xcf^\t\xd9\x91\xeb?\xdeh}+89\xec\xbf\xee\xd0\x83\x04c!\xe4\xbf\x84\x86\x04\x03m\xe6\xbb?\x1e\xf2A\x90\x8bi\xe4\xbf\xeco\xf5\xd1\xde%\xc1\xbf\xb2\rU\xf0\x02\xc2\xf7\xbf\xfa\x93\xa4\xc92\x8e\xed?\x9a\xad\xb7\xe0\x97\xce\xd6?!\x9aX\xee[\xcb\xf8\xbf\x9e\xbe\x8c\xa7&\xc8\xcd\xbf\xbdR\xae\xd6n\xf8\x92?p\x95\xc2\x01\x89\xdb\xdb?oa\xc5 \x83\xc2\xee?\x96u\x94.\x8a^\xe1?\xdb0\xfd`J\xf4\xd8?\xdf\xd8{FD8\xe0?\x84\xff\x92\x7fMQ\xb0\xbf\xc0c\xc1\xa5\xd3\xe3\xa6\xbf\xba\xdd\x1cM\xd2g\xfc?rd\xdb_sL\xde\xbf\x88\xf1\xda\x88\x81\x92\x08@\xd6n\x0ce\xef!\xca\xbf"\x92\xb7\x84\x98D\xf6?\xcc\xd7H\xa9\xf1\xa5\xed?\xc5\xab\x96\xf6\xff\xf0\xbf\xbf\xddk\x9b\xffAX\xf3\xbf\x83{\x8a\xd6>M\xd6?\xb1\xf1\x1d!\x95)\xff\xbf`\xfe\xdbQ*{\xd2\xbf`\x1bT`\\\x93\xec?^C\x1bp\xdc\xba\xb7?\xfcmv\xfa\xb33\xe7?r\x82\xce)\x84*\xf9?\xd7\x9f\xdf:0\xd6\x01@\x17s>\xe1\xebF\xf4?9.^\x9a\x8b\xb5\xa6?\xcc\xcd\x8a\xb9Qa\xbe\xbf\xdab\x03\x98\xbdK\xc1?l\xc6\xfa@6S\xe9?\x1b\xe6\xc5\x9f\x13*\xe6?)\x1aIl\xdf\x88\xe0\xbf\xebg\xe8\x01\x88\x91\xdf\xbf\xc6\xe9\xb3\xe8\x94\xef\xd7\xbf\xda\x1c\x17\x90\xf5\xd3\xa5\xbf\x91U\x9e\x9c\'\x86\xf2\xbfF\xb8\xea\x8c\x0f(\xe3\xbf}\xdc\x14\xfdvk\xf4?\xffJ\xe2c\x19\xc7\xc1?\xe2\x95\x86\x0clZ\xd5\xbf+\xb0\xa7\xc1\xb4\x98\xa3?\x94\xf7\xab\x95J\xa2\xf3\xbf\xc4\xef4\x1e\xb4\xa8\xef\xbf\xb4\x03>\x80\xc9\x04\xf5?\xbcm\x8f\xdc|;\xdd\xbf2\x10\xfc\xe1DF\x00@w\xff\x93\xa4\xea\x08\xa8?&[\x9b\xa8\xd0\xdb\xc3?\\>\xd9)\xbdo\xca?\x87L\x98\xda\xc2U\xfe?I@\xb5\xfdr\x17\xce\xbfB\xf2t\xb9\x19\xb1\x9a?:\xef\x82,=e\xe2\xbf\xfa\xb7n\xc7E\x95\xbc\xbf[oc\x94\xd8\x0b\xf9\xbf\xe4?$\x91z\n\xee?\x17\xbb\rG\xd6\xbe\xd3\xbff\xf0\x03B;\xda\xee\xbf\x90\xba\x8d\x8a\x82\xe5\xd0\xbf\x93aE\xa1.\x83\xe0\xbfT\xea\xd3;<B\xf2\xbf#\xa9Hn\xc3"\xea?U7\xe7\x0f\xdd\xfe\xcf\xbf,<?\x82\xe4\xe2\xdd\xbf\xb8\xda\xd9\xacJ\x1c\xdf?}lI\xb9\x96\xa4\x00\xc0\x96\x10\xbd\xad\x9f\xcd\xd6?2\xa6\x8d\xd0\x8fw\xe3\xbf\x99\xea\xa8\x9b99\xe1\xbf\x08\x19V\x85b\'\xdd\xbf\x14cq$\x0c\xd8\xe0\xbf\x0e\x99\xc77y\x9d\xe6?\xa2\xeb\x13\xb3X\x16\xe2?\xc0m\xaa\xa3\x00\x84\x01\xc0s\xd6y\xf9\x8e\x14\xda\xbf\x8e4Vf^7\xa3\xbf\'\x12\xacpK\xcd\xe0?\xe9\xf5\xc4"\xe0l\xac?\xfa\xa3)\xae\xf9C\xd4\xbf\xccI\x8aH"\x84\xeb\xbf,\xea\xde{@j\xb2?\xb1!L\x03\xdbAp?\xd7{\\0\xd4\x02\x03@\x1a\xa4\xa6Xjt\xc7\xbf\xdb\xdc\x17\x88~\xe8\xdf\xbfJ]\x88\xf9s9\xf8\xbf/2\xe1\xca]\xee\xb8\xbfK2\x8dAb.\x02\xc0l\xab\xbf9\xeb\xde\xcf\xbfvz\x8cH\xebe\xf0\xbf>\xe5\xd6\xcf\xde\x9f\xfb?"#\xc9\xfa\xce\x16\x1f\xbf\xee\xd6B\x87\xea\x11\x00@R\x85>\xb0 \x8c\xf2?b\x81\xe6~\x87\x83\xf6\xbf\xe3~5\xed\x96\xe9\xdf?\x97&~\x8cD\xba\xcb?W,\x04V\x13\x08\xf1?\x9c}\x1ff\x9dv\xcf\xbf9\x03\x86G\x03;\xf0?\xd4Nw\xe1"\x8a\xe3\xbf\xa9\xbe\x02\x8b\xde%\xd7?\xd6\x8cOA\xd0\x95\xd4\xbf\x00R\xe9\xbd\xf3_\xf8\xbfZju\xae\xc5\xea\xf1?\xb9\xf2N\xff\xec\x05\xd1\xbf\x99\xad\x84;\xcd\xee\xe3?\xaeJ\x9d\\\x8d8\xf6\xbf\xa7\x9el\xba\x9d\xb7\xfe?\xf2\xe0@\x88\xfc\x9e\xd8?\xa3jR\x96\xa9\xc4\x01\xc0\xbb\xcc\x12\xf8\xff\xd4\xe5\xbf\xca\xf5R\xcf\xe6\x9c\xe2?\x0b\x7f?\xbe\x0f\xf3\xe7?9?\xd2&\x82\xd5\xf5\xbf\x82\xcdd\xca\xd9t\xca\xbf\x84PVz\xe1N\xec\xbf\x04\xd3\x9bl<R\xcf?\xec\xbd\xff\x11w0\xd6\xbf\xcc\xbc\x95\x16\xc2w\xf1\xbf\xaa+\xa1\x92Ml\xac\xbfo\xcb.\xb7|\x86\xa8?\x00\x81B.\xec\xb0\xe3?8\xdf\xa4\xba\xcfk\xd0?\xa4\xc9\xf7l\x83\x93\xe4?\xef>v\xf1\t`\xe0?\xdc\x80\xb5\xce\xdb\xfc\xe4\xbf\xceG\x1b\xa7K\xcb|?\xf1\xfa\x9cB\xec\x90\xea?\x10\xe0\']\xd2\xf4\xe0\xbf\xcd9\xa2B\xeb\x8d\xc7\xbf\xa0\xac\xeb\xf2\xfd#\xf6?\xe5\xb1\xe1\t\xb2\x1f\xdf\xbfH$\xb6\x01C\xbd\xf6?z\xdf\x969\xfc\x1b\xf5\xbf\xba^\xd4h\xc4\xa2\xe4?\xf3,\x1e\x05-\x0e\xec?f\x98\xe6\xc9S,\xf0?%\x92Eh\xd3\x1a\xb4\xbfHj\x8d\x1a\xcd\xcap\xbf\xdb\x12C6\xd8\x15\xee?p\x86\xc6\xc0\xe2H\xda?\x0bb=^\xcf\xe0\xde?\xd8]\xa5\xa9dP\xf1\xbf\xd7f\xf1\xd9o\xe4\xd3?\x132\xfc\xd1\x90\x14\x03@\xfb\x15\xaa\x0f<\xfa\xd4\xbf\x8b\xf3;\xbeL\xac\xe5\xbf\xc7F\\/\xd7\x92\xfb?;\x05\x06\xd0s.\xc3\xbf\xa0\x8e:+\x99\xfb\xd7?V\x1fJ\xecN\xdb\xa5\xbf\xc5+\xd4\xf4\x924\xe5\xbfBi\x8f\xaa\x12\x15\xdb\xbffQ\xd8\xd1\x7f\xcd\xcc?\x90=J \xf6\n\xd5?\xdeq)+\x9c\xe5\x02@._\xb5\x1b\x15\xc3\xee?\xd4\x944\x92\x18<\xe9\xbf!\x94\xe8\xeer\xe7\xf1?;n!\x1aX8\xc7\xbfQ$\xa8v\x84\xc6\xe7?\xc9\x17\x92\xa7B\x01\xce?5eCM\xee\xad\xf3?R\xdeg\x947\xd7\xe6?@\xc2\r\xbb\xf2J\xe9?\t\xa9r\x0e\xd0\xaa\xd1\xbf4\x01"\xcb\xf5\x84\xcd\xbfm\x1b\xd0\x11\xd1\xfd\xf6\xbf\x10x\x9c~ \xab\xed?e\x9d\t\x84\x8eI\xeb\xbf\xad=\xf0f\x8f\xfe\x8c?\xea\x93\x14}"\xa6\xda\xbf\x98WU\xb7}c\xce\xbf\xcce\xa2w_i\xe1\xbf)\xef7L\xa5\x7f\xf5\xbf\x93=\x15k\x83\xf9\xce\xbfe9\xbd\xb6\xabx\xdc?\xa4\xcbE\xab\xc6\xc0\xbe?\xd2\xcbM\x8c\x1d\x94\xd3?\x9ct\xb0\x16\xe4A\xf1\xbf!d\xd2\x11sZ\xf4\xbf\xe3\x15P\x0eq\xf7\xee\xbf\x1e- \xab\x93\x96\xc3?\xae\xe0\xcf\xbe\xa68\xd7\xbf\xa6\xa9\xa9\xc3J\x0f\xaa\xbf\x17%+ZfJ\xb7?\x00\xc6Z\xf8\x82u\xf5?\x94\xf9#\x0e\x05\xe2\xe6?g\x9a\x0f\xb5\xbf\xf0\xea?h\xd5O\x92\x11\xa8\xf5\xbf\x94u_\xa3k\xfa\xf0?\xeei\xf2\x85\xb9h\xdb?\x13\xe9r\x1f\x8dI\xaa\xbf\xaf\xbc\x15\x81\x895\xea\xbf\x82M\xd6\xb3M\x0f\xf4\xbf\xb2n\xe2\x1c\x96\xf9\xe0\xbf<\xecT\xe8\xf9\xcf\xda\xbf\x04$\xb3a\x94\xbe\xf6\xbf\xa3\x85\xfcH\xe2\xad\xfc\xbf\xb7\xb1:\xd0\x16j\xf1?\xa4\xf3\xa7\x90\x92J\xf4?VqR\x06\x9e\xcc\xee\xbfCW\xc0XN\xb5\xd3?\xfd\xb4\xb4s_\x8f\xf8?\n\x0e\xa0\xf7\xeay\xfe?\x9f\x94JZ\xc8a\xe1\xbf\xc8\x8bC\xea[r\x02@\xfa\xcc\x03%\xef\xe6\xf3\xbf^\xe5\xdc\x874i\xd3\xbfj4\x19;P\x87\x00@i\xd6\xb7+\xbeP\x00@\xd1\x91\xc0\xf9?\x9f\xe8\xbf\x12\x02\x81\xfb\xcf\xf8\xc7?)a\xf1\x9c\xb9&\xd1\xbf\xd4\xdf@\xb2\xee\xb7\x00@=\x9c\xe9/\xf8m\xe2\xbf\x0b0\xea\\a`\xe9\xbf\x1a\x86\x85D,\xeb\xf1\xbf\xb4)\xe6\x08\'\xb8\xd9?\x8a\xb0EN\xcb\x99\xf2\xbfr\xf80\x93\x10\x99\x03@\x08\x83\xd66&\xaf\xdf\xbf$\n!\xdc\xaaz\xd8\xbf\x17\xd6\x04\t\xa3\xb0\x89\xbfPY\x85\xc8c=\xac?r\xff\xec5U\n\xdd?i\x03\xd5t#\xcd\xf3?\xf4kc\x04\xe5\xc4\xe5\xbf\x98\xb1\xbf=\x0b\r\xd8\xbf\xef\x11\xc2\xf7\xe7\xd2\xf3?\xe92SQ\x15`\xe6?6\xe6\x8aY\xe7\xc6\xe5\xbf\x97\xce|\xc2R\xd5\xe2\xbf\xca\x87\xe5\n\xb5\xc2\xb0?1gA\x0e\xc4(\xe5?"8\x02io\xbe\xe6\xbf\xae56\xa3-\xcf\xdf\xbf\x9a\xb5Vr\xa1 \xe0\xbf\xce\x9c\xee\x1aVB\xe9?\xc0Ub\xca\x99\xd6\xc2\xbf\xa8\xe7\xfa96\x03\xe3?h)\xfa\x0cQru\xbf\xe0\x8f\x89\x9d\x11T\xca?\xad\xb5\x99mo\x8b\xfd\xbf\t g0\x85\xb1\xe4\xbf:6\xf5\xe0\xba\x16\xe5\xbfP\x1fk\xb7\xa5\xee\xe4?v#=\xd2\x10\r\xe3\xbf\xd0ExU\x86\xfd\xf7?\xa5G\x7fH\xa3\xd1\xc3?\n\x85\x88o\xe1\xa0\xcf?\xeb\xa8uJO\xf0\x01@\xc2\x1c\xb8\x84\xcf\xd5\xfc\xbfS\x99t\xf51T\xfd?\x9e\xa5\xea\xde\xacP\xc2\xbf\x1f!Oy\xe1\xf0\xdd\xbf\xb7\xf7\xea\x0c\x8b\xba\xe2?9r\x0e\xc2\xa3O\xdb\xbf\x13\x80\xa5\x1ek-\xd3?h\xf9\xe7P!\r\x01\xc0\n&K&#s\xf1?\xa2;\xe3\xc9e\x86\xb4?\x95e3\xdf\x84\xbe\xd5?\x16Q;\xdf\xa5\xa8\xe2?!GO|\x8bh\xfb\xbfg\xc3\x11\xc4\xfaT\xd7?t\xd4\xc2M\x90?\xe2?\xce\xd5\x07\tu\xf3\xf1\xbf\xc6\xb9\r\x9b\xfd\x15\xf7\xbfz\xa0O|7l\xf0\xbf=\x1b\xf1\xef4\xc5\xed\xbf\xc7\x9a6,\xa5\x0c\xe3?\xa6\x05w\x98\xf5\xb9\xdd\xbfOb\xfb\xd0\xc3\xd4\xf9?\xfa\xdc\xdc\xae\x11\x87\xe3?\xa4\xd0v\x8f\x99:\xf3\xbf\xf9nBs\x8f]\xe6\xbf\xd5{\'C\xdb+\xf8?KO\xf4D@\xa7\xd4\xbf\xaa\x9aM\x17\xc2{\xf9?\xed3\xcf\xce1\x1c\xf1\xbf\x97\xd7g\xf3\x00\xfd\xd5\xbf\xb6\xc93\x98R\xad\xf6?\xd8\xdcG\x15\xda\xfb\xea?\x19\xbcM5h\x01\xf5\xbf\x91\x0b\x83\nQ1\xc4\xbf\x0f\xe5\xb3\xc3\x9c\x03\xed\xbfF\xa9y%&l\x9c\xbfK$\x1fZ\xf9\xd7\xe9?\x06\x7f\xba3\x94t\xfa\xbf(\xec\x88\x85\xa7\x88\xfa\xbf4\xd5Q]~F\xd4?C!\xa8\xd9\x0c%\xe1?\xe0\xcb\xcf^\x0c\xc7\xf1?d\x9dJ\x9fYF\xf4\xbfm\xc8\x0f\xb6t\xb9\xf2?\x8fu.\x02C^\xcc\xbfB`\xd8\xf9L\x98\xea?\xf7(3\xefm<\xcc\xbf\x8c\xfa\xe8\x9aC\x1a\xf2?hj\xfc\r:}\xd7?\xa9a\xb6\x98\xda\x0e\xe8?\x82\xb8J\xfe\x11\xd3\xe2?y\xd3q\x7f\xc6\x08\xe8\xbf[\r\xb8\xce\x0f\xd5\x93\xbf\x84U\xf3<y3\xe7\xbf\xbbJ\x8e\xb9\x89\t\xe7?j\xd6\xe8f\x8f\xca\xd1?\x9a\x8f\xf6\xa9\xa9\x06\xd3?\x1d+\xae\x06\xfd\xc7\xd7\xbfeQ\xa8\xf2VB\xe6?<\xb5\xb8\xbf\xe44\xe7?@RZ\xc8x#\xe5?m\'\xb6\xca\xbd\xdf\xf2\xbf\xd9\x1d\x94\xd2\xc4\x98\xf9?\x12\'h\xf0\xab\xc2\xe7\xbf\x08G\x0cMaD\xcd?\x08r\x1b`d8\xed\xbf^ M\x9a\xc0\xc5\xea?,X\xb3Q\x8f\xbe\xb7\xbf\x91\xa3\xa0h\x08\xc1\xc0\xbf\xddk\xd1\xf3i#\xf3\xbfGK\x85]I\xab\xf3\xbfg\x0b\x92\xb8\xef\xfc\xd2?\xb7\x92\x88\x9c%\x01\xe3?{Ty*\x00\xba\xee\xbfs\xeb\x81\xa5\x7f<\xfa?\xc2r\x8a\xd1]N\xee\xbf4\xe2k&\\\xd2\x9d?\xf8\t\xcb\xb5\xfa\x83\xd8\xbf\xbbCn\xa7^\x85\xe0\xbf\xee\x06\xdf6\xca\xc3\xd0\xbf\xba\xb0V\x8d\xad\xb3\xa1?s\xd0\xdbK>\xf7\xd6?\xe9\x8a\x80\xc17\xc8\xc8\xbf\xffM\xf1f\x1b(\xeb?\xbb\x05h\xe1F\xd5\xf7?#\x97\'\x99\x0c\xf5\xe4?\xfa\xea\xc4\xbc\x1c7\xfc\xbfp\xc4\xb3\x05B\x81\xbc?\xea\xd7rj\xb3&\xda?\xcd\xc2Ox\xe6\xb3\xd1\xbfK\xfd\xd3-\xf7\xf0\xe4?\xd1\xf1\xb3\xd8\xd8\xfe\xda\xbf\x9b}i\xd5,\xb7\xfd?*\x84\xa5z\xfc\xa6\xd3\xbf\xa9x\n\x9e\xd1\xe3\xf2?\xdejAd\xf3|\xb6\xbfI\x93nOK\xc7\xe2?\xb0\x04\xe2D\xa0\x80\xb9\xbfd\x0c\xab\xd8\xda\x98\xf6\xbfw\x8a\x87\xf2\x06\xa4\xdb\xbf\xe2\x0f\xfc\xf5\t\xc5\xe4?\x1ezx@9\xbc\xfa\xbf\xc67\xec\xd24 \xea?\xd2\xc5C\xb3c\x01\xea?F\xf4\xbe-\xad\x83\xfb?\xad\x00\x04\xc7\x98t\xb3\xbfz3\x8e\x87\x85\xf9\xde\xbf\n\xee8\xae\xff\x1c\xee\xbf\xe3\x84k\x1fSb\xd2\xbf\x12\xa5\xc2_\xa5\xcf\xd9?\x14F\x92\x19\x96\xe0\xe2?\xd9\x81$\xf3\xbd\xb4\xf4\xbfJ\xfda\xab\xe3{\xda\xbf!GM8\xdf\xa4\xfb?\xb8/9\xe0&\x95\xe2?\xc5\xe9"\xf7\xfa\xb7\x08\xc0N\xff;\xcdc\x0b\xef\xbfS&js\xedX\xcf?\xe1yq\xfaO\x80\xee\xbfg\x89-\t\xf8=\xe1\xbf\x85\x1e;\xcb\xa1\x11\xf7?G0\xf3\r\x03\x93\xfb?\xe68\xac\xb5\xda\xee\xf9?F\x9c\xa2\xb3M"\xe0\xbfb\x8ev_\xebR\xf8\xbf\xf8i\x1fR\x99\xe9\xfb?\x88\xdf\xd3\x19\x14\x14\xa7?\x82W\xe9\x96\xb4(\x03@\x89\xc3\x07\x9b\xad\xd9\xcb\xbfA:\x1e\xb3\xcb\x93\xeb\xbf\xb4\x87\xf8i\xbf\xf9\xb5\xbf\xf6\xe9\xa2\xebP\xa0\xa0?N,3T\x1f-\xfd?a`mL\x03\x14\xf7\xbf\xff\xd8\xf0\xbe\xa2\xed\xe7\xbfX\x8b\xcf?\xb6\xb7\xf6?\xd9\xf3\xd3\xf1\xdfF\xf6?\x18s\xdc\xdf\xe1\xf9\xd2?\xdbSb8\x7f=\xe4\xbf\xff\xa5b\x04\x91<\xeb\xbfl*\xee\xe4\xa2\x15\xd2\xbf%(\n\xf1\x916\xbd?UH\xfc\x95\x85,\xf1?\x05Y\x8dV\xcf\xe2\xf2?\xb5z\x10\xf8\xe8/\xf4?-\xd2\xd8\n\x84\x9d\xe1\xbfd\x05V\xd2c\xe4\xf9?U\x9f\x92/M\x18\xf5?\x15Y\xf2\xb0\xc1\xcc\xfb\xbf\x8fq-\xc9e\xf7\x04@\x8b\t\xb0f\x89Y\xe4?\xecV\x06\xb6\xd1\xbf\xa3?R\xd8\x02\xcf\xd2h\xec?\x02q\x84t\x0c8\xfa?\xaf,\x1b\x9a^\x14\xef\xbf\xd8\r\xa5\xed\x19\x86\xda?4e\xb7\x90\xf5\xaa\xe1?\xf1\xd0\xc0\x10\xb5\xe7\xfc\xbf"\xd9Z\x19\xbc\xc5\xd5?\xf9\xba\x7f\xb7L\xa7\xc8?\xb8\x00w\xe1B\xa4\xfa?W\x8f;\x8c\xd7n\xf9\xbf< _R\x158\xe4\xbf\t\x11\xff\xf8,q\xdb\xbf#\xd3\xb6q\xf3f\xd7\xbf\tF\x99$\xf0\x14\xf8\xbf5V\x18u\xb7<\xd3\xbfY\xe6$\x1b\xdd|\xd6?\x1cT\xb9\xe8\xcc\x82\xe5\xbf\x86c\xaa9^,\xec?\x82\xc7\x16U\x08s\xf7\xbf\xd1i\xcf\x08\xa0\x02\xe6?j\x0c\xcd\x93\x17E\xb7\xbfn\xdbl\x1b\xeb\xd8\xf8\xbf\xeb\x82p\xbf6\xfe\xe6?\xb7\x05+w\x01\xca\xf8?S\x8b\xcc\xea\xa8z\xe0\xbf\r\xe7:\xb8\xb6\xae\xe7?\x18\xc1\x0b\xecy(\xfd\xbfGG\x94:\xba\xb5\xea\xbfBJL\xc9\x84>\xdf?q\x11\xb5\xd8\xce\x12\xe5\xbf\xa3\xae\x0c#x?\n\xc0\xf5\xef\xa7_ys\xdb?)\xe7\xd2\xd7d\x9a\xfb?\xea\x855\xe0\xa9s\xe6?.\xec\xec\xdd\xe53\xcd?&\x86\xb8\xef\xefE\xf6?\x08\x83_(w\x88\xf9?\x15\xdagL\x0ej\xd2\xbf,\xd1O\xee\xdf\x03\xea\xbf\x8d\xe2\xcd`\x10W\xe8?\x8d\x97\xed\x94+\x18\xf2?\x81\x8aN\x1cN\x85\xf1?\xa6f\xa6\xed\x14m\xcd?\xf4\xb8\x80\xa7e{\xf8\xbf<2\xc2>\xac\xb2\xd8\xbfE\xc7U\xae\xce\xf1\xfd?\xbe\xd9\x14\'T\x93\xdd?8\xd4,\x87\x98o\x8a\xbf\x02\xfb\x14\'`;\xe3?\xa6\xfb\x03;\xbei\x88\xbf\xf3\xfe\xbe\xedp\x12\xfd?\xd5\x87\xc4$c(\xde?\xb6\xd8\xabb\x8e\x0f\xa3\xbf\xca\xdc\x9b\xa0\xf9\xd8\xf7?\xb0\xcd>\x17=q\xe7?(\x9aAL:\x14\xc7\xbf\x8c\xae\xdbH\x94\x94\xe1\xbf\xe7\xc7\xc5W\xa1\xa9\xe3\xbf^T\x82\x9arV\xcd\xbf\xab\xbdE\xd9\xaa0\xef?>\xd1\xeeNp\xdf\xe1\xbf\xad\xc7\xeb{\x08\xa8\xe4?\xa7r\xe0\xa8\xa2\x93\xe2\xbf7y\xe7,\x15H\xd9?25|\\\xda\xe2\xf3\xbf)\x9f\x16>\x8e\x04\xf8\xbf`U\xfe\x005\xd4\xef\xbf~\x01CQ\x07\xbe\xd4\xbf\x11\xb5\xd8\xed\x06\x94\xea?j\xe6\xa2r-\xa7\xfe\xbf\x0e\x15~\xcc\x97\x19\xed?\x11\xe45!\x14\xbd\xcc?>706M4\xf4\xbf\x16\x1d\xc6u\xb9\x1f\xe1?<\x17\xcb\x94\xd9\x9d\x03@\x04\x18\xd6\x1f\xec\xff\xaa?C6[\x1fc\xc5\xb2?Z\xef\xcd\xd4\xd5N\xf1\xbfR\xd7\x04J\xda\x0e\xe2?\x80]x\xc1\x01e\xdb?\xff\xf7\xf3\xb4\x11Y\xee\xbf\xd2\tH\xc1\xb8\x8f\xde?\x98\x8e\x05\x8e\x1b\x96\xec\xbf?\x14\xb9\x95\xe8-\xee?\x19\x92C\x97a\xc3\xc6?\x91\xe9.4f\xc3x\xbf\xf0!8\x95\xc9\xdf\xca\xbf\xdf\xe7iQtF\x9f?\x17\xb7\x91\xd6\xe5?\xe4\xbf\x07 2\xce\xc0_\xed?|\x99\x16\x14\xda\xc5\xf2?IoVi\x1d6\x02\xc0\xcfbq\xc0\x94\xcf\xec?.H\xde\x12\x89\x1a\xf1\xbf\x81\x9a\x940\xf9\x07\xf3?0\xfc\x8dzlW\xe0\xbf\x89\x95\x17\x84\x1b\xd7\xa5?\xdaq\xdax<\xac\xec?D\xb7\x13>\xd0\x97\xf1?\xde\x06\xf9\xb4\xb9\x96\xf7?\xf3\xfd\xe6kt<\xe7\xbf\x95\xcbn\xb1\xff\xbd\xe4?JI\xd4\x18\x97\r\x00@\xfa\xbc\xaa\xad/\x97\xfa\xbf-\r%\xc7\x1c\x1c\xd5?\xddq\xbe\xf9\xae\xd2\xc3?\x05E5h\xcd\xe1\xc2?\xc9\xef\x82B\x87\x03\xf4\xbf\xa7\xf3}\xa7\x8a\xda\xf4\xbf\x1b\x96\x1c\xc07\xd1\xf0?)\xa1\xa0u\x87\xf0\xe1?\x8b}\x90\xe1\x10s\xed?\xae-;\xfbu:\xd9\xbfI5\xd91w\xc8\xdd?T\xf0m\n\xadi\xf4?J\x0b\x02_\x81M\xd7?\xd6\xa2F\x9b\x9c\x9b\xc3\xbf\xfdq)I\xa2\x05\xe1?U8\x14\xdc\xee\xf3\xdc\xbfy\x12\x08\x92\xf5\xda\xed?V\x04N#\xbc\x82\xf7?\xe4\x07\xc4r\x88\x1a\xc0\xbf\xe5o!6f\x92\xf2?\xc0\xbc\x1b\xef\x80\xac\xe1\xbfA\xfeR\xd3v\xa3\xb8\xbf\xb2\xd6\x83\xa6\xcas\xe6\xbf\xcc\x0e4f\xe8\x1d\xf4\xbf\xbc@gb\xbf\xa9\xfb\xbf\xf5\x00\xf6a\x91\xd4\xf6?\x88\x90\x91\xb8-\'\x02\xc0\xa5A\x12\xb8\xd9\x0b\xe8\xbf10\x89\xd4\x0bz\x04\xc0\xee5S\xdc\x83Z\xe0?\t=H\x90\xea\x8d\xda\xbf.\x8b\x07\x8d\ri\xf9\xbf\xba\x01\xa5\xd3\xc0\\\xd1?\x13\xa8L\x9b\xc9\xa3\x01@nzG^\x16\xac\xe5\xbf\x9b\\L\x05\xde\xd3\xdd? \xc5\xb2\x08;\xc8\xce\xbf\xc0e:mx\xa7\xf5?\x1ch\xc8k\xa7P\xe9\xbf=\x86\xd5o\xfe\x00\xd2\xbf\x19\x8b\xd3\xd4[\xb9\xbe\xbf\x9c\x19\xea0=\xba\xdd\xbf.1K\x87\x00>\xe7?@\xc6\xa1\xbf]R\xcf?}\xa5\x0f\xeb\x83{\xa0\xbfQ\xc6\xd7\x1d2\x8e\xe3\xbf\xc7+\xe1\x80bu\xcd?\x97H\n\x11\x7f\xda\xd6?\xa4M 8\xb0\r\xe2?\xbb\xcb\xb2WK\x87\xeb\xbf\xf6\x8e\xbe\xd7\x07T\xe6\xbf\xe8\xc6\xe8@\xbf\x8d\xf9\xbf\xb6%\x98O#\xd2\xf3\xbf$6y\xd5P!\xc1?\xf4\xe5k\x17\xefw\xf1\xbfqU\xa7\xa5\xd4\xa7\xd6?J\xba}\x16\xfcw\xd6\xbf\x1a&\xb3\x02\xe8\xa1\xd6\xbfP\xc2\xf0\xc9\x8e\xd3\xea\xbf\xa4Y\xd3v\x9b\xf3\xc9\xbf\xbd!\x94\xc1a\x1f\xef\xbf\xb4L\x82\xad\x80.\xfb?\x91s\xe3\x06\xea\xac\xf0\xbf\xb4\xfd]\xe3\x13&\xc1?U\xa3\x96\xc7\xd9\x02\xe2\xbf\xfd\x04\x03i\x02\xbd\xc9\xbf\xee\xb6\xf3mF\x1c\xd9?\xf0o\x1cn \xd0\xe8?\xb9\n\xc0}\xbc!\xda\xbf\xe0\x06Y\xd1\xcd`\xf6\xbf\x1e{q\xa3\xe0r\xe2?\xc3 W\xe7\x88Q\xf5?\xc5O\xaf\x89\xf9\xe0\xde?P\x89\xf9|\xda7\x01@\xed\xce\xac\x04\xeb\xb7\xdc\xbf\x0e\x1f\x1fSd\x85\xd1?p\xff\xd6D\x91_\xe2\xbfmQu\xaf\x134\xba\xbf\xa9B,`W\\\xe3\xbf\x0f\xb0!\xfc\xf1o\xf1?\xcf\xe7{\xbbak\xd2\xbfTf\xf8\x83\t\xce\xeb?\xdf\x9a"\xc6\xb0o\xe1\xbfT\xb7a\xf0p\x8a\xe9\xbf"\x03\xd5\x1e\xaa\x1d\xf1?\x03w\xccd\x19\xfd\xf1\xbf\xdd\xfcfS\xbb\xbf\xe9?eP\x190\x8d.\xb4?X\x01d\x92\xc9\xba\xf4?Dw\x02\xc89\xea\xf2\xbfB\x81)>\x12\x16\xf1?n\xc9\xadKF\xc1\xe7\xbf\x84\xbb8Y-\x90\xeb?j\xb6\xf3A\xe6\x95\xcf?p\xe5\x9e+KV\xe3?\xee\xc1-\xe5I)\xe9\xbf\x18\x8b\x91\xc9\x89\xcc\xeb\xbfA\xbf\xb6}\xe4\x00\xeb\xbf4\xbb(\xe6\x01\xd0\xe6?\xfe\n\xf5Z\x9c\xf3\xd0?;\xf0A\xe8\x92\xe0\xf4?\xdf;\x95i\xad\x15\xc6\xbf\xcaZ\x0c\n\xc6\xa3\x02\xc0$\x06\xbam\xb0\x85\xec\xbf\x13=)U\xd9o\xe7?\xcd\xd1\xd1w\xf9\xea\xfd\xbf\xf4\xc4\x8b,\xc5=\xe0\xbf\xdf\xec\xb7\xa5\xd3\xd1\xf2\xbf\xe4\xb09P \xf4\xe1?S\xa6\xd9\xcdl\x87\xbe?\xa5\x8cE\x11(\x8f\xfa\xbf.GkY\xcd\xac\xf7\xbfbS\xef\xbb,z\xea\xbf\x1f\x82S\xd9\x900\xc1\xbf\xd8v/\xb4\xb0\xad\xc1\xbf\xe3\x02\xa6\x9b\t\x08\xc5\xbf2~\x8d\xbe=\xe4\xe2?uf\x8f\xfb:\x89\xff?\x1f\xee\x192\x84\x9d\xce\xbf@r\n\x96\x16\xf6\xad?\xb8\x9a\t\xff\xea\x87\xd2?q\r\xee$\xe7\x85\xe3?\xb0\xee\x19j}\x18\xf7?\xf6{\xbdlt\xff\xd1\xbf\x06Y\xd8\xf5\x17\xa7\xf3\xbf>\tl\xec\xc6>\xde\xbf\xd8.\x85v\x7f\xd7\xf3\xbf\xb3\xc4\x1c\x12\xab\xbe\xe9\xbf\xc2M\x8b\xbe\xb0\xd6\xd3?\xca=\xea\x13\xd0F\xe7?\x1e\x89\x8f\xe2P\x17\xb7?j\xc2\n\xa9\x10$\xd6\xbfr\x1b2\xee\xe7\xbf\xf4\xbf\xe5k\r\x9c}u\xdd\xbf\x83\xcdz\xe6\x9d\x88\xd9\xbf\xab\xea\xf78#\xc2\xf1?\xfb\x9b\xcc\xf3*&\xce?\xc3\x08z\x95k\x85\xb3?\xe2F\x14\xb0\x8e\xd6\xe4?\xfe\xa2\xb3\xc4\xea*\xde?\xd9\xfc\xbf\x86\xc0\xbe\xd1?\xec\xa8\xdc\x91Q\xa4\xe2?\x8dWR/n;\xea\xbf${\xac\x8e\x8e\x7f\xdc\xbf\xee\x87\tC6\xae\xdf?j\xfd\xec+7\xad\xd0?3_\xda\xc0]\x07\xf5?\x081\x1f\x83\xe5\xff\xeb\xbfS\xe9j\x96B\x86\xd5?\xab\r\xd9\xadj\xcf\xec?\xe7\xbdE\xaf*9\xf6?\xce$g\xcc\xb5\xb1\xcd\xbf\xc6R\xd0\xb3\xd1,\xf2?=;\x10\xe3\x92\xe3\xf8\xbf\xbc\x81\xd3x~\x12\xf0\xbf&\xfd\xc0\xcbr\x15\xd9?\xd8\x15\x9c\x9adv\xee?\xb5\xd3{#\x1a\x8a\xe6\xbf\xa0\x9e\x1e\x88\xeb\xf4\xb8?\xb3g\x1d\xf4\xa4\x89\xd8?\xeb\xddz\xf0h\xcc\xc7?\xfa8\x8b\xf8(\xca\x00@\xd6\x1fe]\xc4\xe3\xd1?\x0brOf\xbe\xf5\xca?\xe7&\xfa\x9c\xd6S\xe0?\n V&O\xed\xc3?\xd8\x19\x1b\x98\xf2\xeb\xef?\x8a3\xaf\xd5\xd7\x1c\xa1?\x03\xb3v\xfb_\xb3\xf0?\x8c\xbe\xd8\x884\x97\xf0?h~v\x97\xbd\x8d\xc3\xbf\xbbT\xaaZ\x10\x1e\xe3?\x1c"\xadU|\xa6\xe1?\xda\x962\x9a\xc6;\xf7\xbf\xef\xc4+ \xc5e\xc7\xbf[\xcf5F\xfa\x83\xb5\xbf\x129zk\x87k\xc2?E\x96]n\t \xe2?1\x02\x8d\xa7\xb67\xd6?K\xfa-\xed\x99g\xfc?\xccZ!A\xb6\x03\xca\xbf\xb2tV\xc5D\xfc\xdf\xbf\xbc\x00\x1f\x9dp\xcb\xf3?\xeb\xfb\xec\xa7\'c\x01\xc0:Y*\xc3\xb58\xd3?fD\xa6w\x1f\xac\xff\xbf\r\xde\x02\x11Y\xff\xec?\x90w\x80\x91s\x9b\xfe\xbf\x0e\x82\xef\x18=\x92\xe1\xbfd4\xb8\xb3\xb7\xf6\xac\xbf\xe6Td\xb1\xb1\xb8\xda?\xa5\x8fn\xc4\xa2\x80\xe9?%\x05\x86\xc4\x93\xfb\xde?GP\xba7\xde\xab\xfe?E?\xd0Fz\xb0\xb8?~\xb0M\xb1tE\xe1?P\xde\xf7\x0e\x8c>\xe3?\xd5\x96\x8c\x96\xc3\xeb\xd2\xbf\x02\xd2\x07.s\x06\xfc\xbf\xc1\xee.O\xa9\x05\xe6?}x\x8bPm\'\xf7?\x8d\x87\n\x0e\xee\x1c\x8d?q\x19tq\x1abcbuiltins\nslice\nq\x1bK\x00K\x08K\x01\x87q\x1cRq\x1d\x86q\x1eRq\x1f\x85q ]q!(cpandas.core.indexes.base\n_new_Index\nq"cpandas.core.indexes.base\nIndex\nq#}q$(X\x04\x00\x00\x00dataq%h\x0ch\rK\x00\x85q&h\x0f\x87q\'Rq((K\x01K\x08\x85q)h\x13X\x02\x00\x00\x00O8q*\x89\x88\x87q+Rq,(K\x03X\x01\x00\x00\x00|q-NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK?tq.b\x89]q/(X\x02\x00\x00\x00x0q0X\x02\x00\x00\x00x1q1X\x02\x00\x00\x00x2q2X\x02\x00\x00\x00x3q3X\x02\x00\x00\x00x4q4X\x02\x00\x00\x00x5q5X\x02\x00\x00\x00x6q6X\x02\x00\x00\x00x7q7etq8bX\x04\x00\x00\x00nameq9Nu\x86q:Rq;h"cpandas.core.indexes.range\nRangeIndex\nq<}q=(h9NX\x05\x00\x00\x00startq>K\x00X\x04\x00\x00\x00stopq?KdX\x04\x00\x00\x00stepq@K\x01u\x86qARqBe\x86qCRqDX\x04\x00\x00\x00_typqEX\t\x00\x00\x00dataframeqFX\t\x00\x00\x00_metadataqG]qHX\x05\x00\x00\x00attrsqI}qJX\x06\x00\x00\x00_flagsqK}qLX\x17\x00\x00\x00allows_duplicate_labelsqM\x88sub.',
  'y': b'\x80\x03cpandas.core.series\nSeries\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00_mgrq\x03cpandas.core.internals.managers\nSingleBlockManager\nq\x04)\x81q\x05(]q\x06cpandas.core.indexes.base\n_new_Index\nq\x07cpandas.core.indexes.range\nRangeIndex\nq\x08}q\t(X\x04\x00\x00\x00nameq\nNX\x05\x00\x00\x00startq\x0bK\x00X\x04\x00\x00\x00stopq\x0cKdX\x04\x00\x00\x00stepq\rK\x01u\x86q\x0eRq\x0fa]q\x10cnumpy.core.multiarray\n_reconstruct\nq\x11cnumpy\nndarray\nq\x12K\x00\x85q\x13C\x01bq\x14\x87q\x15Rq\x16(K\x01Kd\x85q\x17cnumpy\ndtype\nq\x18X\x02\x00\x00\x00f8q\x19\x89\x88\x87q\x1aRq\x1b(K\x03X\x01\x00\x00\x00<q\x1cNNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00tq\x1db\x89B \x03\x00\x00dE\xfd\xc3\xfb0n\xc0\xd9\x99\x8cvA\xe1,\xc0%.P\x9cV\x80S@a\x1a\xc0\xedk\x8f?@\xbae\xee\x05r\x901\xc0\xd2\xd7c\xd3L\x9b\x19@\x08\x9aBE \xe1P\xc0\xec\xa9\x18N\\C:\xc0o^~b\xc4BS\xc0XOS\x8d\xe7]d\xc0\xber\x94\x0c\xe2\xd54\xc0\xd6`Q\xea\x80\xc0$\xc0Q\xa5\xd7pB\'b@\xbfA{\xb8;\xe6W@\xed\xd6\x11!\xb8\x01i@\xc1\xa0\xcc\xaf\xf4\xe6d@\x9a,9\xce\x08\x19<\xc0\x9e%\xca\xb1\x1f@5@\x96\xad\x80\x16 \x83K@`_\x9dF\xec\x1dX\xc0\xae<\xe8\x06.\xe3X@\x83\xc6\x92\'\x12\xf3V@\xe4j\xdcFf/^\xc0k\xa1\x9af\xea\xc9E@*\x82\x8b\x9c\x08\x9cm\xc0r\xc8\x93V\xdb\xb8/\xc0\x8c\xb4Ll\xf8\xb2U@\xef\xf4\x05\x0c\x1e\x1ef@\x81\xaeMZ\xff\xaeD@\x07i\xc2\xde\x9d\x1bm\xc0\xfc?\xc3\xc1\xdc\x05J@\x12\xc9t\x06\x08\xbba\xc0\xc5R\xcer\xedrW\xc0\x13\xd7\xf9\xba\xa6\x98A@\x06\xe2\x02\x05\xae\xc5E@\xe62\xce(\xb4Vo@k\xbb\xd1`\xb3\xd8I\xc0}\xcdx\x01\xf1\xa4K\xc0\xe5\x84\xd3Z\x9e\x9bi@\x85iU`[_L@\xf9l\xca]\x91UM\xc0\xa9\x0200\xff\xbbA\xc0\xf0\x94>8\xccF\\\xc0\x9a\xb8&\xcb\x18\xa1M@f\x1e\xcb:\xf2\xabT\xc0\x0b\xbe;Jp\xeeh@\xf6\x0f\xbb\xa5\xcc\x18^@\x17\xe6 \xe8\xc7\xeba@\xd4F\xfc\xcf\xfb\x8e\\\xc0v\xbd\x16\xe4\xe2\xe7p@i\xb0`\xbc+\xc92\xc0:-f\x01f\xeeR@Hy\x8b\xbc\x89M\t\xc0/6j\x00\xca\xe5b@\xbd3\xac\xdb\x84yn@\xb4\xd1\xeb\x84\x8e)\x06@\xa4\x96\x82\xbe\xae\xadB@\x07\x8b\xdc\xc1\xd8LX@\xfe\x1e\x8cg\xc6&d\xc0\xf6\n{\x0e\xc2\x1b3@\x9b\xec\xdfIwRj\xc0\xa4\xa7\xa5\x04\xb1\x98D\xc0\x84\xee\x8f\xcdy\xd3\x17@zf5\xee5\x7fY\xc0\xb9\x01#\x02\xe3\xd1W\xc0\xf3\x82\x1cb\x81Ge\xc0>z)}\xfdJ9\xc0\x7f\x9fV\xa9$/9@\xb4\xfbn\x1dz\xd7H\xc0ug\x8e\x07\xa1\xfc@\xc0f\\\x0e\xc8\x8d\xaca\xc0X\xa7L\x10k\xfdP\xc0\x92\xe9\x8ca*\xccF@<\xcf\xe4\x92\xfc\xa9@@v\'\\\x93@\xa7=@\x9e\xbd\x19\xec\xd2H2@\xa26\xc1Q(T\x06@\x19&\xf0\xc3\xc2\x91M@\xfb\x8d\xbd\\A`]@\xc6\xf6\xd6\xbf\xc4\xb13\xc0\xfc/k\xc0\xb8\x90@@^yn\x8aQ\x82\x11\xc0\xd89\xd7y\xd8:W@k;\xb1@N\x91H@5\xce0`\x9aRf\xc0\xd9\xa6:\x0c\xa95_\xc0\xf8$\xe1\x80\xed\xd3f\xc0\xf5\x7f3Hd\x9fT@\x88\xe7\xe5\x02y\xf1_\xc0\xcc\xf3\xa0\xbb \x0bm\xc0&\x9dr\x8b\xb0iN@\x9e\xd8\x1dM\xf4\xe1f@\x18\xcf\xb8\\\xff}P\xc0\xf9\xe0V}u[E@\xe6t=R\xc5ip@\xea\xa3u\xac\xfd\x81e@\x00f\xa3j\x17\x82\xed?\xec\xba\xbds\xc6\\i@\x90\xd0\xb3\x16\x97\x14-\xc0\xf8\xfb\xd5\xe7\x92"^@q\x1etq\x1fba]q h\x07h\x08}q!(h\nNh\x0bK\x00h\x0cKdh\rK\x01u\x86q"Rq#a}q$X\x06\x00\x00\x000.14.1q%}q&(X\x04\x00\x00\x00axesq\'h\x06X\x06\x00\x00\x00blocksq(]q)}q*(X\x06\x00\x00\x00valuesq+h\x16X\x08\x00\x00\x00mgr_locsq,cbuiltins\nslice\nq-K\x00KdK\x01\x87q.Rq/uaustq0bX\x04\x00\x00\x00_typq1X\x06\x00\x00\x00seriesq2X\t\x00\x00\x00_metadataq3]q4h\naX\x05\x00\x00\x00attrsq5}q6X\x06\x00\x00\x00_flagsq7}q8X\x17\x00\x00\x00allows_duplicate_labelsq9\x88sh\nX\x01\x00\x00\x00yq:ub.',
  'model_name': 'SVR',
  'model': b'\x80\x03csklearn.svm._classes\nSVR\nq\x00)\x81q\x01}q\x02(X\x06\x00\x00\x00kernelq\x03X\x03\x00\x00\x00rbfq\x04X\x06\x00\x00\x00degreeq\x05K\x03X\x05\x00\x00\x00gammaq\x06X\x05\x00\x00\x00scaleq\x07X\x05\x00\x00\x00coef0q\x08G\x00\x00\x00\x00\x00\x00\x00\x00X\x03\x00\x00\x00tolq\tG?PbM\xd2\xf1\xa9\xfcX\x01\x00\x00\x00Cq\nG?\xf0\x00\x00\x00\x00\x00\x00X\x02\x00\x00\x00nuq\x0bG\x00\x00\x00\x00\x00\x00\x00\x00X\x07\x00\x00\x00epsilonq\x0cG?\xb9\x99\x99\x99\x99\x99\x9aX\t\x00\x00\x00shrinkingq\r\x88X\x0b\x00\x00\x00probabilityq\x0e\x89X\n\x00\x00\x00cache_sizeq\x0fK\xc8X\x0c\x00\x00\x00class_weightq\x10NX\x07\x00\x00\x00verboseq\x11\x89X\x08\x00\x00\x00max_iterq\x12J\xff\xff\xff\xffX\x0c\x00\x00\x00random_stateq\x13NX\x10\x00\x00\x00_sklearn_versionq\x14X\x06\x00\x00\x000.24.2q\x15ub.'}]

Using Fugue transform()

Now that we know the functionw orks, we can then use the Fugue transform() function to generate the training_manifest. This interprets the List[Dict[str,Any]] output type of the create_training_manifest() function and brings it out to a pandas DataFrame (and Spark or Dask later).

from fugue import transform

training_manifest = transform(df, 
                              create_training_manifest, 
                              schema="index:str, group:str,X:binary,y:binary,model_name:str,model:binary", 
                              params=dict(models=[LinearRegression(), SVR()]))
training_manifest.head()
index group X y model_name model
0 group0-LinearRegression group0 b'\x80\x03cpandas.core.frame\nDataFrame\nq\x00... b'\x80\x03cpandas.core.series\nSeries\nq\x00)\... LinearRegression b'\x80\x03csklearn.linear_model._base\nLinearR...
1 group0-SVR group0 b'\x80\x03cpandas.core.frame\nDataFrame\nq\x00... b'\x80\x03cpandas.core.series\nSeries\nq\x00)\... SVR b'\x80\x03csklearn.svm._classes\nSVR\nq\x00)\x...

One training run

Each row in our training_manifest represents a model training run. All we need to do is pull the metadata, unpickle it, and then run the .fit() and .predict() method of the model. We then store the mean_absolute_error of the training run so that we can evaluate these later. This is done in the training_run() function below.

Because Fugue lets us be flexible about type annotations, we can use the List[Dict[str,Any]] structure for both input and output to make our logic easier to write.

def training_run(df: List[Dict[str,Any]]) -> List[Dict[str,Any]]:
    training_sample = df[0]
    index = training_sample["index"]
    group = training_sample["group"]
    X = pickle.loads(training_sample["X"])
    y = pickle.loads(training_sample["y"])
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
    model = pickle.loads(training_sample["model"])
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    mae = mean_absolute_error(y_test, y_pred)
    return [dict(index=index,
                 group=group,
                 model_name=training_sample["model_name"],
                 error=float(mae),
                 model=pickle.dumps(model))]

We can then test it by passing List[Dict[str,Any]] from the first row of our training_manifest.

training_run([training_manifest.iloc[0].to_dict()])
[{'index': 'group0-LinearRegression',
  'group': 'group0',
  'model_name': 'LinearRegression',
  'error': 8.757634740955517,
  'model': b'\x80\x03csklearn.linear_model._base\nLinearRegression\nq\x00)\x81q\x01}q\x02(X\r\x00\x00\x00fit_interceptq\x03\x88X\t\x00\x00\x00normalizeq\x04\x89X\x06\x00\x00\x00copy_Xq\x05\x88X\x06\x00\x00\x00n_jobsq\x06NX\x08\x00\x00\x00positiveq\x07\x89X\x0e\x00\x00\x00n_features_in_q\x08K\x08X\x05\x00\x00\x00coef_q\tcnumpy.core.multiarray\n_reconstruct\nq\ncnumpy\nndarray\nq\x0bK\x00\x85q\x0cC\x01bq\r\x87q\x0eRq\x0f(K\x01K\x08\x85q\x10cnumpy\ndtype\nq\x11X\x02\x00\x00\x00f8q\x12\x89\x88\x87q\x13Rq\x14(K\x03X\x01\x00\x00\x00<q\x15NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00tq\x16b\x89C@\\=<\x9d\x19kQ@\x05\xa4!\x86\xfa\x82E@qW/nc\x9cX@p\xc7\xc1I\x83O\xfe\xbfhC\x16\x0c)R\xf0\xbfu\xf4\x99\x90o\n\'@H\x91\x98\xd2\xaa\x8f\t@\xf3\x9a\xce)\xd1\x020@q\x17tq\x18bX\t\x00\x00\x00_residuesq\x19cnumpy.core.multiarray\nscalar\nq\x1ah\x14C\x08\x1a4\x0e\x9bL\x0c\xc1@q\x1b\x86q\x1cRq\x1dX\x05\x00\x00\x00rank_q\x1eK\x08X\t\x00\x00\x00singular_q\x1fh\nh\x0bK\x00\x85q h\r\x87q!Rq"(K\x01K\x08\x85q#h\x14\x89C@Y\x0b\x16$\xd7k%@\xf4\xb3\r\xc6\xc2\xf0$@\x95\x11\x0b\xcd<\x0b"@1\xa7\xc9\x10\xa6\x9b!@oQ\xde\xaf\x05\xc0 @|\xe7EE #\x1e@\x80\xdfm\x8ch\x19\x1c@\xb4\xb4\xfe\x92r\x0b\x19@q$tq%bX\n\x00\x00\x00intercept_q&h\x1ah\x14C\x08\xc0\x95l\xac\xb4\xc9\xc0?q\'\x86q(Rq)X\x10\x00\x00\x00_sklearn_versionq*X\x06\x00\x00\x000.24.2q+ub.'}]

We can use the Fugue transform() again to run the training runs. Just note that we need to pass in partition on the index, which is unique per row. This means that each row will be passed in to the training_run() function. Fugue then takes care of aggregating the results into a DataFrame.

training_results = transform(training_manifest, 
                             training_run, 
                             schema="index:str,group:str,model_name:str,error:double,model:binary",
                             partition={"by": "index"})
                             
training_results.head()
index group model_name error model
0 group0-LinearRegression group0 LinearRegression 11.190594 b'\x80\x03csklearn.linear_model._base\nLinearR...
1 group0-SVR group0 SVR 76.397862 b'\x80\x03csklearn.svm._classes\nSVR\nq\x00)\x...

Multiple Models for Each Group#

Everything above is now scale agnostic and we can bring the logic to Spark. We previously ran these on Fugue’s default NativeExecutionEngine, which is sequential. In practice, doing a grid search can take multiple hours. Parallelizing the training runs over Spark or Dask will allow us to iterate faster and fully utilize compute.

We make a new larger DataFrame that contains 10 distinct groups. We want to train the models for each of these groups separately.

df = make_data(groups=10)

All of our logic remains the same. We simple use the SparkExecutionEngine to scale and speed up our model training. The same thing can be done with the DaskExecutionEngine.

from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()
training_manifest = transform(df, 
                             create_training_manifest, 
                             schema="index:str,group:str,X:binary,y:binary,model_name:str,model:binary", 
                             params=dict(models=[LinearRegression(), SVR()]),
                             partition={"by": "group"},
                             engine=spark)

results = transform(training_manifest, 
                    training_run, 
                    schema="index:str,group:str,model_name:str,error:float,model:binary",
                    partition={"by": "index"},
                    engine=spark)

results.show()
+--------------------+------+----------------+----------+--------------------+
|               index| group|      model_name|     error|               model|
+--------------------+------+----------------+----------+--------------------+
|group3-LinearRegr...|group3|LinearRegression|  9.379544|[80 03 63 73 6B 6...|
|          group2-SVR|group2|             SVR|  75.86907|[80 03 63 73 6B 6...|
|group9-LinearRegr...|group9|LinearRegression|  9.286413|[80 03 63 73 6B 6...|
|group4-LinearRegr...|group4|LinearRegression| 6.1316595|[80 03 63 73 6B 6...|
|group6-LinearRegr...|group6|LinearRegression|  9.684757|[80 03 63 73 6B 6...|
|group1-LinearRegr...|group1|LinearRegression| 5.3616314|[80 03 63 73 6B 6...|
|          group9-SVR|group9|             SVR|114.082726|[80 03 63 73 6B 6...|
|          group1-SVR|group1|             SVR| 141.20859|[80 03 63 73 6B 6...|
|          group6-SVR|group6|             SVR|  91.27704|[80 03 63 73 6B 6...|
|          group5-SVR|group5|             SVR|  85.69009|[80 03 63 73 6B 6...|
|group2-LinearRegr...|group2|LinearRegression|   6.46798|[80 03 63 73 6B 6...|
|group5-LinearRegr...|group5|LinearRegression|  7.961879|[80 03 63 73 6B 6...|
|          group8-SVR|group8|             SVR|  92.93862|[80 03 63 73 6B 6...|
|group0-LinearRegr...|group0|LinearRegression|   6.80798|[80 03 63 73 6B 6...|
|group8-LinearRegr...|group8|LinearRegression| 7.6318617|[80 03 63 73 6B 6...|
|          group7-SVR|group7|             SVR| 140.42226|[80 03 63 73 6B 6...|
|          group0-SVR|group0|             SVR| 81.492325|[80 03 63 73 6B 6...|
|          group4-SVR|group4|             SVR|  87.68793|[80 03 63 73 6B 6...|
|          group3-SVR|group3|             SVR| 118.69519|[80 03 63 73 6B 6...|
|group7-LinearRegr...|group7|LinearRegression| 7.0831575|[80 03 63 73 6B 6...|
+--------------------+------+----------------+----------+--------------------+

Extending this Setup and Fugue Tune#

There are two hyperparameter tuning approaches that can be used with this setup. First is Grid Search, where we try different combinations of hyperparameters. This can easily be inserted into the create_training_manifest() function to create more runs. The second is Bayesian optimization (with packages like Optuna) where a starting point is initialized and then the hyperparameters are optimized through successive runs. This type of logic can easily go into the training_run() function we defined above.

Fugue actually provides a much simpler interface for this type of hyperparameter tuning with the Fugue tune library that is built on top of the Fugue core. This library can be used for more serious hyperparameter tuning.