import logging
import numpy
from sherpa.utils import SherpaFloat, NoNewAttributesAfterInit
from sherpa.utils.err import ParameterErr
from sherpa.utils import formatting

warning = logging.getLogger(__name__).warning

__all__ = ('Parameter', 'CompositeParameter', 'ConstantParameter',
           'UnaryOpParameter', 'BinaryOpParameter')

# Default minimum and maximum magnitude for parameters
# tinyval = 1.0e-120
# hugeval = 1.0e+120
# tinyval = 1.0e-38
# hugeval = 1.0e+38
#
# Use FLT_TINY and FLT_MAX
tinyval = numpy.float(numpy.finfo(numpy.float32).tiny)
hugeval = numpy.float(numpy.finfo(numpy.float32).max)

def _make_set_limit(name):
    def _set_limit(self, val):
        val = SherpaFloat(val)
        # Ensure that we don't try to set any value that is outside
        # the hard parameter limits.
        if val < self._hard_min:
            raise ParameterErr('edge', self.fullname,
                               'hard minimum', self._hard_min)
        if val > self._hard_max:
            raise ParameterErr('edge', self.fullname,
                               'hard maximum', self._hard_max)

        # Ensure that we don't try to set a parameter range, such that
        # the minimum will be greater than the current parameter value,
        # or that the maximum will be less than the current parameter value.

        # But we only want to do this check *after* parameter has been
        # created and fully initialized; we are doing this check some time
        # *later*, when the user is trying to reset a parameter range
        # such that the new range will leave the current value
        # *outside* the new range.  We want to warn against and disallow that.

        # Due to complaints about having to rewrite existing user scripts,
        # downgrade the ParameterErr issued here to mere warnings.  Also,
        # set the value to the appropriate soft limit.
        if hasattr(self, "_NoNewAttributesAfterInit__initialized") and \
           self._NoNewAttributesAfterInit__initialized:
            if name == "_min" and (val > self.val):
                self.val = val
                warning(('parameter %s less than new minimum; %s reset to %g') % (self.fullname, self.fullname, self.val))
            if name == "_max" and (val < self.val):
                self.val = val
                warning(('parameter %s greater than new maximum; %s reset to %g') % (self.fullname, self.fullname, self.val))

        setattr(self, name, val)

    return _set_limit

def _make_unop(op, opstr):
    def func(self):
        return UnaryOpParameter(self, op, opstr)
    return func

def _make_binop(op, opstr):
    def func(self, rhs):
        return BinaryOpParameter(self, rhs, op, opstr)

    def rfunc(self, lhs):
        return BinaryOpParameter(lhs, self, op, opstr)

    return (func, rfunc)

class Parameter(NoNewAttributesAfterInit):
    """Represent a model parameter.

    Parameters
    ----------
    modelname : str
        The name of the model component containing the parameter.
    name : str
        The name of the parameter. It should be considered to be
        matched in a case-insensitive manner.
    val : number
        The default value for the parameter.
    min, max, hard_min, hard_max: number, optional
        The soft and hard limits for the parameter value.
    units : str, optional
        The units for the parameter value.
    frozen : bool, optional
        Does the parameter default to being frozen?
    alwaysfrozen : bool, optional
        If set then the parameter can never be thawed.
    hidden : bool, optional
        Should the parameter be included when displaying the model
        contents?
    aliases : None or list of str
        If not None then alternative names for the parameter (these
        are expected to be matched in a case-insensitive manner).

    """

    #
    # Read-only properties
    #

    def _get_alwaysfrozen(self):
        return self._alwaysfrozen
    alwaysfrozen = property(_get_alwaysfrozen)

    def _get_hard_min(self):
        return self._hard_min
    hard_min = property(_get_hard_min)

    def _get_hard_max(self):
        return self._hard_max
    hard_max = property(_get_hard_max)

    #
    # 'val' property
    #
    # Note that _get_val has to check the parameter value when it
    # is a link, to ensure that it isn't outside the parameter's
    # min/max range. See issue #742.
    #
    def _get_val(self):
        if hasattr(self, 'eval'):
            return self.eval()
        if self.link is None:
            return self._val

        val = self.link.val
        if val < self.min:
            raise ParameterErr('edge', self.fullname, 'minimum', self.min)
        if val > self.max:
            raise ParameterErr('edge', self.fullname, 'maximum', self.max)

        return val

    def _set_val(self, val):
        if isinstance(val, Parameter):
            self.link = val
        else:
            # Reset link
            self.link = None

            # Validate new value
            val = SherpaFloat(val)
            if val < self.min:
                raise ParameterErr('edge', self.fullname, 'minimum', self.min)
            if val > self.max:
                raise ParameterErr('edge', self.fullname, 'maximum', self.max)

            self._val = val
            self._default_val = val

    val = property(_get_val, _set_val)

    #
    # '_default_val' property
    #

    def _get_default_val(self):
        if hasattr(self, 'eval'):
            return self.eval()
        if self.link is not None:
            return self.link.default_val
        return self._default_val

    def _set_default_val(self, default_val):
        if isinstance(default_val, Parameter):
            self.link = default_val
        else:
            # Reset link
            self.link = None

            # Validate new value
            default_val = SherpaFloat(default_val)
            if default_val < self.min:
                raise ParameterErr('edge', self.fullname, 'minimum', self.min)
            if default_val > self.max:
                raise ParameterErr('edge', self.fullname, 'maximum', self.max)

            self._default_val = default_val

    default_val = property(_get_default_val, _set_default_val)

    #
    # 'min' and 'max' properties
    #

    def _get_min(self):
        return self._min
    min = property(_get_min, _make_set_limit('_min'))

    def _get_max(self):
        return self._max
    max = property(_get_max, _make_set_limit('_max'))

    #
    # 'default_min' and 'default_max' properties
    #

    def _get_default_min(self):
        return self._default_min
    default_min = property(_get_default_min, _make_set_limit('_default_min'))

    def _get_default_max(self):
        return self._default_max
    default_max = property(_get_default_max, _make_set_limit('_default_max'))

    #
    # 'frozen' property
    #

    def _get_frozen(self):
        if self.link is not None:
            return True
        return self._frozen

    def _set_frozen(self, val):
        val = bool(val)
        if self._alwaysfrozen and (not val):
            raise ParameterErr('alwaysfrozen', self.fullname)
        self._frozen = val
    frozen = property(_get_frozen, _set_frozen)

    #
    # 'link' property'
    #

    def _get_link(self):
        return self._link

    def _set_link(self, link):
        if link is not None:
            if self._alwaysfrozen:
                raise ParameterErr('frozennolink', self.fullname)
            if not isinstance(link, Parameter):
                raise ParameterErr('notlink')

            # Short cycles produce error
            # e.g. par = 2*par+3
            if self in link:
                raise ParameterErr('linkcycle')

            # Correctly test for link cycles in long trees.
            cycle = False
            ll = link
            while isinstance(ll, Parameter):
                if ll == self or self in ll:
                    cycle = True
                ll = ll.link

            # Long cycles are overwritten BUG #12287
            if cycle and isinstance(link, Parameter):
                link.link = None

        self._link = link
    link = property(_get_link, _set_link)

    #
    # Methods
    #

    def __init__(self, modelname, name, val, min=-hugeval, max=hugeval,
                 hard_min=-hugeval, hard_max=hugeval, units='',
                 frozen=False, alwaysfrozen=False, hidden=False, aliases=None):
        self.modelname = modelname
        self.name = name
        self.fullname = '%s.%s' % (modelname, name)

        self._hard_min = SherpaFloat(hard_min)
        self._hard_max = SherpaFloat(hard_max)
        self.units = units

        self._alwaysfrozen = bool(alwaysfrozen)
        if alwaysfrozen:
            self._frozen = True
        else:
            self._frozen = frozen

        self.hidden = hidden

        # Set validated attributes.  Access them via their properties so that
        # validation takes place.
        self.min = min
        self.max = max
        self.val = val
        self.default_min = min
        self.default_max = max
        self.default_val = val
        self.link = None
        self._guessed = False

        self.aliases = [a.lower() for a in aliases] if aliases is not None else []

        NoNewAttributesAfterInit.__init__(self)

    def __iter__(self):
        return iter([self])

    def __repr__(self):
        r = "<%s '%s'" % (type(self).__name__, self.name)
        if self.modelname:
            r += " of model '%s'" % self.modelname
        r += '>'
        return r

    def __str__(self):
        if self.link is not None:
            linkstr = self.link.fullname
        else:
            linkstr = str(None)

        return (('val         = %s\n' +
                 'min         = %s\n' +
                 'max         = %s\n' +
                 'units       = %s\n' +
                 'frozen      = %s\n' +
                 'link        = %s\n'
                 'default_val = %s\n' +
                 'default_min = %s\n' +
                 'default_max = %s') %
                (str(self.val), str(self.min), str(self.max), self.units,
                 self.frozen, linkstr, str(self.default_val),
                 str(self.default_min), str(self.default_max)))

    # Support 'rich display' representations
    #
    def _val_to_html(self, v):
        """Convert a value to a string for use by the HTML output.

        The conversion to a string uses the Python defaults for most
        cases. The units field is currently used to determine whether
        to convert angles to factors of pi (this probably should be
        done by a subclass or mixture).
        """

        # The use of equality rather than some form of tolerance
        # should be okay here.
        #
        if v == hugeval:
            return 'MAX'
        elif v == -hugeval:
            return '-MAX'
        elif v == tinyval:
            return 'TINY'
        elif v == -tinyval:
            return '-TINY'

        if self.units in ['radian', 'radians']:
            tau = 2 * numpy.pi

            if v == tau:
                return '2π'
            elif v == -tau:
                return '-2π'
            elif v == numpy.pi:
                return 'π'
            elif v == -numpy.pi:
                return '-π'

        return str(v)

    def _units_to_html(self):
        """Convert the unit to HTML.

        This is provided for future expansion/experimentation,
        and is not guaranteed to remain.
        """

        return self.units

    def _repr_html_(self):
        """Return a HTML (string) representation of the parameter
        """
        return html_parameter(self)

    # Unary operations
    __neg__ = _make_unop(numpy.negative, '-')
    __abs__ = _make_unop(numpy.absolute, 'abs')

    # Binary operations
    __add__, __radd__ = _make_binop(numpy.add, '+')
    __sub__, __rsub__ = _make_binop(numpy.subtract, '-')
    __mul__, __rmul__ = _make_binop(numpy.multiply, '*')
    __div__, __rdiv__ = _make_binop(numpy.divide, '/')
    __floordiv__, __rfloordiv__ = _make_binop(numpy.floor_divide, '//')
    __truediv__, __rtruediv__ = _make_binop(numpy.true_divide, '/')
    __mod__, __rmod__ = _make_binop(numpy.remainder, '%')
    __pow__, __rpow__ = _make_binop(numpy.power, '**')

    def freeze(self):
        """Set the `frozen` attribute for the parameter.

        See Also
        --------
        thaw
        """
        self.frozen = True

    def thaw(self):
        """Unset the `frozen` attribute for the parameter.

        See Also
        --------
        frozen
        """
        self.frozen = False

    def unlink(self):
        self.link = None

    def reset(self):
        # circumvent the attr checks for simplicity, as the defaults have
        # already passed (defaults either set by user or through self.set).
        if self._guessed:
            self._min = self.default_min
            self._max = self.default_max
            self._guessed = False
        self._val = self.default_val

    def set(self, val=None, min=None, max=None, frozen=None,
            default_val=None, default_min=None, default_max=None):
        """Change a parameter setting."""

        if max is not None and max > self.max:
            self.max = max
        if default_max is not None and default_max > self.default_max:
            self.default_max = default_max

        if min is not None and min < self.min:
            self.min = min
        if default_min is not None and default_min < self.default_min:
            self.default_min = default_min

        if val is not None:
            self.val = val
        if default_val is not None:
            self.default_val = default_val

        if min is not None:
            self.min = min
        if max is not None:
            self.max = max

        if default_min is not None:
            self.default_min = default_min
        if default_max is not None:
            self.default_max = default_max

        if frozen is not None:
            self.frozen = frozen

class CompositeParameter(Parameter):

    def __init__(self, name, parts):
        self.parts = tuple(parts)
        Parameter.__init__(self, '', name, 0.0)
        self.fullname = name

    def __iter__(self):
        return iter(self._get_parts())

    def _get_parts(self):
        parts = []

        for p in self.parts:
            # A CompositeParameter should not hold a reference to itself
            assert (p is not self), (("'%s' object holds a reference to " +
                                      "itself") % type(self).__name__)

            parts.append(p)
            if isinstance(p, CompositeParameter):
                parts.extend(p._get_parts())

        # FIXME: do we want to remove duplicate components from parts?

        return parts

    def eval(self):
        raise NotImplementedError

class ConstantParameter(CompositeParameter):

    def __init__(self, value):
        self.value = SherpaFloat(value)
        CompositeParameter.__init__(self, str(value), ())

    def eval(self):
        return self.value

class UnaryOpParameter(CompositeParameter):

    def __init__(self, arg, op, opstr):
        self.arg = arg
        self.op = op
        CompositeParameter.__init__(self,
                                    '%s(%s)' % (opstr, self.arg.fullname),
                                    (self.arg,))

    def eval(self):
        return self.op(self.arg.val)

class BinaryOpParameter(CompositeParameter):

    @staticmethod
    def wrapobj(obj):
        if isinstance(obj, Parameter):
            return obj
        return ConstantParameter(obj)

    def __init__(self, lhs, rhs, op, opstr):
        self.lhs = self.wrapobj(lhs)
        self.rhs = self.wrapobj(rhs)
        self.op = op
        CompositeParameter.__init__(self, '(%s %s %s)' %
                                    (self.lhs.fullname, opstr,
                                     self.rhs.fullname), (self.lhs, self.rhs))

    def eval(self):
        return self.op(self.lhs.val, self.rhs.val)

# Notebook representation
#
def html_parameter(par):
    """Construct the HTML to display the parameter."""

    # Note that as this is a specialized table we do not use
    # formatting.html_table but create everything directly.
    #
    def addtd(val):
        "Use the parameter to convert to HTML"
        return '{}	'.format(par._val_to_html(val))

    out = '
'
    out += '

'
    cols = ['Component', 'Parameter', 'Thawed', 'Value',
            'Min', 'Max', 'Units']
    for col in cols:
        out += '{}	'.format(col)

    out += '

'

    out += '{}	'.format(par.modelname)
    out += '{}	'.format(par.name)

    linked = par.link is not None
    if linked:
        out += "linked	"
    else:
        out += '<input disabled type="checkbox"'
        if not par.frozen:
            out += ' checked'
        out += '></input>	'

    out += addtd(par.val)
    if linked:
        # 8592 is single left arrow
        # 8656 is double left arrow
        #
        val = formatting.clean_bracket(par.link.fullname)
        out += '⇐ {}	'.format(val)

    else:
        out += addtd(par.min)
        out += addtd(par.max)

    out += '{}	'.format(par._units_to_html())
    out += '
'

    out += '

'

    ls = ['Parameter' + out + '']
    return formatting.html_from_sections(par, ls)


from __future__ import annotations
from alpaca.clr import AST

from alpaca.utils import Visitor

import eisen.adapters as adapters
from eisen.state.state_postinstancevisitor import State_PostInstanceVisitor
from eisen.state.state_postspreadvisitor import State_PostSpreadVisitor
from eisen.state.memcheckstate import MemcheckState

from eisen.__memory.spreads import Spread, SpreadVisitor
from eisen.__memory.deps import FunctionDepsDatabase, Deps

State = MemcheckState

class MemCheck(Visitor):
    def __init__(self, debug: bool = False):
        super().__init__(debug=debug)
        self.get_deps = None

    def run(self, state: State_PostInstanceVisitor) -> State_PostSpreadVisitor:
        self.get_deps = GetDeps(state)
        internal_state = MemcheckState.create_from_basestate(state)

        self.get_deps.of_function(internal_state.but_with(ast=MemCheck.get_main_function(state.get_ast())))
        # self.apply(internal_state)
        return State_PostSpreadVisitor.create_from_basestate(state, self.get_deps.cache)

    def apply(self, state: State):
        self._route(state.get_ast(), state)

    @Visitor.for_ast_types("start")
    def _start(fn, state: State):
        state.apply_fn_to_all_children(fn)

    @Visitor.for_ast_types("mod")
    def _mod(fn, state: State):
        adapters.Mod(state).enter_module_and_apply(fn)

    @Visitor.for_ast_types("def", "create", "is_fn")
    def _def(fn, state: State):
        fn.get_deps.of_function(state)

    @Visitor.for_ast_types("struct")
    def _create(fn, state: State):
        node = adapters.Struct(state)
        if node.has_create_ast():
            fn.apply(state.but_with(ast=node.get_create_ast()))

    @Visitor.for_ast_types("variant")
    def _variant(fn, state: State):
        node = adapters.Variant(state)
        fn.apply(state.but_with(ast=node.get_is_ast()))

    @Visitor.for_ast_types("interface")
    def _nothing(fn, state: State):
        return

    @classmethod
    def get_main_function(cls, full_ast: AST) -> AST:
        for child in full_ast:
            if child.type == "def" and child.first().value == "main":
                return child

class GetDeps():
    """Representation of the function GET_DEPS: F -> F_Deps with local caching and DP to prevent
    unnecessary lookups.
    """
    def __init__(self, state: State):
        self.cache = FunctionDepsDatabase()
        self.spread_visitor = SpreadVisitor(self)
        self._add_builtin_function_deps(state)

    def _add_builtin_function_deps(self, state: State):
        for builtin_func_instance in state.get_all_builtins():
            self.cache.add_deps_for(builtin_func_instance, F_deps=Deps(
                R = [[0]],
                A = [[0], []]))

    def _try_cache_lookup(self, state: State) -> Deps | None:
        node = adapters.Def(state)
        if not state.get_inherited_fns():
            return self.cache.lookup_deps_of(node.get_function_instance())

    def _add_to_cache(self, state: State, F_deps: Deps):
        node = adapters.Def(state)
        if not state.get_inherited_fns():
            self.cache.add_deps_for(node.get_function_instance(), F_deps)

    def _add_new_spreads_for_inputs(self, state: State):
        """Add new spreads for argument/return values to the function. Argument spreads default
        to only be the argument number, as their lifetime is only dictated by theirselves. Return
        spreads default to the empty set, as there is no information on which arguments dictate
        their lifetimes yet.
        """
        node = adapters.Def(state)
        arg_node = adapters.ArgsRets(state.but_with(ast=node.get_args_ast()))
        for i, name in enumerate(arg_node.get_names()):
            SpreadVisitor.add_spread(state, name, Spread(values={i}, depth=0))

        ret_node = adapters.ArgsRets(state.but_with(ast=node.get_rets_ast()))
        for name in ret_node.get_names():
            SpreadVisitor.add_spread(state, name, Spread(values=set(), depth=0, is_return_value=True))

    def _construct_RVS(self, state: State) -> list[Spread]:
        node = adapters.Def(state)
        ret_node = adapters.ArgsRets(state.but_with(ast=node.get_rets_ast()))
        RVS: list[Spread] = []
        for name in ret_node.get_names():
            spread_for_this_return_value = SpreadVisitor.get_spread(state, name)
            RVS.append(spread_for_this_return_value)

        return RVS

    def _construct_AS(self, state: State) -> list[Spread]:
        node = adapters.Def(state)
        arg_node = adapters.ArgsRets(state.but_with(ast=node.get_args_ast()))
        AS: list[Spread] = []
        for name in arg_node.get_names():
            spread_for_this_argument = SpreadVisitor.get_spread(state, name)
            AS.append(spread_for_this_argument)

        return AS

    def of_function(self, state: State) -> Deps:
        """State should have state.get_ast() return an abstract syntax list of type 'def'. This is
        the pointer to F, and this function will return F_deps. Cache lookups will be performed if
        F takes no free function parameters; else novel computation is required.
        """
        # print("getting deps for", adapters.Def(state).get_function_name())
        cached_f_deps = self._try_cache_lookup(state)
        if cached_f_deps is not None: return cached_f_deps
        # print("no cache found")

        # all processing must occur inside an isolate context, to avoid name collisions from
        # previous functions.
        state = state.but_with(context=state.create_isolated_context())
        node = adapters.Def(state)
        self._add_new_spreads_for_inputs(state)

        # invoke the SpreadVisitor to populate all spreads with the correct values after the
        # function call. Depth counts down, starting at -2 (it is underneath the first argument
        # value), and decreasing for each if/while context entered.
        # note: a depth of -1 indicates a literal/token
        self.spread_visitor.apply(state.but_with(
            ast=node.get_seq_ast(),
            depth=-2))

        RVS = self._construct_RVS(state)
        AS = self._construct_AS(state)

        # # need to keep this here to examine code inside this function, even though we know
        # # it has no return value
        # if not node.has_return_value():
        #     return Deps()

        F_deps = Deps.create_from_return_value_spreads(RVS, AS)
        self._add_to_cache(state, F_deps)
        return F_deps


#Name:  Dahalia Howell

#My First Ever Github Project :)

#This function checks an inputted list to determine whether or not it is a fibonacci sequence.
#It returns True if it is and False if it is not.
def fib_check(lst):
    target = lst[0]
    counter = 0
    while target > fib(counter):
        counter+=1
    if counter != target:
        return False
    return lst == genFib(counter, counter + len(lst))

#This function returns the fibonacci number of its input.
def fib(x):
    if x == 0:
        return 0
    elif x < 3:
        return 1
    else:
        return fib(x-1) + fib(x-2)

#This function accepts the starting number and one plus the ending number of a range as input.
#It the finds the fibonacci number of each number within the range and adds them to a list after each iteration.
#The function returns a list containing the fibonacci sequence of the range.
def genFib(start, end):
    lst = []
    for i in range(start, end):
        lst += [fib(i)]
    return lst

# print(genFib(0,6))
print(fib_check([0,1,1,2,3,5]))


import os
import pandas as pd
import numpy as np
import nltk
from bs4 import BeautifulSoup
nltk.download('stopwords')
nltk.download('wordnet')
from nltk.stem import PorterStemmer #not used due to poor performance
from nltk.stem import WordNetLemmatizer
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from nltk.corpus.reader.plaintext import PlaintextCorpusReader
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import train_test_split, KFold, cross_val_score
from sklearn.linear_model import LogisticRegression
#from sklearn.model_selection import cross_val_score

def construct_file_list(directory):
	file_list = []
	for text_file in sorted(os.listdir(directory)):
		os.chdir(directory)
		if text_file.endswith(".txt"):
	    	#print(os.getcwd())
			file_list.append(text_file)
	if(directory == '/Users/Tausal21/Desktop/comp_551/mini_peoject_02/test'):
		#file_list.sort(key=lambda f: int(filter(str.isdigit, f)))
		file_list = sorted(file_list , key=lambda x: int(os.path.splitext(x)[0]))
	return file_list

def construct_feature_matrix_countVectorizer(directory, maximum_features, target_column_value, boolean_train):
	file_list = construct_file_list(directory)

	cv = CountVectorizer(input='filename', stop_words='english', max_df=0.75, min_df=5, max_features=maximum_features)
	vec = cv.fit(file_list)

	bag_of_words = vec.transform(file_list)
	feature_matrix_withoutTarget = pd.DataFrame(bag_of_words.toarray(), columns=vec.get_feature_names())

	if(boolean_train == False):
		file_list_df = pd.DataFrame({'col': file_list})
		#print(file_list_df)
		return [feature_matrix_withoutTarget, file_list_df] #This returns the test_set feature matrix
	else:
		if(target_column_value == 1):
			Y_raw = np.ones((12500,), dtype=float)
			target_column_Y = pd.DataFrame(Y_raw, columns=['TARGET_Y']) #appends target column for positive review
		else:
			Y_raw = np.zeros((12500,), dtype=float)
			target_column_Y = pd.DataFrame(Y_raw, columns=['TARGET_Y']) #appends target column for positive review

		feature_matrix = pd.concat([feature_matrix_withoutTarget, target_column_Y], axis=1)
		return feature_matrix #returns pos/neg training feature matrix with labels

def kFold_LogisticRegression(feature_matrix_input, no_of_folds):
	model = LogisticRegression()
	scores = cross_val_score(model, feature_matrix_input.loc[:, feature_matrix_input.columns != 'TARGET_Y'], feature_matrix_input.TARGET_Y, cv=no_of_folds)
	return scores

def Logistic_reg(train_X, train_Y, test_X):
	print("train_X shape: ", train_X.shape)
	print("train_Y shape: ", train_Y.shape)
	model = LogisticRegression()
	model.fit(train_X, train_Y)

	prediction_list = model.predict(test_X)
	return prediction_list

pos_dir = '/Users/Tausal21/Desktop/comp_551/mini_peoject_02/train/pos'
neg_dir = '/Users/Tausal21/Desktop/comp_551/mini_peoject_02/train/neg'
test_dir = '/Users/Tausal21/Desktop/comp_551/mini_peoject_02/test'

pos_features = construct_feature_matrix_countVectorizer(pos_dir, 5000, 1, True)
print("Pos_features shape: ", pos_features.shape)
neg_features = construct_feature_matrix_countVectorizer(neg_dir, 5000, 0, True)
print("Neg_features shape: ", neg_features.shape)

feature_matrix_list = [pos_features, neg_features]
feature_matrix_final = pd.concat(feature_matrix_list, sort=False).fillna(0)
print("final_feature shape: ", feature_matrix_final.shape)
no_of_features = len(feature_matrix_final.columns) - 1
print("number of features: ", no_of_features)

[test_set, file_list_df] = construct_feature_matrix_countVectorizer(test_dir, no_of_features, 0, False)
print("test_set shape: ", test_set.shape)
print(file_list_df)

#scores = kFold_LogisticRegression(feature_matrix_final, 10)
prediction_list = Logistic_reg(feature_matrix_final.loc[:, feature_matrix_final.columns != 'TARGET_Y'], feature_matrix_final.TARGET_Y, test_set)
prediction_list_df = pd.DataFrame(prediction_list)

output_df = pd.concat([file_list_df, prediction_list_df], axis=1)
output_df.to_csv('output2.csv')
print(output_df)


#!/usr/bin/env python
# coding: utf-8

# In[462]:

import numpy as np
import pandas as pd
from pandas import read_csv
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
from matplotlib.pyplot import figure
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import r2_score
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
from sklearn.ensemble import RandomForestRegressor
import seaborn as sns
import math

import statistics as stat
from sklearn.neural_network import MLPRegressor

# Seguimos el hilo argumental del [ejercicio 9.1](https://github.com/Gerard-Bonet/Sprint9Tasca1.git) para trabajar con el 9.2. No nos servirán las variables del ejercicio 9.1, ya que
#
# no dividimos el conjunto de datos  en variables independientes y objetivos. Es decir, no vamos a aprobechar nada de él pero si
#
# alguna información, que vamos a pasar a resumir:
#
#

# In[556]:

df = pd.read_csv("DelayedFlights.csv") # este es el conjunto de datos proporcionado en el ejercicio
df

# - Las variables DepTime','CRSDepTime', 'ArrTime', 'CRSArrTime" básicamente son las horas programadas y reales que acaban determinando 'ActualElapsedTime', 'CRSElapsedTime', 'AirTime', 'ArrDelay','DepDelay'. Restar  'ArrTime' y 'CRSArrTime nos da ArrDelay, por ejemplo. Mientras en el otro ejercicio, no nos hicieron falta, para entrenar una red neuronal o un arbol, nos pueden venir bien si no contamos con la variable DepDelay( Ejercicio 3)
#
# - Las variables "CarrierDelay","WeatherDelay","NASDelay","SecurityDelay","LateAircraftDelay" tienen un tercio de valores NaN, y la suma de todas es el retraso general.
#
# - 'FlightNum' y'TailNum' son variables catogóricas que no aportan mucho
#
# - "ActualElapsedTime",  "CRSElapsedTime","AirTime" y "Distance" tienen un coeficiente de correlación lineal entre ellas cercano a 0,95 $\pm 2$ , mientras que ArrDelay y DepDelay, tienen una correlación cercana a cero respecto a estas 4 variables.
#
# - Arrdelay y DepDelay tienen una correlación cercana a 0,8.
#
# - Entre el primer grupo(distance) y el segundo(arrdelay) el Coeficiente de correlación tiende a cero
#
#
# - los aeropuertos donde hay más vuelos hay más minutos acumulados de retrasos. No crece de manera lineal, va creciendo de forma $ax^2 +bx$ de forma muy aplanada. Ésto estaba por corroborar.
#
# - Con las compañías crece de forma lineal. A más vuelos, más minutos acumulados de retrasos.
#
# - Ignoraré las variables Cancelled o Diverted ya que si tienen un valor de 1 ( y no llegan a 8000 casos) tienen valores NaN en ArrDelay y DepDelay
#
#
#
#

# 0. **PREPROCESAMIENTO DE DATOS.**
#
# Vamos a dedicar esta parte a tratar las variables con valores perdidos, transformación de estas variables, selección, y otras
#
# manipulaciones para poder aplicar a las regresiones

# In[464]:

df.columns

# 0.1. **Muestreo de población y tratamiento de valores perdidos**
#
# Primero hacemos un **muestreo de la población** para evitar problemas de memoria, ya que al hacer ciertas operaciones
#
# sobre todo el conjunto de datos, el ordenador da problemas de memoria, incluso vectorizando
#

# In[557]:

df1= df.sample(390000)# el 20% aproximadamente
df1.isnull().sum()# miramos la cantidad de valores perdidos

# Como hicimos en la [ejercicio 9.1](https://github.com/Gerard-Bonet/Sprint9Tasca1.git) vamos a ver si estos valores NaN corresponden a vuelos cancelados o derivados, que no van a servir de nada para calcular el valor de ArrDelay

# In[562]:

# vamos a ver si todos los valores NaN corresponden a todos lo vuelos Cancelados o Derivados
df1_div= df1[df1["Diverted"]==1]
df1_can=df1[df1["Cancelled"]==1]
df1_div.shape#número de vuelos desviados

# In[563]:

df1_can.shape#número de vuelos cancelados

# In[564]:

df1_div.shape[0]+df1_can.shape[0]# número total de cancelados y derivados.

# In[565]:

df1_div["ArrTime"].isnull().sum()+df1_can["ArrTime"].isnull().sum()# que coincide con los valores NaN de ArrTime

# In[566]:

df1_div["ActualElapsedTime"].isnull().sum()+df1_can["ActualElapsedTime"].isnull().sum()# esto daría lo mismos
# para ArrDelay y DepDelay

# Los valores NaN, coinciden con aquellos que el vuelos ha sido Cancelado o Desviado,por lo tanto, no aportan información
#
# al cálculo de la regresión de ArrDelay, optamos por eliminarlos

# In[567]:

df2=df1.dropna( subset=["ArrDelay"]).reset_index(drop=True)
df2.isna().sum()

# 0.2. **Transformación de variables horarias**
#
# En esta parte vamos a convertir las variables DepTime,	CRSDepTime,	ArrTime,	CRSArrTime en la función cíclica.
#
# Estas cuatro variables vienen en formato horario  hh:mm. Lo que haremos será contar todos los minutos transcurridos durante
#
# el día, siendo 0 minutos a las 00:00 y 1440 los minutos transcurridos durante el día a las 23:59.
#
# Más adelante, en el apartado 0.4, transformaremos estas variables en cíclicas.
#
#
#
#
#
#

# In[568]:

# Primero de todo convierto las variables horarias en formato hora y para eso tienen que haber 4 digítos, que los relleno por la
#izquierda con ceros
# Primero tengo que convertir en entero las variables DepTime y ArrTime en enteros para evitar los decimales

df2['DepTime'] = df2['DepTime'].astype(int)

# In[569]:

df2['ArrTime'] = df2['ArrTime'].astype(int)
df2

# In[570]:

#relleno por la izquierda con ceros
df2['DepTime'] = df2['DepTime'].astype(str).str.zfill(4)
df2['CRSDepTime'] = df2['CRSDepTime'].astype(str).str.zfill(4)
df2['ArrTime'] = df2['ArrTime'].astype(str).str .zfill(4)
df2['CRSArrTime'] = df2['CRSArrTime'].astype(str).str.zfill(4)
df2.head()

# In[571]:

# las convierto en formato horario( Nota: en un principio lo pasé a formato horario por si lo necesitaba para datetime, pero
# al final opté por otro tipo de conversión)
df2['DepTime'] = df2['DepTime'].astype(str).str[:2]  + ':' + df2['DepTime'].astype(str).str[2:4] + ':00'
df2['CRSDepTime'] = df2['CRSDepTime'].astype(str).str[:2] + ':' + df2['CRSDepTime'].astype(str).str[2:4] + ':00'
df2['ArrTime'] = df2['ArrTime'].astype(str).str[:2] + ':' + df2['ArrTime'].astype(str).str[2:4]  + ':00'
df2['CRSArrTime'] = df2['CRSArrTime'].astype(str).str[:2] + ':' + df2['CRSArrTime'].astype(str).str[2:4] + ':00'

df2

# In[572]:

# creamos la función minutos, que divide la hora hh:mm con un Split, en una lista ("hh","mm"), reconvierte hh y mm en enteros,
# para luego pasarlos a minutos, y con la reconverión ya comentada aplica la función minutos()
def minutos(x):
    x=x.split( sep=":")
    seg= 60*(int(x[0]))+(int(x[1]))

    return seg

dfhoras= df2[["DepTime", "CRSDepTime", "ArrTime", "CRSArrTime"]]

# In[573]:

dfhoras_DT= dfhoras["DepTime"].apply(minutos)
dfhoras_CRSD=dfhoras["CRSDepTime"].apply(minutos)
dfhoras_AT=dfhoras["ArrTime"].apply(minutos)
dfhoras_CRSA=dfhoras["CRSArrTime"].apply(minutos)

# In[574]:

df2.columns

# In[575]:

df3= df2.drop(['Unnamed: 0', 'Year', 'DepTime',
       'CRSDepTime', 'ArrTime', 'CRSArrTime','FlightNum', 'TailNum', 'Cancelled', 'CancellationCode', "Diverted"], axis=1)
# 'Unnamed: 0' y  'Year" no aportan nada,  TailNum y Flight Num son eliminadas por cuestión de practicidad y para no
# añadir columnas vía Dummies por cada código de vuelo o Tailnum
# Y al Final , Cancelled y Diverted no aportan nada al cálculo de arrdelay

# In[576]:

# ahora añadimos las cuatro columnas nuevas

df4= pd.concat([df3, dfhoras_DT,dfhoras_CRSD , dfhoras_AT, dfhoras_CRSA], axis=1)
df4.columns

# In[578]:

df4[["DepTime", "CRSDepTime", "ArrTime", "CRSArrTime"]].describe()# miramos como quedan para ver si hay alguna anomalía en
# los máximos y mínimos

# In[579]:

df4.isna().sum()#revisamos el número de nulos

# 0.3 **Transformación de Variables Delay.**
#
# Vamos a analizar la variables ArrDelay y DepDelay, rescepto a los motivos del retraso.
#
#

# In[580]:

df_delay= df4[['ArrDelay','DepDelay','CarrierDelay', 'WeatherDelay', 'NASDelay', 'SecurityDelay','LateAircraftDelay',]]

df_delay

# A simple vista vemos que la suma de minutos por fila  de CarrierDelay', 'WeatherDelay', 'NASDelay', 'SecurityDelay',
#
# 'LateAircraftDelay', es igual a ArrDelay

# In[581]:

sns.pairplot( df_delay,kind="reg", x_vars=['CarrierDelay', 'WeatherDelay', 'NASDelay', 'SecurityDelay','LateAircraftDelay'], y_vars="ArrDelay")

# In[582]:

# Tras visualizar el DF veo como posibilidad que si ArrDelay es menor que x minutos ( x podría ser de 10 o 20 minutos ),
# las X_vars tienen valores NaN
# también veo que si se da la condición(min< x), las cinco variables de X_Vars son NaN
df_delay[df_delay["CarrierDelay"].isna()]

# In[583]:

df_delay[df_delay["ArrDelay"]>=20].isna().sum()#miramos varios valores de Arrdelay para ver cuando empiezan a parecer valores NaN

# In[584]:

df_delay[df_delay["ArrDelay"]>18].isna().sum()

# In[585]:

df_delay[df_delay["ArrDelay"]>15].isna().sum()

# In[586]:

df_delay[df_delay["ArrDelay"]>13].isna().sum()

# In[591]:

dfd=df_delay[df_delay["ArrDelay"]>=15]# de manera definitiva
dfd.isna().sum()

# In[592]:

dfd=df_delay[df_delay["ArrDelay"]<15]
dfd.isna().sum()

# Con esto acabamos de demostrar que los valores de **ArrDelay < 15 minutos**, no registran las causas de retraso.
#
# Podriamos sustituir los valores NaN repartiendo lo minutos de Arrdelay<15 entre las cinco variables, pero hay valores de Arrdelay negativos. **Así que asignaremos un valor de 0.0 a todos lo NaN**
#
#

# In[593]:

dfd2=df_delay[df_delay["ArrDelay"]>=15]
dfd2.isna().value_counts()

# In[595]:

delay_not_NAN= df_delay[['CarrierDelay', 'WeatherDelay', 'NASDelay', 'SecurityDelay','LateAircraftDelay']].fillna(0.0)
delay_not_NAN.isna().value_counts()

# In[596]:

delay_not_NAN.describe()

# In[597]:

df5_0= df4.drop(  ["CarrierDelay", 'WeatherDelay', 'NASDelay', 'SecurityDelay','LateAircraftDelay'], axis=1 )# borramos los
#valores con NaN, y añadimos las variables con la sustitución de NaN por cero
df5= pd.concat([df5_0, delay_not_NAN], axis =1)
df5.isna().sum()

# 0.4 **Variables Categóricas y Visualización de variables.**
#
#  En este apartado vamos a ver de que manera se comportan las viarbles para determinar cuales son independientes o no, así como
#  analizar la categóricas.
#
#

# In[598]:

df5.columns

# Cómo recordamos en el [ejercicio 9.1](https://github.com/Gerard-Bonet/Sprint9Tasca1.git), habían 300 **origenes y destinos**, así como 20 **compañías**. El retraso acumulado en ArrDelay
#
# tenía una relación lineal en el número de vuelos por compañías, así que tampoco aportaba mucha más información.
#
# Mientras que por aeropuerto tenía una tendencia lineal, y crecía algo más para aeropuertos con muchos vuelos
#
# Así que hacer un get_dummies nos generaría 640 variables, así que **vamos a eliminarlas**.

# In[599]:

df5.drop(["UniqueCarrier", "Origin", "Dest"], axis=1, inplace=True)

# In[600]:

# Vamos a ver la correlación lineal
df5corr= df5.corr()
f, ax = plt.subplots(figsize=(15,15))
sns.heatmap(df5corr, vmax=1, vmin=-1, square=True,cmap="Blues", annot=True)
plt.show()

#

# Nos permite ver que LateAircraft Delay, NasDelay, WheatherDelay y Depdelay son las variables con alta correlación lineal con ArrDelay, y como vimos en el 9.1 ActualElapsedTime', 'CRSElapsedTime', 'AirTime', y Distance  están altamente correlaiconadas
# entre ellas pero no con ArrDelay
#
# Las variables temporales (mes, dia del mes y dia de la semana ) tienen una correlación casi nula con el resto de
# variables, además de que en este DataSet funcionan como variables categóricas.
#
# Empecemos por ver como se distribuye arrdelay en función de los meses, que cómo ya habíamos visto en el ejercicio 9.1 hay más
# vuelos de Diciembre a Marzo y de Junio a Agosto.
#
# También, si nos fijamos en los días de la semana, vimos en 9.1 que los Jueves, Viernes, Domingos y Lunes tenían más vuelos que los otros días. Siendo el Viernes el día con más vuelos y el sábado el que menos.

# In[601]:

df5ArrMonth= df5[df5["ArrDelay"]<200] # miramos como se distribuye Arrdelay en función del mes
order= []
for i in range(1,13):
    order.append(i)

g = sns.FacetGrid(df5ArrMonth, row="Month", row_order= order,
                  height=2.7, aspect=5,)
g.map( sns.histplot, "ArrDelay", stat="count")

# In[602]:

df5[["ArrDelay", "Month"]].groupby("Month").mean()

# In[603]:

df5ArrMonth= df5[df5["ArrDelay"]<200] # y hacemos lo mismo para el día de la semana
order2= []
for i in range(1,8):
    order2.append(i)

g = sns.FacetGrid(df5ArrMonth, row="DayOfWeek", row_order= order2,
                  height=2.7, aspect=5,)
g.map( sns.histplot, "ArrDelay", stat="count")

# In[604]:

df5[["ArrDelay", "DayOfWeek"]].groupby("DayOfWeek").mean()

# In[605]:

#También mmiramos la distribución del retraso acumulado por meses  y días

df5[["ArrDelay", "Month"]].groupby("Month").sum().plot(kind="bar")
df5[["ArrDelay", "DayOfWeek"]].groupby("DayOfWeek").sum().plot(kind="bar")

# Las últimas distribuciones tienen una distribución casi idéntica al conteo  de vuelos de Month y Dayofweek que vimos
# en [ejercicio 9.1](https://github.com/Gerard-Bonet/Sprint9Tasca1.git); es decir, a más vuelos, más retraso acumulado.
#
# Teniendo en cuenta que los vuelos pueden llegar al día siguiente, como los vuelos salidos el Lunes pueden llegar el Martes,
# la media de atrasos en función de los días de la semana se mantiene en $ 41.5 \pm 2.5 $. Teniendo en cuenta ésto, y que el día
# de la semana tiene un índice de correlación muy bajo, y que como pasaba con las compañías, hay más atrasado acumulado en función del dia de la semana o del mes a causa de que hay más cantidad de vuelos. Vamos a descartar estas dos variables.
#
# No voy a hacer el mismo razonamiento para DayofMonth, ya que puedo usar el mismo argumento que con las otras dos variables.
#
# El día del Mes, el mes y el día de la semana , no influye en los retrasos y además nos generaría contabilizar muchas más columnas, ya que son variables categóricas.
#

# In[606]:

df6= df5.drop(['Month', 'DayofMonth', 'DayOfWeek'], axis=1)

# In[608]:

df6.shape# miramos dimensiones del Data Set

# Las Variables "DepTime", "CRSDepTime", "ArrTime", "CRSArrTime", deberían ser una función cíclica, es decir, cuando las horas de
# Arrtime sea menor que DepTime, habría contar 1440 minutos más, dando igual si es CRS o no

# In[508]:

df6[["DepTime", "CRSDepTime", "ArrTime", "CRSArrTime"]].describe()

# In[609]:

f,axs= plt.subplots(2, 2, figsize=(14,8))
sns.regplot(data=df6, x=  "DepTime",y = "ArrDelay",ax= axs[0,0], ci=None,scatter_kws={"color": "blue"}, line_kws={"color": "red"})

sns.regplot( data=df6, x=  "CRSDepTime",y = "ArrDelay",ax= axs[0,1], ci=None,scatter_kws={"color": "blue"}, line_kws={"color": "red"})

sns.regplot( data=df6, x=  "ArrTime",y = "ArrDelay",ax= axs[1,0]  , ci=None, scatter_kws={"color": "blue"}, line_kws={"color": "red"})

sns.regplot( data=df6, x=  "CRSArrTime",y = "ArrDelay",ax= axs[1,1]  , ci=None, scatter_kws={"color": "blue"}, line_kws={"color": "red"})

# In[614]:

minimo=df[df["ArrDelay"]<0].sort_values("ArrDelay")# miramos los valores más bajos de ArrDelay
zmin=minimo["ArrDelay"].min()
zmin

# In[615]:

# podemos observar una independencia casi total, pero si hacemos lo siguiente.
def rest(z):
    x=z[0]
    y=z[1]
    if (x < y) & ((x-y)<zmin):
        t= (1440+x)-y
        return t
    else:
        t= x-y
        return t

x11= df6[["DepTime","CRSDepTime" ]].apply(rest, axis=1)
x10= df6[["ArrTime","CRSArrTime" ]].apply(rest,axis=1)

f,axs= plt.subplots(2, 1, figsize=(14,8))

sns.regplot(data=df6, x=  x10,y = "ArrDelay",ax= axs[0], ci=None,scatter_kws={"color": "blue"}, line_kws={"color": "red"})

sns.regplot( data=df6, x=  x11,y = "DepDelay",ax= axs[1], ci=None,scatter_kws={"color": "blue"}, line_kws={"color": "red"})

plt.show()

# Sean **x10** y **x11** definidas por
#
# **x10= df6["ArrTime"]-df6["CRSArrTime"]**
#
# **x11= df6["DepTime"]-df6["CRSDepTime"]**
#
# podemos observar una relación lineal.
#
#
#
# Por otro lado, habíamos visto en el ejercicio 9.1 lo siguiente:
#
# "ActualElapsedTime", "CRSElapsedTime","AirTime" y "Distance" tienen un coeficiente de correlación lineal entre ellas cercano a 0,95  ±2  , mientras que ArrDelay y DepDelay, tienen una correlación cercana a cero respecto a estas 4 variables.
#
# Arrdelay y DepDelay tienen una correlación cercana a 0,8.
#
# Por lo que sólo nos queda estudiar Taxiin y taxiout

# In[616]:

f,axs= plt.subplots(2, 1, figsize=(14,8))

sns.regplot(data=df6, x=  "TaxiIn",y = "ArrDelay",ax= axs[0], ci=None,scatter_kws={"color": "blue"}, line_kws={"color": "red"})

sns.regplot( data=df6, x=  "TaxiOut",y = "ArrDelay",ax= axs[1], ci=None,scatter_kws={"color": "blue"}, line_kws={"color": "red"})

plt.show()

# Podemos ver que ambas variables (TaxiIn y TaxiOut)tienen una correlación muy baja respecto a ArrDelay, a pesar de la tendencia
# lineal. Pero hay una gran acumulación de restrasos importantes a pesar de tiempos cortos de tiempos de despegue (TaxiOut) o de
# aterrizaje, lo que hace perder la linealidad para valores bajos de taxiin o taxiouit
#
#

# 0.5 **Transformación y Selección de Variable**
#
# Vamos a usar el coeficiente de correlación para seleccionar las características que mejor nos sirven para la regressión.
#
# Antes de todo, vamos a remodelar el data set, añadiendo x10 y x11, y eliminado 'DepTime', 'CRSDepTime', 'ArrTime', 'CRSArrTime', ya que x10 y x11 son combinaciones lienales de estas 4.
#
# También eliminamos 'ActualElapsedTime', 'CRSElapsedTime', 'AirTime' ya que tienen un 0.95 de correlación o más  con Distance y aportan la misma información.
#
#

# In[617]:

x10=x10.rename("X10")
x11=x11.rename("X11")
x10.describe()

# In[618]:

x11.describe()

# In[619]:

x1= pd.concat([x10,x11,df6["ArrDelay"]],axis=1)
x1.corr()

# In[620]:

#remodelamos el DF con x10 y x11
df6b=df6.drop(['DepTime', 'CRSDepTime', 'ArrTime', 'CRSArrTime', 'ActualElapsedTime', 'CRSElapsedTime', 'AirTime'], axis=1)
df7=pd.concat([df6b, x10,x11], axis =1)
df7

# -Hasta el momento hemos reducido una docena de variables categóricas, bien porque no aportaban nada como Year, bien porque
# nos aumentaban la dimensionalidad del DataSet  como Origen o bien porque no influenciaban en nada  como
# el mes en que se daba el vuelo sobre el ArrDelay.
#
# -Hemos reducido 4 variables continuas a x10 y x11
#
# -Y hemos reducido 4 variables a 1, debido a su alto grado de correlación entre ellas( dejando Distance)
#
# Con las que quedan, vamos a ver el coeficente de correlación de Spearman, pero antes de todo,vamos a estandarizar las variables
#
#

# In[622]:

scaler = StandardScaler()

df8= pd.DataFrame(scaler.fit_transform(df7), columns=df7.columns )

df8.describe().round(3)

# In[623]:

# y aplicamos el coeficiente de correlación de Spearman
df8corr= df8.corr(method="spearman")
f, ax = plt.subplots(figsize=(15,15))
sns.heatmap(df8corr, vmax=1, vmin=-1, square=True,cmap="Blues", annot=True)
plt.show()

# EL coeficiente de correlación de Sperman tampoco no aporta mucho más que el de Pearson. Vamos a mirar un método de selección
# de variables, para ver cuales son las mejores variables. Escogeremos f_regression.

# In[624]:

df8.columns

# In[626]:

from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_regression
Xpreseleccion= df8.drop(["ArrDelay"], axis=1)
ypreseleccion= df8["ArrDelay"]
for i in range(1,12): # vamos a mirar como f_selection va escogiendo las variables en función del estadístico F
    fs = SelectKBest(score_func=f_regression, k=i)
    XS=fs.fit(Xpreseleccion,ypreseleccion)

    filter=fs.get_support()
    variables=np.array(Xpreseleccion.columns)
    print(variables[filter])
    print (XS.scores_[filter])
    print ("\n")

# Observamos que la selección de variables por f_Regression nos lleva a unos resultados muy similares al coeficiente correlación
# Pearson. Así que escogeremos la variables con mayor inidce que correlación:
#
#  sean las variables,    ['DepDelay' 'TaxiOut' 'CarrierDelay' 'NASDelay' 'LateAircraftDelay']
#

# In[627]:

df9= df8[["ArrDelay",'DepDelay', 'CarrierDelay', 'NASDelay' ,'LateAircraftDelay', 'X10', 'X11']]
df9.head()

# 0.6 **Separación entre Train y Test**.

# In[669]:

X_= df9.drop(["ArrDelay"], axis=1)

y_= df9["ArrDelay"]

X_train, X_test, y_train, y_test = train_test_split( X_, y_, test_size=0.30, random_state=42, shuffle=True)

# 1.  **Modelos de regresión**
#
# Crea tres modelos de regresión para predecir ArrDelay

# In[670]:

#Creamos los 3 modelos
lin = LinearRegression()
rft=RandomForestRegressor(n_estimators=200, max_depth=10, random_state=42 )
mpl= MLPRegressor(hidden_layer_sizes=(20,20,20), activation="logistic", solver="sgd",max_iter=300 )

# - **Modelo de regresión lineal**

# In[671]:

lin.fit(X_train, y_train)
fx_lin= lin.predict(X_test)# la f(x0,....,xn)predicha

print(fx_lin)# valores de fx predichos
print(fx_lin.shape) #tamaño de la matriz

# In[672]:

r_lin = lin.score(X_test, y_test)
r_lin # podemos ver que el ajuste de correlación es de valor alto

# In[673]:

# sea y = A1X1+A2X2+......+AnXn + b
print('punto de corte del eje y(x=0) ', lin.intercept_) # marca el punto de intercepeción del eje y cuando x=0, b
print( "coeficientes de las variables x", lin.coef_)# marca los coeficientes A1,...:AN de las variables indeondientes

# - **Modelo de bosque aleatorio**

# In[674]:

rft.fit(X_train, y_train)
fx_rft= rft.predict(X_test)# la f(x0,....,xn)predicha
print(fx_rft)# valores de fx predichos

# In[675]:

# miramos la correlación lienal
r_rft = rft.score(X_test, y_test)
r_rft

# In[676]:

# como no calcula coeficientes, ya que los cálculos los hace en función de la ganancia de información de cada arbol del conjunto
# aleatorio, miramos la importancia de cada caracterísitca.
importance = rft.feature_importances_
variables_finales=['DepDelay', 'CarrierDelay', 'NASDelay' ,'LateAircraftDelay', 'X10', 'X11']
for i,j in enumerate(importance):
    print('Feature: %0d, Score: %.5f' % (i,j), variables_finales[i])

# - **Modelo de red neuronal perceptron multicapa**

# In[677]:

mpl.fit(X_train, y_train)
fx_mpl= mpl.predict(X_test)# la f(x0,....,xn)predicha

print(fx_mpl)# valores de fx predichos

# In[678]:

# comprobamos el coeficiente de la regresión
r_mpl= mpl.score(X_test, y_test)
r_mpl

# 2. **Comprueba el error en la métrica de MSE y R2**
#

# Podemos observar, que los coeficientes de correlación tienen muy buenos ajustes.
#
#

# In[679]:

print( "correlación lineal para la regresión lineal ", r_lin)

# In[680]:

print( "correlación lineal para el bosque aleatorio ", r_rft)

# In[681]:

print( "correlación lineal para el perceptrón multicapa ", r_mpl)

# Ahora miramos el error cuadrático medio

# In[703]:

print('Error cuadrático medio de la regresión lineal :', mean_squared_error(y_test, fx_lin))

# In[704]:

print('Error cuadrático medio del bosque aleatorio:', mean_squared_error(y_test, fx_rft))

# In[705]:

print('Error cuadrático medio de la red enurona:', mean_squared_error(y_test, fx_mpl))

# Contando que las variables están estandarizadas, y la media tiende a cero, y el error cuadrático medio reduce las
# discrepancias menores a uno, el que mejor rendimiento saca es el Bosque Aleatorio

# - **Ejercicio 3** :Modificar el modelo para ver el resultado.
#
# Vamos a modificar ciertos parámetros del modelo para ver cómo responden

# ------------------------------------------------------------------------------------

# .  **Regresión lineal**

# Modificamos el témino constante

# In[686]:

#Empecemos modificando, quitando el término constante de la ecuación
lin2 = LinearRegression(fit_intercept= False  )

# In[687]:

lin2.fit(X_train, y_train)
fx_lin2= lin2.predict(X_test)

# In[701]:

r_lin2 = lin2.score(X_test, y_test)
print("coeficiente sin término constante", r_lin2)
print("coeficiente con término constante ", r_lin)
print("diferencia de ajuste  = ", (r_lin-r_lin2))
if r_lin< r_lin2:
    print ( "la regresión sin término constante tiene mejor ajuste ")
else:
    print ( "la regresión con término constante tiene mejor ajuste ")

# In[707]:

print( "coeficientes de las variables x sin término constante ", lin2.coef_)
print( "coeficientes de las variables x con término constante ", lin.coef_)

# In[759]:

print('Error cuadrático medio de la regresión lineal sin término constante:', mean_squared_error(y_test, fx_lin2))
print('Error cuadrático medio de la regresión lineal con término constante:', mean_squared_error(y_test, fx_lin))
if  mean_squared_error(y_test, fx_lin)<  mean_squared_error(y_test, fx_lin2):
    print ( "la regresión con término constante tiene menor error de ajuste ")
else:
    print ( "la regresión sin término constante tiene menor error de ajuste ")

# Tenemos unas discrepancias mínimas, podemos ver que el ajuste sin término constante tiene mejor ajuste con el coeficiente de
# correlación, sin embargo su error es menor en el término constante

# . **Bosque Aleatorio.**

# Empecemos modificando el número de árboles a la mitad

# In[714]:

rft2=RandomForestRegressor( n_estimators=100, max_depth=10, random_state=42 )

# In[715]:

rft2.fit(X_train, y_train)
fx_rft2= rft2.predict(X_test)

# In[722]:

r_rft2 = rft2.score(X_test, y_test)
print("r del bosque  con 100 árboles  ", r_rft2)
print("r del bosque  con 200 árboles  ", r_rft)

# In[723]:

if r_rft< r_rft2:
    print ( "bosque  con 100 árboles, tiene mejor ajuste")
else:
    print ( "bosque  con 200 árboles , tiene mejor ajuste ")

# In[760]:

print('Error cuadrático medio de la regresión lineal con 100 árboles:', mean_squared_error(y_test, fx_rft2))
print('Error cuadrático medio de la regresión lineal con 200 árboles:', mean_squared_error(y_test, fx_rft))
if  mean_squared_error(y_test, fx_rft)<  mean_squared_error(y_test, fx_rft2):
    print ( "la regresión con 200 árboles tiene menor error de ajuste ")
else:
    print ( "la regresión con 100 árboles tiene menor error de ajuste ")

# modificamos el máximo de la profundidad de las capas a la mitad

# In[719]:

rft3=RandomForestRegressor( n_estimators=200, max_depth=5, random_state=42 )

# In[720]:

rft3.fit(X_train, y_train)
fx_rft3= rft3.predict(X_test)

# In[725]:

r_rft3 = rft3.score(X_test, y_test)
print("r del bosque  con 5 capas   ", r_rft3)
print("r del bosque  con 10 capas   ", r_rft)

# In[726]:

if r_rft< r_rft3:
    print ( "bosque  con 5 capas, tiene mejor ajuste")
else:
    print ( "bosque con 10 capas , tiene mejor ajuste ")

# In[761]:

print('Error cuadrático medio de la regresión lineal con 5 capas:', mean_squared_error(y_test, fx_rft3))
print('Error cuadrático medio de la regresión lineal con 10 capas:', mean_squared_error(y_test, fx_rft))
if  mean_squared_error(y_test, fx_rft)<  mean_squared_error(y_test, fx_rft3):
    print ( "la regresión con 10 capas tiene menor error de ajuste ")
else:
    print ( "la regresión con  5 capas tiene menor error de ajuste ")

# - **Red Neuronal**

# Vamos a modificar el número de capas, la tasa de aprendizaje, la función de activación, el método de cálculo del gradiente,

# In[728]:

mpl1= MLPRegressor(hidden_layer_sizes=(20,20), activation="logistic", solver="sgd",max_iter=300 )# número de capas
mpl2= MLPRegressor(hidden_layer_sizes=(20,20,20), activation="relu", solver="sgd",max_iter=300 )# la función de activación
mpl3= MLPRegressor(hidden_layer_sizes=(20,20,20), activation="logistic", solver="sgd",max_iter=300, learning_rate_init=0.01,
                  learning_rate= "invscaling")# modificando la tasa de aprendizaje
mpl4= MLPRegressor(hidden_layer_sizes=(20,20,20), activation="logistic", solver="adam",max_iter=300 )# solventamos por Adam

# En MPL1 hemos quitado una capa

# In[729]:

mpl1.fit(X_train, y_train)#Entrenamos los modelos

# En MPL2 hemos cambiado la función de activación tipo RELU, tal que si x<0 Relu=0 , si x>=0, Relu=x

# In[730]:

mpl2.fit(X_train, y_train)

# En MPL 3 hemos modificado hemos modificado la tasa de aprendizaje de 0.001 a 0.01, y en vez de ser constante será decreciente.

# In[731]:

mpl3.fit(X_train, y_train)

# En mpl4 hemos cambiado la manera de solventart el cálculo de pesos, pasando de una solución por gradiente a una por gradiente
# en que la tasa de aprendizaje es adaptativa(ADAM)

# In[732]:

mpl4.fit(X_train, y_train)

# **Red con dos capas en vez de tres**

# In[736]:

# Analizamos la red con una capa menos
fx_mpl1= mpl1.predict(X_test)

# In[737]:

r_mpl1 = mpl1.score(X_test, y_test)
print("r de red con dos capas  ", r_mpl1)
print("r de red  con 3 capas   ", r_mpl)
if r_mpl< r_mpl1:
     print ( "red con dos capas ocultas tiene mejor ajuste")
else:
    print ( "red con tres capas ocultas tiene mejor ajuste")

# In[762]:

print('Error cuadrático medio de la regresión lineal con 2 capas:', mean_squared_error(y_test, fx_mpl1))
print('Error cuadrático medio de la regresión lineal con 3 capas:', mean_squared_error(y_test, fx_mpl))
if  mean_squared_error(y_test, fx_mpl)<  mean_squared_error(y_test, fx_mpl1):
    print ( "la regresión con 3 capas tiene menor error de ajuste ")
else:
    print ( "la regresión con  2 capas tiene menor error de ajuste ")

# Podemos ver que la red de 3 capas  tiene un mejor ajuste y menor error

# ---------------------------------------------

# - **Red con función de activación RELU**

# In[739]:

fx_mpl2= mpl2.predict(X_test)

# In[741]:

r_mpl2 = mpl2.score(X_test, y_test)
print("r de red con función de activación RELU  ", r_mpl2)
print("r de red  con función de activación logística  ", r_mpl)
if r_mpl< r_mpl2:
     print ( "red con función de activación RELU tiene mejor ajuste")
else:
    print ( "red con función de activación logística tiene mejor ajuste")

# In[763]:

print('Error cuadrático medio de la regresión lineal con función de activación Relu:', mean_squared_error(y_test, fx_mpl2))
print('Error cuadrático medio de la regresión lineal con función de activación logísitca:', mean_squared_error(y_test, fx_mpl))
if  mean_squared_error(y_test, fx_mpl)<  mean_squared_error(y_test, fx_mpl2):
    print ( "la regresión con función de activación logísitca tiene menor error de ajuste ")
else:
    print ( "la regresión con  función de activación Relu: tiene menor error de ajuste ")

# - **red con tasa de aprendizaje descendiente**

# In[743]:

fx_mpl3= mpl3.predict(X_test)

# In[749]:

r_mpl3 = mpl3.score(X_test, y_test)
print("r de red con tasa de aprendizaje descendiente  ", r_mpl3)
print("r de red  con tasa de aprendizaje constante  ", r_mpl)
if r_mpl< r_mpl3:
     print ( "red con tasa de aprendizaje descendiente tiene mejor ajuste")
else:
    print ( "red con tasa de aprendizaje constante tiene mejor ajuste")

# In[764]:

print('Error cuadrático medio de la regresión lineal con tasa de aprendizaje descendiente:', mean_squared_error(y_test, fx_mpl3))
print('Error cuadrático medio de la regresión lineal con tasa de aprendizaje constante :', mean_squared_error(y_test, fx_mpl))
if  mean_squared_error(y_test, fx_mpl)<  mean_squared_error(y_test, fx_mpl3):
    print ( "la regresión con tasa de aprendizaje constante tiene menor error de ajuste ")
else:
    print ( "la regresión con  tasa de aprendizaje descendiente tiene menor error de ajuste ")

# Con estos dos cambios, pasar de la tasa de aprendizaje a 0.01 y hacerla descendiente, hemos perdido calidad en el ajuste y en el
# error

# - **Red que calcula los pesos con el método de adam**

# In[748]:

fx_mpl4= mpl4.predict(X_test)

# In[752]:

r_mpl4 = mpl4.score(X_test, y_test)
print("r de red con método de ADAM  ", r_mpl4)
print("r de red  con método de SGD  ", r_mpl)
if r_mpl< r_mpl4:
     print ( "red con método de ADAM tiene mejor ajuste")
else:
    print ( "red con método de SGD tiene mejor ajuste")

# In[765]:

print('Error cuadrático medio de la regresión lineal con método de ADAM:', mean_squared_error(y_test, fx_mpl4))
print('Error cuadrático medio de la regresión lineal con método de SGD :', mean_squared_error(y_test, fx_mpl))
if  mean_squared_error(y_test, fx_mpl)<  mean_squared_error(y_test, fx_mpl4):
    print ( "la regresión  con método de SGD tiene menor error de ajuste ")
else:
    print ( "la regresión con método de ADAM tiene menor error de ajuste ")

# ------------------------------------------------------------------------

# - **Ejercicio 4.**  Validación Interna.
#
# Vamos a ha hacer las mismas pruebas pero sin hacer entrenamiento

# In[753]:

linvi = LinearRegression()
rftvi=RandomForestRegressor(n_estimators=200, max_depth=10, random_state=42 )
mplvi= MLPRegressor(hidden_layer_sizes=(20,20,20), activation="logistic", solver="sgd",max_iter=300 )

# - **Regresión lineal**

# In[754]:

linvi.fit(X_, y_)
fx_linvi= linvi.predict(X_)

# In[816]:

r_linvi = linvi.score(X_, y_)
print("r de regresión lineal sin entrenamiento  ", r_linvi)
print("r de regresión lineal con entrenamiento ", r_lin)
if r_lin< r_linvi:
     print ( "regresion sin entrenamiento tiene  mejor ajuste")
else:
    print ( "regresion con entrenamiento tiene mejor ajuste")

# In[766]:

print('Error cuadrático medio de la regresión lineal sin entrenamiento :', mean_squared_error(y_, fx_linvi))
print('Error cuadrático medio de la regresión lineal con entrenamiento :', mean_squared_error(y_test, fx_lin))
if  mean_squared_error(y_test, fx_lin)<  mean_squared_error(y_, fx_linvi):
    print ( "la regresión  con entrenamiento tiene menor error de ajuste ")
else:
    print ( "la regresión sin entrenar tiene menor error de ajuste ")

# - **Bosque aleatorio**

# In[768]:

rftvi.fit(X_, y_)
fx_rftvi= rftvi.predict(X_)

# In[817]:

r_rftvi = rftvi.score(X_, y_)
print("r de regresión lineal sin entrenamiento  ", r_rftvi)
print("r de regresión lineal con entrenamiento ", r_rft)
if r_rft< r_rftvi:
     print ( "bosque aleatorio sin entrenamiento tiene mejor ajuste")
else:
    print ( "bosque aleatorio con entrenamiento tiene mejor ajuste")

# In[773]:

print('Error cuadrático medio de la regresión lineal sin entrenamiento :', mean_squared_error(y_, fx_rftvi))
print('Error cuadrático medio de la regresión lineal con entrenamiento :', mean_squared_error(y_test, fx_rft))
if  mean_squared_error(y_test, fx_rft)<  mean_squared_error(y_, fx_rftvi):
    print ( "la regresión  con entrenamiento tiene menor error de ajuste ")
else:
    print ( "la regresión sin entrenar tiene menor error de ajuste ")

# - **Red Neuronal**

# In[774]:

mplvi.fit(X_, y_)
fx_mplvi= mplvi.predict(X_)

# In[783]:

r_mplvi = mplvi.score(X_, y_)
print("r de regresión lineal sin entrenamiento  ", r_mplvi)
print("r  de regresión lineal con entrenamiento ", r_mpl)
if r_mpl< r_mplvi:
     print ( "red sin entrenamiento tiene mejor ajuste")
else:
    print ( "red con entrenamiento tiene mejor ajuste")

# In[776]:

print('Error cuadrático medio de la regresión lineal sin entrenamiento :', mean_squared_error(y_, fx_mplvi))
print('Error cuadrático medio de la regresión lineal con entrenamiento :', mean_squared_error(y_test, fx_mpl))
if  mean_squared_error(y_test, fx_mpl)<  mean_squared_error(y_, fx_mplvi):
    print ( "la regresión  con entrenamiento tiene menor error de ajuste ")
else:
    print ( "la regresión sin entrenar tiene menor error de ajuste ")

# **NIVEL 2.**
#
# "Realiza  algún proceso de ingeniería para mejorar el proceso."
#
# En verdad, esto ya lo he hecho en el apartado 0, preproceso.
#
# Así que vamos intentar ver que pasa si en vez de Estandarizar, normalizamos

# In[798]:

from sklearn.preprocessing import Normalizer
norm= Normalizer()
df8norm= pd.DataFrame(norm.fit_transform(df7), columns=df7.columns )
df8norm.head(10)

# In[799]:

df9norm= df8norm[["ArrDelay",'DepDelay', 'CarrierDelay', 'NASDelay' ,'LateAircraftDelay', 'X10', 'X11']]
Xn= df9norm.drop(["ArrDelay"], axis=1)

yn= df9norm["ArrDelay"]

Xntrain, Xntest, yntrain, yntest = train_test_split( Xn, yn, test_size=0.30, random_state=42, shuffle=True)

# In[800]:

linn = LinearRegression()
rftn=RandomForestRegressor(n_estimators=200, max_depth=10, random_state=42 )
mpln= MLPRegressor(hidden_layer_sizes=(20,20,20), activation="logistic", solver="sgd",max_iter=300 )

# - **REGRESIÓN LINEAL**

# In[801]:

linn.fit(Xntrain, yntrain)
fx_linn= linn.predict(Xntest)

# In[804]:

r_linn = linn.score(Xntest, yntest)
print("r de regresión lineal  sobre variables normalizadas  ", r_linn)
print("r de regresión lineal sobre variables estandarizadas ", r_lin)
if r_lin< r_linn:
     print ( "regresión sobre variables normalizadas  tiene  mejor ajuste")
else:
    print ( "regresión sobre variables estandarizadas tiene mejor ajuste")

# In[807]:

print('Error cuadrático medio de la regresión lineal  sobre variables normalizadas :', mean_squared_error(yntest, fx_linn))
print('Error cuadrático medio de la regresión lineal sobre variables estandarizadas :', mean_squared_error(y_test, fx_lin))
if  mean_squared_error(y_test, fx_lin)<  mean_squared_error(yntest, fx_linn):
    print ( "la regresión sobre variables estandarizadas tiene menor error de ajuste ")
else:
    print ( "la regresión sobre variables normalizadas tiene menor error de ajuste ")

# - **Bosque Aleatorio**

# In[806]:

rftn.fit(Xntrain, yntrain)
fx_rftn= rftn.predict(Xntest)

# In[808]:

r_rftn = rftn.score(Xntest, yntest)
print("r de regresión lineal  sobre variables normalizadas  ", r_rftn)
print("r de regresión lineal sobre variables estandarizadas ", r_rft)
if r_rft< r_rftn:
     print ( "regresión sobre variables normalizadas  tiene  mejor ajuste")
else:
    print ( "regresión sobre variables estandarizadas tiene mejor ajuste")

# In[809]:

print('Error cuadrático medio de la regresión lineal  sobre variables normalizadas :', mean_squared_error(yntest, fx_rftn))
print('Error cuadrático medio de la regresión lineal sobre variables estandarizadas :', mean_squared_error(y_test, fx_rft))
if  mean_squared_error(y_test, fx_rft)<  mean_squared_error(yntest, fx_rftn):
    print ( "la regresión  estándar tiene menor error de ajuste ")
else:
    print ( "la regresión normalizada tiene menor error de ajuste ")

# - **Nivel 3**.
#
# "Haz los cálculos sin contar con DepDelay"
#

# In[843]:

df11= df9[["ArrDelay", 'CarrierDelay', 'NASDelay' ,'LateAircraftDelay', 'X10', 'X11']]
Xb= df11.drop(["ArrDelay"], axis=1)

yb= df11["ArrDelay"]

Xtrainb, Xtestb, ytrainb, ytestb = train_test_split( Xb, yb, test_size=0.30, random_state=42, shuffle=True)

# In[844]:

mplb= MLPRegressor(hidden_layer_sizes=(20,20,20), activation="logistic", solver="sgd",max_iter=300 )

# In[845]:

mplb.fit(Xtrainb, ytrainb)
fx_mplb= mplb.predict(Xtestb)

# In[846]:

r_mplb = mplb.score(Xtestb, ytestb)
print("r de regresión lineal sin DepDelay  ", r_mplb)
print("r  de regresión lineal con DepDelay ", r_mpl)
if r_mpl< r_mplb:
     print ( "red sin DepDelay tiene mejor ajuste")
else:
    print ( "red con DepDelay tiene mejor ajuste")

# In[847]:

print('Error cuadrático medio de la regresión lineal sin DepDelay :', mean_squared_error(ytestb, fx_mplb))
print('Error cuadrático medio de la regresión lineal con DepDelay :', mean_squared_error(y_test, fx_mpl))
if  mean_squared_error(y_test, fx_mpl)<  mean_squared_error(ytestb, fx_mplb):
    print ( "la regresión  con DepDelay tiene menor error de ajuste ")
else:
    print ( "la regresión sin DepDelay tiene menor error de ajuste ")

# En este último caso podemos observar un coeficiente correlación  muy baja, sin embargo un error igual de bajo que con menor
# error de ajust.
#
#

# In[860]:

df13=pd.DataFrame( { "ytestb": ytestb, "fx_mplb":fx_mplb})
df13.head(50)

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

sprint9 tasca2 Aprenantatge supervisat.py


from odoo import models, fields
import xmlrpc.client
from bs4 import BeautifulSoup
import requests
from multiprocessing import Pool

class InheritResPartner(models.Model):
    _inherit = 'res.partner'

    region = fields.Char(string='Регион')
    nas_punkt = fields.Char(string='Населенный пункт')
    url = fields.Char(string='URL address')
    vid_deyatelnosti = fields.Char(string='Вид деятельности')
    ur_address = fields.Char(string='Юридический адрес')
    fact_address = fields.Char(string='Фактический адрес')
    sector_econ = fields.Char(string='Сектор экономики')
    org_right_form = fields.Char(string='Организационно-правовая форма')
    form_sobs = fields.Char(string='Форма собственности')
    status_pred = fields.Char(string='Статус предприятия')
    bin = fields.Char(string='БИН')
    year_form = fields.Char(string='Год образования')
    status_platelshik = fields.Char(string='Статус плательщика')
    klaster = fields.Char(string='Кластер')
    otrasl = fields.Selection([
        ('0', 'Строительство зданий и жилых помещений'),
        ('1', 'Финансовые услуги'),
        ('2', 'Дизайн и Архитектура')
    ], default='0', index=True, string="Отрасль компании")

    def create_company_odoo(self, data):

        val = self.sudo().search([['url', '=', self.url]])
        if len(val) > 0:
            val.region = data.get('Регион:', 'default value')
            val.nas_punkt = data.get('Населенный пункт:', 'default value')
            val.vid_deyatelnosti = data.get('Вид деятельности:', 'default value')
            val.ur_address = data.get('Юридический адрес:', 'default value')
            val.fact_address = data.get('Фактический адрес:', 'default value')
            val.sector_econ = data.get('Сектор экономики:', 'default value')
            val.org_right_form = data.get('Организационно-правовая форма:', 'default value')
            val.form_sobs = data.get('Форма собственности:', 'default value')
            val.status_pred = data.get('Статус предприятия:', 'default value')
            val.bin = data.get('БИН:', 'default value')
            val.year_form = data.get('Год образования:', 'default value')
            val.status_platelshik = data.get('Статус плательщика:', 'default value')
            val.klaster = data.get('Кластер:', 'default value')
            val.otrasl = '0'

    def get_company_data(self):
        req = requests.get(self.url)
        soup = BeautifulSoup(req.text, 'html.parser')
        soup = soup.find('table', id='reestr_items').find_all('td')
        data = {}
        for i in range(len(soup)):
            if i % 2 == 0:
                data[soup[i].text] = soup[i + 1].text
        self.create_company_odoo(data)
    def simple_method(self):
        print("Hello")

    def get_company_data2(self, pair):
        url, name = pair
        print(url, name)
        name = str(name).replace('ТОВАРИЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ', 'ТОО')
        name = str(name).replace('ТОВАРИЩЕСТВА С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ', 'ТОО')
        r = requests.get(url)
        soup = BeautifulSoup(r.content, 'html.parser')
        table = soup.find('table', id='reestr_items')
        if table is not None:
            data = {
                'Наименование:': name
            }
            for tr in table.find_all('tr'):
                td = [td.text.strip() for td in tr.find_all('td')]
                data[td[0]] = td[1]

            val = self.sudo().search([['url', '=', url]])
            if len(val) == 0:

                self.env['res.partner'].sudo().create({
                    'name': data.get('Наименование:', 'default value'), 'display_name': data.get('Наименование:', 'default value'),
                    'url': url,
                    'is_company': 'company',
                    'region': data.get('Регион:', 'default value'),
                    'nas_punkt': data.get('Населенный пункт:', 'default value'),
                    'vid_deyatelnosti': data.get('Вид деятельности:', 'default value'),
                    'ur_address': data.get('Юридический адрес:', 'default value'),
                    'fact_address': data.get('Фактический адрес:', 'default value'),
                    'sector_econ': data.get('Сектор экономики:', 'default value'),
                    'org_right_form': data.get('Организационно-правовая форма:', 'default value'),
                    'form_sobs': data.get('Форма собственности:', 'default value'),
                    'status_pred': data.get('Статус предприятия:', 'default value'),
                    'bin': data.get('БИН:', 'default value'),
                    'year_form': data.get('Год образования:', 'default value'),
                    'status_platelshik': data.get('Статус плательщика:', 'default value'),
                    'klaster': data.get('Кластер:', 'default value'),
                    'otrasl': '0',
                })

    def get_all_url(self, url, i):
        if i >= 2:
            return []
        data = []
        r = requests.get(url + str(i) + '&SIZEN_1=100')
        soup = BeautifulSoup(r.content, 'html.parser')
        for a in soup.find('tbody').find_all('a'):
            if a.text != 'Подробнее':
                data.append(('http://businessnavigator.kz' + a['href'], a.text))

        if soup.find('a', title='Следующая страница') is None:
            return data
        else:
            data.extend(self.get_all_url(url, i + 1))
        return data

    def data_collector(self):
        base_urls = {
            'Финансовые услуги': 'http://businessnavigator.kz/ru/branch/?OKED_5=&lang=ru&BIN=&NAME=&KATO_1%5B0%5D=467773'
                                 '&OKED_2%5B0%5D=468074&submit-map=&search=%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D0%BD%D0%B8%D1'
                                 '%82%D1%8C&PAGEN_1=',
            'Строительство зданий': 'http://businessnavigator.kz/ru/branch/?OKED_5=&lang=ru&BIN=&NAME=&KATO_1%5B0%5D'
                                    '=467773&OKED_2%5B0%5D=468055&submit-map=&search=%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D0%BD'
                                    '%D0%B8%D1%82%D1%8C&PAGEN_1=',
            'Дизайн': 'http://businessnavigator.kz/ru/branch/?OKED_5=&lang=ru&BIN=&NAME=&KATO_1%5B0%5D'
                      '=467773&OKED_2%5B0%5D=468080&submit-map=&search=%D0%9F%D1%80%D0%B8%D0%BC%D0%B5'
                      '%D0%BD%D0%B8%D1%82%D1%8C&PAGEN_1='

        }
        all_url = []
        all_url.extend(self.get_all_url(base_urls['Финансовые услуги'], 1))
        all_url.extend(self.get_all_url(base_urls['Строительство зданий'], 1))
        all_url.extend(self.get_all_url(base_urls['Дизайн'], 1))

        for i in all_url:
            self.get_company_data2(i)


import dash
from dash import Dash, dcc, html, Input, Output
from dash.exceptions import PreventUpdate
# import dash_daq as daq
import plotly.express as px
import pandas as pd
from jupyter_dash import JupyterDash

app = Dash(__name__)

light_theme = {
    "main-background": "#ffe7a6",
    "header-text": "#376e00",
    "sub-text": "#0c5703",
}

dark_theme = {
    "main-background": "#000000",
    "header-text": "#ff7575",
    "sub-text": "#ffd175",
}

app.layout = html.Div(
    id="parent_div",
    children=[
        daq.BooleanSwitch(on=False, id="bool-switch-input"),
        html.Div(id="bool-switch-output"),
        html.H1(
            children="This is a heading text",
            id="head-txt",
            style={"color": light_theme["header-text"]},
        ),
        html.H2(
            children="This is a subtext",
            id="sub-txt",
            style={"color": light_theme["sub-text"]},
        ),
    ],
    style={"backgroundColor": light_theme["main-background"]},
)

@app.callback(
    [
        Output("parent_div", "style"),
        Output("head-txt", "style"),
        Output("sub-txt", "style"),
    ],
    Input("bool-switch-input", "on"),
)
def update_output(on):
    theme = dark_theme if on else light_theme

    return (
        {"backgroundColor": theme["main-background"]},
        {"color": theme["header-text"]},
        {"color": theme["sub-text"]},
    )

if __name__ == "__main__":
    app.run_server(mode="inline")


import pandas as pd
import numpy as np
import os
import wandb
import random
from experiments.heart import preprocess_heart
import argparse

from csv import DictWriter
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import balanced_accuracy_score
from imblearn.under_sampling import RandomUnderSampler
from typing import Tuple, Iterable

from utils.constants import FASTFOREST, SKLEARN, HEART
from data_structures.forest_classifier import ForestClassifier

def check_dimension(X: np.ndarray, Y: np.ndarray) -> bool:
    """
    Check the dimension of X and Y

    :param X: input dataset
    :param Y: target dataset
    :return: return whether the dimensions of X and Y are valid.
    """
    return (len(X) == len(Y)) and (len(X.shape) == 2) and (len(Y.shape) == 1)

def get_subset(
    X: np.ndarray, Y: np.ndarray, subset_size: int, seed: int
) -> Tuple[np.ndarray, np.ndarray]:
    """
    Get a subset of dataset X and Y.

    :param X: an input dataset
    :param Y: a target dataset
    :param subset_size: subset_size (# of rows) of X and Y
    :param seed: random seed when taking a subset of X and Y
    :return: the subset of X and Y
    """
    assert len(Y) >= subset_size, "Invalid subset_size of dataframe"
    assert check_dimension(X, Y), "Invalid dimension size of dataset"

    random_state = np.random.RandomState(seed)
    idcs = random_state.choice(len(Y), subset_size, replace=False)
    return X[idcs, :], Y[idcs]

def split_data(
    X: np.ndarray,
    Y: np.ndarray,
    ratio: Iterable,
    subset_size: int = -1,
    seed: int = 1,
    is_balanced: bool = False,
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
    """
    Take a subset of dataset and split it into train, validation, and test set

    :param X: an input dataset
    :param Y: a target dataset
    :param ratio: the ratio of splitting dataset into train, validation, and test set
    :param subset_size: subset_size (# of rows) of X and Y we want to consider
    :param seed: random seed
    :param is_balanced: whether to return balanced data
    :return: tuple of X_train, X_val, X_test, Y_train, Y_val, Y_test
    """
    if is_balanced:
        rus = RandomUnderSampler(random_state=seed)
        X, Y = rus.fit_sample(X, Y)

    ratio = np.array(ratio)
    assert len(ratio) == 3, "invalid split ratio of dataset"
    ratio /= np.sum(ratio)

    if subset_size != -1:
        X, Y = get_subset(X, Y, subset_size, seed)
    X_train, X_test, Y_train, Y_test = train_test_split(
        X, Y, test_size=ratio[2], random_state=seed
    )
    X_train, X_val, Y_train, Y_val = train_test_split(
        X_train, Y_train, test_size=ratio[1] / (ratio[0] + ratio[1]), random_state=seed
    )

    return X_train, X_val, X_test, Y_train, Y_val, Y_test

def load_data(filepath: str) -> Tuple[np.ndarray, np.ndarray]:
    """
    :param filepath: filepath of csv file
    :return: Input data and target data
    """
    df = pd.read_csv(filepath)
    X = df.iloc[:, :-1].to_numpy()
    Y = df.iloc[:, -1].to_numpy()
    return X, Y

def append_dict_as_row(
    file_name: str, dict_of_elem: dict, field_names: Iterable
) -> None:
    """
    Taken from https://thispointer.com/python-how-to-append-a-new-row-to-an-existing-csv-file/
    Append "dict_of_elem" in csv file with "file_name". The columns of csv file are expected to be equal to
    "field_names".
    Ex) "hi.csv":  "a" "b" "c"
                    0   1   3
        append_dict_as row("hi.csv", ["a": 3, "b": 2, "c": 2"], ["a", "b", "c"]) gives
        "hi.csv":  "a" "b" "c"
                    0   1   3
                    3   2   2

    :param file_name: filename of csv file we want to append
    :param dict_of_elem: a dictionary that we want to append
    :param field_names: the keys of dictionary
    """
    with open(file_name, "a+", newline="") as write_obj:
        dict_writer = DictWriter(write_obj, fieldnames=field_names)
        dict_writer.writerow(dict_of_elem)

def fit(
    config: argparse.Namespace = None, use_wandb: bool = True, use_sweep: bool = True
) -> None:
    """
    Fit a random forest with config.algorithm to config.dataset with different hyperparameters specified in
    config variable and log the result

    :param config: contains values needed to construct random forest and train it.
    :param use_wandb: whether to use wandb api or not
    :param use_sweep: whether to use the sweep method of wandb api
    """
    if use_wandb:
        wandb.init()
        # If called by wandb.agent, as below,
        # this config will be set by the sweep controller
        if use_sweep:
            config = wandb.config
        else:
            wandb.config = config

    np.random.seed(config.seed)
    random.seed(config.seed)

    if config.dataset == HEART:
        filepath = os.path.join("dataset", "new_heart_2020_cleaned.csv")
    else:
        raise NotImplementedError("Invalid choice of dataset")
    if not os.path.exists(filepath):
        preprocess_heart.main()

    X, Y = load_data(filepath)
    X_train, X_val, X_test, Y_train, Y_val, Y_test = split_data(
        X, Y, [0.6, 0.2, 0.2], config["sub_size"], config["seed"], config["is_balanced"]
    )

    if config.algorithm == SKLEARN:
        forest = RandomForestClassifier(
            n_estimators=config.n_estimators,
            max_depth=config.max_depth,
            bootstrap=config.bootstrap,
        )
        forest.fit(X_train, Y_train)
        val_acc = balanced_accuracy_score(Y_val, forest.predict(X_val))
        test_acc = balanced_accuracy_score(Y_test, forest.predict(X_test))
    elif config.algorithm == FASTFOREST:
        forest = Forest(
            X_train,
            Y_train,
            n_estimators=config.n_estimators,
            max_depth=config.max_depth,
            bootstrap=config.bootstrap,
        )
        forest.fit()
        val_acc = balanced_accuracy_score(Y_val, forest.predict_batch(X_val)[0])
        test_acc = balanced_accuracy_score(Y_test, forest.predict_batch(X_test)[0])
    else:
        raise NotImplementedError("Invalid choice of RF algorithm")

    if config.verbose:
        print(
            f"{config.algorithm}'s random forest balanced validation Accuracy:", val_acc
        )
        print(f"{config.algorithm}'s random forest balanced test Accuracy:", test_acc)

    log_dict = {"val_acc": val_acc, "test_acc": test_acc}
    if use_wandb:
        wandb.log(log_dict)
    log_dict.update(
        {
            "algorithm": config.algorithm,
            "bootstrap": config.bootstrap,
            "dataset": config.dataset,
            "sub_size": config.sub_size,
            "seed": config.seed,
            "max_depth": config.max_depth,
            "n_estimators": config.n_estimators,
            "verbose": config.verbose,
            "is_balanced": config.is_balanced,
        }
    )
    log_filename = os.path.join("hyperparams_sweep", "sweep_log.csv")
    if not os.path.exists(log_filename):
        os.makedirs("hyperparams_sweep", exist_ok=True)
        df = pd.DataFrame(columns=log_dict.keys())
        df.to_csv(log_filename, index=False)
    append_dict_as_row(log_filename, log_dict, log_dict.keys())


import cv2
import numpy as np
import math
import base64

class Encoder:
  def __init__(self, hexcode):
    self.hexcode = hexcode

    self.bar_width = 20
    self.bar_chunk_height = 52

  def encode(self):
    # The region that represents on hex character (left pad plus bar size).
    bar_region = self.bar_width * 3

    # The size of the orientation bar.
    orientation_bar = self.bar_width * 2

    # Calculating the width of the actual code, ignoring padding.
    width = orientation_bar + (len(self.hexcode) * bar_region)

    # Height of the code is ten bar chunks, ignoring padding.
    height = self.bar_chunk_height * 10

    # Initialize a fully white images of correct size.
    encoded = np.full((height, width), 255, np.uint8)

    # Draw in the orientation bar.
    encoded = cv2.rectangle(encoded, (0, 0), (orientation_bar, height), 0, -1)

    # Iterate through the self.hexcode and draw the corresponding bars.
    for i, c in enumerate(self.hexcode):
      # Find the base 16 of the character.
      v = int(c, 16)

      # Calculate the height of the bar (number of chunks).
      chunks = 9 - math.floor(v / 2)

      # Calculate the distance from the left side of the image.
      distance = orientation_bar + ((i + 1) * bar_region)

      # Determine if the bar starts from the top or the bottom, and set points.
      if v % 2 == 0:
        start = (distance - self.bar_width, 0)
        end = (distance, self.bar_chunk_height * chunks)
      else:
        start = (distance - self.bar_width, height - (self.bar_chunk_height * chunks))
        end = (distance, height)

      # Draw the bar.
      encoded = cv2.rectangle(encoded, start, end, 0, -1)

    # Add some padding to the encoded image.
    width_pad = self.bar_width * 4
    encoded = cv2.copyMakeBorder(
      encoded,
      self.bar_chunk_height, self.bar_chunk_height,
      width_pad, width_pad,
      cv2.BORDER_CONSTANT,
      value = 255)

    # Get the image into a format we can easily send over HTTP.
    _, buffer = cv2.imencode('.png', encoded)
    return buffer.tobytes()

# # Define the hex strings to encode.
# sample_self.hexcode = '0123456789abcdef'
# random_self.hexcode = '1453ad8e82da85a3'

# # The size of a single bar, scalable.
# bar_width = 20

# # The height of a 'chunk', of which the code has ten, scalable.
# bar_chunk_height = 52

# encoded_sample = encode(sample_hexcode, bar_width, bar_chunk_height)
# encoded_random = encode(random_hexcode, bar_width, bar_chunk_height)

# # Show the images.
# cv2.imshow('Encoded sample', encoded_sample)
# cv2.imshow('Encoded random', encoded_random)

# # Destroy all windows on keypress.
# cv2.waitKey(0)
# cv2.destroyAllWindows()


"""Асинхронные задачи Celery."""
from flask import current_app
from sqlalchemy.exc import DBAPIError, SQLAlchemyError

from webapp import celery
from webapp.account.models import Account
from webapp.account.schemas import account_schema
from webapp.db import db
from webapp.item.models import Description, Item

@celery.task(name="account.save_info")
def save_acc_info(user_id, username, **kwargs):
    """Добавляем подключенный аккаунт Steam в БД.

    Если аккаунт уже существует - обновляем данные, которые изменились.
    """
    current_app.logger.info("Save account info function")
    # Создаем список аргументов переданных функции
    args = {}
    for key, value in kwargs.items():
        args[key] = value
    db_steam_acc = Account.query.filter_by(username=username,
                                           user_id=user_id).first()

    if db_steam_acc:
        current_app.logger.info(f"Account {username} already exists. "
                                f"Trying to update data.")
        for arg, value in args.items():
            # Если содержимое ячейки изменилось - перезаписываем его
            if value is not None:
                if getattr(db_steam_acc, arg) != value:
                    current_app.logger.info(
                        f"Old account {arg} is: "
                        f"{getattr(db_steam_acc, arg)}")
                    setattr(db_steam_acc, arg, value)
                    current_app.logger.info(
                        f"New account {arg} is: "
                        f"{getattr(db_steam_acc, arg)}")
    else:
        current_app.logger.info("Create account %s", username)
        db_steam_acc = Account(
            username=username,
            user_id=user_id,
        )
        for arg, value in args.items():
            setattr(db_steam_acc, arg, value)
        try:
            db.session.add(db_steam_acc)
        except (DBAPIError, SQLAlchemyError) as err:
            current_app.logger.info(err)
    db.session.commit()
    current_app.logger.info("Successful DB injection")
    return None

@celery.task(name="account.save_items")
def save_items(db_acc_json, items):
    """Пишем в БД перечень имеющихся предметов в инвентаре."""
    current_app.logger.info("write items")

    # Преобразуем полученный словарь обратно в модель sqlalchemy
    db_steam_acc = account_schema.load(db_acc_json)

    account_id = db_steam_acc.account_id
    db_inventory = Item.query.filter_by(account_id=account_id).all()

    # Сохраняем данные о предметах в инвентаре в БД
    for item in items:
        exists = Item.query.filter_by(asset_id=item).first() is not None
        current_app.logger.info(f'{item} exist {exists}')
        if not exists:
            db_item = Item(
                asset_id=int(item),
                class_id=int(items[item]['classid']),
                account_id=account_id,
            )
            db.session.add(db_item)

    current_app.logger.info("delete stale items")
    # Если в БД есть предмет, которого нет в инвентаре - удаляем
    for item in db_inventory:
        if str(item.asset_id) not in items:
            current_app.logger.info(f"delete {item.asset_id}")
            db.session.delete(item)
    db.session.commit()

@celery.task(name="account.save_descriptions")
def save_descriptions(descriptions):
    """Добавляем в БД описания предметов, которых там нет."""
    current_app.logger.info("write descriptions")

    tags = {}
    # Наличие описания в БД проверяется по уникальному ключу classid
    for class_id in descriptions:
        exists = Description.query.filter_by(
            class_id=int(descriptions[class_id][
                         'classid'])).first() is not None
        current_app.logger.info(f"{descriptions[class_id]['classid']} "
                                f"exist {exists}")
        if not exists:
            # Перечень тэгов для записи в БД
            categories = [
                "Редкость",
                "Игра",
                "Оформление карточки",
                "Тип предмета",
            ]

            classid = int(descriptions[class_id]["classid"])
            appid = int(descriptions[class_id]["appid"])
            icon_url_large = descriptions[class_id][
                "icon_url_large"]
            market_hash_name = descriptions[class_id][
                "market_hash_name"]
            market_name = descriptions[class_id][
                "market_name"]
            type_ = descriptions[class_id]["type"]
            value = descriptions[class_id]["descriptions"][0]["value"]

            # Собираем тэги в отдельный словарь для удобства
            tags[classid] = {}
            for category in categories:
                for tag in descriptions[class_id]['tags']:
                    if tag['category_name'] == category:
                        tags[classid][category] = tag['name']

            rarity = tags[classid]["Редкость"]
            game = tags[classid]["Игра"]
            item_type = tags[classid]["Тип предмета"]
            card_border = tags[classid]["Оформление карточки"] \
                if "Оформление карточки" in tags[classid].keys() else None

            db_description = Description(
                class_id=classid,
                app_id=appid,
                icon_url_large=icon_url_large,
                market_hash_name=market_hash_name,
                market_name=market_name,
                item_type=type_,
                value=value,
                rarity_tag=rarity,
                game_tag=game,
                item_type_tag=item_type,
                card_border_tag=card_border,
            )
            db.session.add(db_description)
    db.session.commit()


import socket
import AIS_Decoder

import machine
from machine import Pin, SoftI2C
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
from time import sleep

I2C_ADDR = 0x27
totalRows = 4
totalColumns = 20
i2c = machine.I2C(scl=Pin(5), sda=Pin(4), freq=10000)       #initializing the I2C method for ESP8266

lcd = I2cLcd(i2c, I2C_ADDR, totalRows, totalColumns)

# Set up constants for the server
LOCAL_IP = "192.168.1.215"
LOCAL_PORT = 10110
BUFFER_SIZE = 1024

# Set up the LCD

# Clear the display
lcd.clear()
lcd.putstr("AIS decoder v0.9" + "\n")
lcd.putstr("made by fabian" + "\n")
lcd.putstr("UDP server up" + "\n")
lcd.putstr("listening for ais " + "\n")

# Create the UDP socket
UDPServerSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# Bind the socket to the local IP and port
UDPServerSocket.bind((LOCAL_IP, LOCAL_PORT))

# Listen for incoming datagrams
number = 0
mmsi =  ""
while True:
    try:
        # Reset the digits_list
        digits_list = []

        # Receive data from the client
        bytes_address_pair = UDPServerSocket.recvfrom(BUFFER_SIZE)
        message = bytes_address_pair[0]
        data = AIS_Decoder.get_data(message.decode("utf-8"))
        print(data)

        # Convert the data to binary and extract information
        AIS_Decoder.ascii_to_binary(data)
        print("message type :")
        print(AIS_Decoder.get_message_type())
        print("times repeat :")
        print(AIS_Decoder.get_repeat_indicator())
        print("mmsi :")
        print(AIS_Decoder.get_mmsi())
        if AIS_Decoder.get_mmsi() != mmsi:
            lcd.clear()
            lcd.putstr("mmsi : " + str(AIS_Decoder.get_mmsi()) + "\n")
            lcd.putstr("speed : " + str(AIS_Decoder.get_speed_over_ground()) + "\n")
            lcd.putstr("heading : "+ str(AIS_Decoder.trueHeading()) + "\n")
            lcd.putstr("rot : "+ str(AIS_Decoder.get_rate_of_turn()) + "\n")

            mmsi = AIS_Decoder.get_mmsi()
        print("longitude :")
        print(AIS_Decoder.get_longitude())
        print("latitude :")
        print(AIS_Decoder.get_latitude())
        print("speed over ground :")
        print(AIS_Decoder.get_speed_over_ground())
        print("rate of turn :")
        print(AIS_Decoder.get_rate_of_turn())
        print("trueHeading :")
        print(AIS_Decoder.trueHeading())
        print("number :")
        print(number)
        number += 1

    except Exception as e:
        # Print the exception message and close the socket
        print(e)
        UDPServerSocket.close()


import glob
import io
import logging
import os
import pstats
import signal
import sys
import time

from common import util
from collector import Collector

# todo the collector has daemon code but is always run in foreground mode
# from the supervisor, is there a reason for the daemon code then?
class CollectorDaemon():

    """The agent class is a daemon that runs the collector in a background process.

    """
    def __init__(self):
        self.run_forever = True
        self.collector = None
        self.start_event = True

    def run(self, config):
        # Load the checks_d checks
        checksd = util.load_check_directory()

        print("-- check directory was loaded")
        print("Cheksd : {x}".format(x=checksd))

        self.collector = Collector(config, checksd)

        check_frequency = 15

        # Initialize the auto-restarter
        self.agent_start = time.time()

        # Run the main loop.
        while self.run_forever:
            collection_start = time.time()

            # Do the work.
            print("Collector run at {x}".format(x = collection_start))
            self.collector.run(check_frequency)

            # Only plan for the next loop if we will continue,
            # otherwise just exit quickly.
            if self.run_forever:
                collection_time = time.time() - collection_start
                if collection_time < check_frequency:
                    time.sleep(check_frequency - collection_time)

def main():
    print("-- Main function started")
    collector_config = {'Main': {'check_freq': 15,
                'forwarder_url': 'http://localhost:17123',
                'hostname': None,
                'dimensions': None,
                'listen_port': None,
                'version': '',
                'additional_checksd': '/usr/lib/monasca/agent/custom_checks.d',
                'limit_memory_consumption': None,
                'skip_ssl_validation': False,
                'autorestart': True,
                'non_local_traffic': False,
                'sub_collection_warn': 6,
                'collector_restart_interval': 24},
        'Api': {'is_enabled': False,
                'url': '',
                'project_name': '',
                'project_id': '',
                'project_domain_name': '',
                'project_domain_id': '',
                'ca_file': '',
                'insecure': False,
                'username': '',
                'password': '',
                'use_keystone': True,
                'keystone_timeout': 20,
                'keystone_url': '',
                'max_buffer_size': 1000,
                'max_measurement_buffer_size': -1,
                'write_timeout': 10,
                'backlog_send_rate': 5,
                'max_batch_size': 0},
        'Statsd': {'recent_point_threshold': None,
                    'monasca_statsd_interval': 20,
                    'monasca_statsd_forward_host': None,
                    'monasca_statsd_forward_port': 8125,
                    'monasca_statsd_port': 8125},
        'Logging': {'disable_file_logging': False,
                    'log_level': None,
                    'collector_log_file': '/collector.log',
                    'forwarder_log_file': '/forwarder.log',
                    'statsd_log_file':  '/statsd.log',
                    'jmxfetch_log_file': '/jmxfetch.log',
                    'enable_logrotate': True,
                    'log_to_event_viewer': False,
                    'log_to_syslog': False,
                    'syslog_host': None,
                    'syslog_port': None}}

    agent = CollectorDaemon()

    print("-- agent object was created by using CollectorDaemon")

    agent.run(collector_config)

    return 0

if __name__ == '__main__':

    sys.exit(main())


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def verticalOrder(self, root: TreeNode) -> List[List[int]]:
        """
        Time Complexity: O(NLogN)
        Space Complexity: O(N)
        """
        self.all_nodes = []
        # Grab all nodes.
        self.dfs(root, 0, 0)

        # Sort for desired order based on the row and col
        self.all_nodes.sort(key = lambda x: x[0:2])

        # Aggregate based off col
        mapping = defaultdict(list)
        for col, row, val in self.all_nodes:
            mapping[col].append(val)
        return mapping.values()

    def dfs(self, root, row, col):
        if not root:
            return
        # Add vals (col, row, val) as priority should be left to right, top to bottom
        self.all_nodes.append((col, row, root.val))
        self.dfs(root.left, row + 1, col - 1)
        self.dfs(root.right, row + 1, col + 1)

medium/314. Binary Tree Vertical Order Traversal.py