import numpy
import scipy.stats
import pandas

def compare_averages(filename):
    """
    Performs a t-test on two sets of baseball data (left-handed and right-handed hitters).

    You will be given a csv file that has three columns.  A player's
    name, handedness (L for lefthanded or R for righthanded) and their
    career batting average (called 'avg'). You can look at the csv
    file via the following link:
    https://www.dropbox.com/s/xcn0u2uxm8c4n6l/baseball_data.csv

    Write a function that will read that the csv file into a pandas data frame,
    and run Welch's t-test on the two cohorts defined by handedness.

    One cohort should be a data frame of right-handed batters. And the other
    cohort should be a data frame of left-handed batters.

    We have included the scipy.stats library to help you write
    or implement Welch's t-test:
    http://docs.scipy.org/doc/scipy/reference/stats.html

    With a significance level of 95%, if there is no difference
    between the two cohorts, return a tuple consisting of
    True, and then the tuple returned by scipy.stats.ttest.

    If there is a difference, return a tuple consisting of
    False, and then the tuple returned by scipy.stats.ttest.

    For example, the tuple that you return may look like:
    (True, (9.93570222, 0.000023))
    """
    baseball_data = pandas.read_csv(filename)
    baseball_data_left = baseball_data[baseball_data['handedness']=='L']
    baseball_data_right = baseball_data[baseball_data['handedness']=='R']
    handedness_test=scipy.stats.ttest_ind(baseball_data_left['avg'], baseball_data_right['avg'], equal_var=False)
    return (handedness_test[1]>0.05, handedness_test)

    """
    Official answer for returning the correct values:

    if handedness_test[1] <= 0.05:
        return (False, handedness_test)
    else:
        return (True, handedness_test)
    """

if __name__ == '__main__':
    filename = "baseball_data.csv"
    result = compare_averages(filename)
    print result


#Problem sheet 1

print 'Problem Sheet 1'

from gaussElimin import *
import numpy as np
from scipy import linalg

print 'Q1a'
#4v1-v2-v3-v4=v+
#-v1+3v2+0v3-v4=0
#-v1+0v2+3v3-v4=v+
#-v1-v2-v3+4v4=0
print '4v1-v2-v3-v4=v+'
print '-v1+3v2+0v3-v4=0'
print '-v1+0v2+3v3-v4=v+'
print '-v1-v2-v3+4v4=0'

print 'Q1b'
x=np.array([[4.0,-1.0,-1.0,-1.0],[-1.0,3.0,0.0,-1.0],[-1.0,0.0,3.0,-1.0],[-1.0,-1.0,-1.0,4.0]], dtype = float)
print x
y=np.array([[5.0],[0.0],[5.0],[0.0]], dtype = float) #creates a matrix
print y

z=gaussElimin(x,y)
print z

print 'Q1c - Using LuDecomposition of our matrix'

from LUdecomp import *

P,L,U=linalg.lu(x) #in this case P is just an identitiy matrix because its just 1

print 'The original matrix'
print (x)
print ''
print 'The L matrix'
print (L)
print ''
print 'The U matrix'
print (U)
print ''

print 'Q1D'

x1=np.array([[5.0],[0.0],[5.0],[0.0]]) #vector b when vo is 0
x2=np.array([[5.0],[1.0],[5.0],[1.0]]) #vector b when v0 is now 1

print 'original vector b when v0=0'
print x1
print "Below are the vectors b where instead of V=0 V0=1:"
print x2

x=np.array([[4.0,-1.0,-1.0,-1.0],[-1.0,3.0,0.0,-1.0],[-1.0,0.0,3.0,-1.0],[-1.0,-1.0,-1.0,4.0]])

P,L,U=linalg.lu(x)
k=gaussElimin(L,x2)#solves Lz=b where b is new vector and L is from part c, which redefines b when you use gaussElimin solving as Ux=z it puts in your new b in this case x2 and spits out your original answer
J=gaussElimin(U,k)
M=gaussElimin(L,x1)
N=gaussElimin(U,M)
print 'when v0=1'
print J #Solutions match
print 'When v0=0'
print M #Solutions match from before with part b


import numpy as np

# ステップ関数の実装
def step_function(x):
    return np.array(x > 0, dtype=np.int32)

#シグモイド関数の実装
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def sigmoid_grad(x):
    return (1.0 - sigmoid(x)) * sigmoid(x)

#ReLU関数の実装
def relu(x):
    return np.maximum(0, x)

#恒等関数(あくまでも例なので値を戻しているだけ)
def identity_function(x):
    return x

#この書き方ではオーバーフローの問題が出てくるので、このままでは利用できない
#def softmax(a):
#    exp_a = np.exp(a) #指数関数
#    sum_exp_a = np.sum(exp_a) #指数関数の和
#    y = exp_a / sum_exp_a
#
#    return y

#ソフトマックス関数
#※ソフトマックス関数はニューラルネットワークの学習時に使用するものであり、
#  推論(分類)時には省略するのが一般的
def softmax(x):
    #c = np.max(a)
    #exp_a = np.exp(a - c) #オーバーフロー対策
    #sum_exp_a = np.sum(exp_a)
    #y = exp_a / sum_exp_a
    #return y
    x = x - np.max(x, axis=-1, keepdims=True)   # オーバーフロー対策
    return np.exp(x) / np.sum(np.exp(x), axis=-1, keepdims=True)

#2乗和誤差
def sum_squareed_error(y, t):
    return 0.5 * np.sum((y - t)**2)

#交差エントロピー誤差(バッチ対応版)
def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    # 教師データがone-hot-vectorの場合、正解ラベルのインデックスに変換
    if t.size == y.size:
        t = t.argmax(axis=1)

    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size

#数値微分
def numerical_diff(f, x):
    h = 1e-4 #0.0001
    return (f(x + h) - f(x - h)) / (2 * h)

#2次関数(簡単な微分)
def function_1(x):
    return 0.01*x**2 + 0.1*x

#偏微分
def function_2(x):
    #return x[0]**2 + x[1]**2
    #または return np.sum(x**2)
    if x.ndim == 1:
        return np.sum(x**2)
    else:
        return np.sum(x**2, axis=1)

#勾配
def _numerical_gradient_no_batch(f, x):
    h = 1e-4 #0.0001
    grad = np.zeros_like(x) #Xと同じ形状の配列を生成

    for idx in range(x.size):
        tmp_val = x[idx]
        # f(x + h)の計算
        x[idx] = tmp_val + h
        fxh1 = f(x)

        # f(x - h)の計算
        x[idx] = tmp_val - h
        fxh2 = f(x)

        grad[idx] = (fxh1 - fxh2) / (2 * h)
        x[idx] = tmp_val #値を元に戻す

    return grad

def numerical_gradient(f, x):
    #if X.ndim == 1:
    #    return _numerical_gradient_no_batch(f, X)
    #else:
    #    grad = np.zeros_like(X)
    #
    #    for idx, x in enumerate(X):
    #        grad[idx] = _numerical_gradient_no_batch(f, x)
    #
    #    return grad
    h = 1e-4 # 0.0001
    grad = np.zeros_like(x)

    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
    while not it.finished:
        idx = it.multi_index
        tmp_val = x[idx]
        x[idx] = tmp_val + h
        fxh1 = f(x) # f(x+h)

        x[idx] = tmp_val - h
        fxh2 = f(x) # f(x-h)
        grad[idx] = (fxh1 - fxh2) / (2*h)

        x[idx] = tmp_val # 値を元に戻す
        it.iternext()

    return grad

#勾配降下法
# f : 最適化したい関数
# init_x : 初期値
# lr : learning rate
# step_num : 勾配法による繰り返しの数
def gradient_descent(f, init_x, lr=0.01, step_num=100):
    x = init_x
    x_history = []

    for i in range(step_num):
        x_history.append(x.copy())

        grad = numerical_gradient(f, x)
        x -= lr * grad

    return x, np.array(x_history)


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time     : 2018/10/31 17:03
# @Author   : Iydon
# @File     : 5.9.py

import numpy as np

def linspace(start, end, step=None):
    """
    Args:
        step: start:step:end
    """
    length = (end-start)/step
    return [start+i*step for i in range(int(length[0,0])+1)]

def runge_kutta(dy, dy0, start, end, step, order:int=2):
    """
    Runge-Kutta Methods of Order Two.
    """
    if order not in [1,2,3,4]:
        raise ValueError
    xs = linspace(start, end, step=step)
    ys = [dy0 for i in xs]
    for i in range(len(xs)-1):
        k1 = step * dy(xs[i],ys[i])
        if order<2:
            ys[i+1] = ys[i] + k1
        elif order<3:
            k2 = step * dy(xs[i]+step/2,ys[i]+k1/2)
            ys[i+1] = ys[i] + k2
        elif order<4:
            k2 = step * dy(xs[i]+step/2,ys[i]+k1/2)
            k3 = step * dy(xs[i]+step,ys[i]-k1+2*k2)
            ys[i+1] = ys[i] + (k1+4*k2+k3)/6
        elif order<5:
            k2 = step * dy(xs[i]+step/2,ys[i]+k1/2)
            k3 = step * dy(xs[i]+step/2,ys[i]+k2/2)
            k4 = step * dy(xs[i]+step,ys[i]+k3)
            ys[i+1] = ys[i] + (k1+2*k2+2*k3+k4)/6
    return ys

t1,t2 = lambda t: -(2*t*t+1)*np.exp(2*t), lambda t: (t*t+2*t-4)*np.exp(2*t)
dy    = lambda t,y: np.matrix([[t1(t[0,0])],[t2(t[1,0])]]) + np.matrix([[3,2],[4,1]])*y
dy0   = np.matrix([[1],[1]])
start = np.matrix([[0],[0]])
end   = np.matrix([[1],[1]])
step  = 0.2
result = runge_kutta(dy, dy0, start, end, step, order=4)
print(result)
u1 = lambda t: np.exp(5*t)/3-np.exp(-t)/3+np.exp(2*t)
u2 = lambda t: np.exp(5*t)/3+2*np.exp(-t)/3+t*t*np.exp(2*t)
t  = [0, 0.2, 0.4, 0.6, 0.8, 1]
print([u1(i) for i in t])
print([u2(i) for i in t])

t1,t2 = lambda t: np.cos(t)+4*np.sin(t), lambda t: -3*np.sin(t)
dy    = lambda t,y: np.matrix([[t1(t[0,0])],[t2(t[1,0])]]) + np.matrix([[-4,-2],[3,1]])*y
dy0   = np.matrix([[0],[-1]])
start = np.matrix([[0],[0]])
end   = np.matrix([[2],[2]])
step  = 0.1
result = runge_kutta(dy, dy0, start, end, step, order=4)
print(result)
u1 = lambda t: 2*np.exp(-t)-2*np.exp(-2*t)+np.sin(t)
u2 = lambda t: -3*np.exp(-t)+2*np.exp(-2*t)
t  = [i/10 for i in range(21)]
print([u1(i) for i in t])
print([u2(i) for i in t])


import numpy as np

# Helper function to calculate the sigmoid
def sigmoid(z):
    sig = 1 / (1 + np.exp(-z))

    return sig

# Helper function to initialize weights and bias with zero
def initialize_parameters(dimension):
    weights = np.zeros((dimension, 1))
    bias = 0

    return weights, bias

# Helper function to do a single forward pass
def forward_propagate(X, Y, weights, bias):
    # Get the number of training examples
    m = X.shape[1]

    # Calculate the z
    z = np.dot(weights.T, X) + bias

    # Calculate activation A using sigmoid activation
    A = sigmoid(z)

    # Calculate for the cost
    cost = (-1/m) * np.sum(Y * np.log(A) + (1 - Y) * np.log(1 - A))

    cost = np.squeeze(cost)

    return A, cost

# Helper function to do a single backward pass
def backward_propagate(X, Y, A):
    # Calculate for the derivatives
    m = X.shape[1]
    dz = A - Y
    dw = (1/m) * np.dot(X, dz.T)
    db = (1/m) * np.sum(dz)

    return dw, db

# Helper function to optimize weights and bias using gradient descent algorithm
def gradient_descent(X, Y, weights, bias, iterations, learning_rate, print_cost=False):
    costs = []

    for i in range(iterations):
        # Compute for cost and gradient using propagate
        A, cost = forward_propagate(X, Y, weights, bias)
        dw, db = backward_propagate(X, Y, A)

        # Update weights and bias parameters
        weights = weights - learning_rate * dw
        bias = bias - learning_rate * db

        # Record cost
        if i % 100 == 0:
            costs.append(cost)

        # Print the cost every 100 iterations
        if print_cost and i % 100 == 0:
            print ("Cost after iteration %i: %f" %(i, cost))

    return weights, bias, dw, db, costs

def predict(X, weights, bias):
    m = X.shape[1]
    Y_pred = np.zeros((1, m))

    A = sigmoid(np.dot(weights.T, X) + bias)

    for i in range(A.shape[1]):
        if A[0,i] <= 0.5:
            Y_pred[0,i] = 0
        else:
            Y_pred[0,i] = 1

    return Y_pred


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Jul  9 08:04:05 2021

@author: alessandro
"""

import numpy as np
import sympy as sym
from sympy.utilities.lambdify import lambdify
import matplotlib.pyplot as plt
from scipy.optimize import fsolve

x = sym.symbols('x')
fx = x - 2 * sym.sqrt(x - 1)
dfx = sym.diff(fx, x, 1)

f = lambdify(x, fx, np)
df = lambdify(x, dfx, np)

a = 1
b = 3
zero = 2

xx = np.linspace(a, b, 100)
y = f(xx)
d = df(xx)
plt.ylim((-1, 1))
plt.plot(xx, y)
plt.plot(xx, d)
plt.plot([zero, ], f(np.array([zero])), 'o')
plt.plot([zero, ], df(np.array([zero])), 'o')
plt.plot(xx, 0*xx)
plt.show()

# Serve newton di grado due poichè la derivata prima vale zero in alpha
# mentre la derivata seconda non si annulla

def newton(f, df, m, x0, tolx, tolf, nmax=2048):
    def delta(x): return f(x) / df(x) if abs(df(x)) > np.spacing(1) else print("Derivata nulla")
    def prossimax(x): return x - m * delta(x)

    x = prossimax(x0)
    fx = f(x)
    it, xk = 1, [x]
    while it < nmax and abs(fx) > tolf and abs(delta(x)) > tolx * abs(x):
        x = prossimax(x)
        xk.append(x)
        fx = f(x)
        it += 1

    return x, it, xk

alpha, it, xk = newton(f, df, 2, 3, 1e-12, 1e-12)
print(alpha)

# devo stabilire l'ordine di convergenza

def stimaordine(xk):
    k = len(xk) - 4
    n = np.log(np.abs(xk[k + 3] - xk[k + 2]) / np.abs(xk[k + 2] - xk[k + 1]))
    d = np.log(np.abs(xk[k + 2] - xk[k + 1]) / np.abs(xk[k + 1] - xk[k]))
    return n / d

ordine = stimaordine(xk)
print(f"L'ordine è {ordine}")

# stampo le iterate
plt.title("Iterazioni")
plt.semilogy(range(1, it + 1), xk, 'o')
plt.semilogy(range(1, it + 1), xk)

# provo a partire da x0 = 1
a = newton(f, df, 2, 1, 1e-12, 1e-12)
print(a)

import numpy,from scipy,import sympy,from sympy


r"""

Newton's method is a rather popular iterative root finding algorithm. Starting
at an initial guess :math:`x_0` it tries to find better and better
approximations of the root of a function :math:`f(x)`. For this it uses the
first derivative :math:`f'(x)` of the function. The process

.. math::

    x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)}

is repeated until a value :math:`f(x_n)` is reached that is within a predefined
tolerance to zero. For further information see the `Wikipedia`_ page.

The way it is supposed to work is as follows:

>>> def f(x):
...     return x**2 - 2
...
>>> def df_dx(x):
...     return 2*x
...
>>> newtons_method_1d(f, df_dx, x0=4, tol=1e-8)  # doctest:+SKIP
1.4142135623730951

Hence, implement a function following the given definition:

.. autofunction:: newtons_method_1d

Start by downloading the
:exercise:`exercise template </exercises/newtons_method_1d.py>` and
editing this file. You can run tests via

.. code-block:: console

    $ python newtons_method_1d.py test

to check whether you got a correct solution. You can also take a look at
:solution:`one possible solution </exercises/newtons_method_1d.py>`.

.. _Wikipedia: https://en.wikipedia.org/wiki/Newton's_method

"""

def newtons_method_1d(f, df_dx, x0, tol):
    """Return the root of `f` within `tol` by using Newton's method.

    Parameters
    ----------
    f : callable[[float], float]
        The function of which the root should be found.
    df_dx : callable[[float], float]
        The derivative of `f`.
    x_0 : float
        The initial guess for the algorithm.
    tol : float
        The tolerance of the method.

    Returns
    -------
    float
        The root of `f` within a tolerance of `tol`.

    """
    # begin solution
    x = x0
    while abs(f(x)) > tol:
        x -= f(x) / df_dx(x)
    return x
    # end solution

# -----------------------------------------------------------------------------
# In the following the tests for this exercise are given---do not modify them.
import sys
import pytest
from numpy.testing import assert_allclose

@pytest.mark.parametrize(
    ('f', 'df_dx', 'x0', 'tol', 'expected'),
    [
        (lambda x: x**2 - 2, lambda x: 2*x, 4, 1e-8, 2**(1/2)),
        (lambda x: x**2 - 2, lambda x: 2*x, -4, 1e-8, -2**(1/2)),
        (lambda x: x**3 - 5, lambda x: 3*x**2, 4, 1e-8, 5**(1/3))
    ])
def test_correct_result(f, df_dx, x0, tol, expected):
    assert_allclose(
        newtons_method_1d(f, df_dx, x0, tol),
        expected,
        rtol=0,
        atol=tol)

if __name__ == '__main__':
    if len(sys.argv) == 2 and sys.argv[-1] == 'test':
        pytest.main([__file__])


"""
 sum

The sum tool returns the sum of array elements over a given axis.

import numpy

my_array = numpy.array([ [1, 2], [3, 4] ])

print numpy.sum(my_array, axis = 0)         #Output : [4 6]
print numpy.sum(my_array, axis = 1)         #Output : [3 7]
print numpy.sum(my_array, axis = None)      #Output : 10
print numpy.sum(my_array)                   #Output : 10

By default, the axis value is None. Therefore, it performs a sum over all the dimensions of the input array.

prod

The prod tool returns the product of array elements over a given axis.

import numpy

my_array = numpy.array([ [1, 2], [3, 4] ])

print numpy.prod(my_array, axis = 0)            #Output : [3 8]
print numpy.prod(my_array, axis = 1)            #Output : [ 2 12]
print numpy.prod(my_array, axis = None)         #Output : 24
print numpy.prod(my_array)                      #Output : 24

By default, the axis value is None. Therefore, it performs the product over all the dimensions of the input array.

Task

You are given a 2-D array with dimensions
X.
Your task is to perform the tool over axis and then find the

of that result.

Input Format

The first line of input contains space separated values of
and .
The next lines contains

space separated integers.

Output Format

Compute the sum along axis

. Then, print the product of that sum.

Sample Input

2 2
1 2
3 4

Sample Output

24

Explanation

The sum along axis
= [ ]
The product of this sum =
"""

import numpy

N, M = map(int, input().split())
A = numpy.array([input().split() for _ in range(N)],int)
print(numpy.prod(numpy.sum(A, axis=0), axis=0))


import numpy as np

def mean_square_error(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate MSE loss

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    MSE of given predictions
    """
    squared_error = np.square(y_true-y_pred)
    mean2 = np.sum(squared_error)/y_true.shape[0]
    return mean2

def misclassification_error(y_true: np.ndarray, y_pred: np.ndarray, normalize: bool = True) -> float:
    """
    Calculate misclassification loss

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values
    normalize: bool, default = True
        Normalize by number of samples or not

    Returns
    -------
    Misclassification of given predictions
    """
    t = y_pred * y_true
    error_num = np.count_nonzero(t<0)
    if normalize:
      return float(error_num/y_true.shape[0])
    else:
        return error_num

def accuracy(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate accuracy of given predictions

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    Accuracy of given predictions
    """

    true_predictions = np.count_nonzero(y_pred == y_true)
    predictions = y_pred.shape[0]
    return float(true_predictions)/predictions

def cross_entropy(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate the cross entropy of given predictions

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    Cross entropy of given predictions
    """
    raise NotImplementedError()


import numpy as np
import matplotlib.pyplot as plt

def pca(x, varRetained = 0.95):
    ''' varRetained is the original data variance retained in the new dataset. New number of dimensions
     is computed based on the desired fraction of the original variance.
    '''
    n = x.shape[0]
    d = x.shape[1]
    sigma = 1.0/d*np.dot(x.T,x)
    U, S, V = np.linalg.svd(sigma, full_matrices=True)
    k = 0
    total_var = np.sum(S)
    var_cum_sums = np.array([np.sum(S[:i+1])/total_var*100 for i in range(d)])
    k = len(var_cum_sums[var_cum_sums<(varRetained*100)])
    U_reduced = U[:, : k]
    return np.dot(x, U_reduced), k

class FLDA:
    def fit(self, x, y):
        n = x.shape[0]
        x = np.concatenate([x, np.ones([n,1])], axis = 1)
        classes = set(y)
        n0= n1= 0
        for i in y:
            if(y==0):
                M0 += x[i]
                n0 += 1
            else:
                M1 += x[i]
                n1 += 1
        M0 = M0/n0
        M1 = M1/n1
        Sw = []
        for i in y:
            if(y==0):
                Sw += np.dot((x[i] - M0), (x[i] - M0).T)
            else:
                Sw += np.dot((x[i] - M1), (x[i] - M1).T)
        w = np.dot(np.linalg.inv(Sw), (M0- M1))
        return w
    def predict(self, x, w):
        h = np.dot(w, x)
        if(h>0):
            return 0
        else:
            return 1


# Author: Dimitrios Damopoulos
# MIT license (see LICENCE.txt in the top-level folder)

# TODO: documentation

import numpy as np

def sigmoid(z):
    """
    Computes the sigmoid function

    Args:
        z (np.ndarray): the values where the sigmoid should be calculated on

    Returns:
        An np.ndarray with the same shape as the input `z' with the values of
        sigmoid
    """
    sigm = 1. / (1. + np.exp(-z))
    return sigm

def cross_entropy(p_hat, p):
    """
    Computer the cross entropy between two distributions

    Args:
        p_hat (np.ndarray of shape m,): The "predicted" probability distribution
        p (np.ndarray of shape m,): The "true" probability distribution

    Returns:
        The cross-entropy between the two distributions
    """
    # get values which are very close to zero a bit higher, in order to avoid
    # NaNs in the computation of the logarithm later.
    eps = np.finfo(float).eps
    p_hat[p_hat < eps] = eps

    ce = - np.log(p_hat).T.dot(p)
    return ce

def cross_entropy_with_one_hot_vector(p_hat, p):
    """
    Same as math_utils.cross-entropy, but for a "true" probability distribution
    has arose for a binary random variable (i.e., a process that outputs True
    or False for every sample. It should output the same as
    math_utils.cross_entropy, but faster.

    Args:
        p_hat (np.ndarray of shape m,): The "predicted" probability distribution
        p (np.ndarray of shape m,): The "true" probability distribution. Its
            values are converted to binary before the computation of the
            cross-entropy, by just comparing them with 0: anything above zero is
            treated as have value "1" and the rest as having value "0"

    Returns:
        The cross-entropy between the two distributions
    """
    eps = np.finfo(float).eps
    p1 = p > 0
    p0 = np.logical_not(p1)
    part1 = np.log(p_hat[p1] + eps).sum()
    part0 = np.log(1. - p_hat[p0] + eps).sum()

    return -(part0 + part1)

def rmse(y_hat, y):
    """
    Returns the Root Mean Square error between two series of measurements
    """
    losses = y_hat - y
    se = losses.T.dot(losses)
    return np.sqrt(se / y.shape[0])

def gradient_of_rmse(y_hat, y, Xn):
    """
    Returns the gradient of the Root Mean Square error with respect to the
    parameters of the linear model that generated the prediction `y_hat'.
    Hence, y_hat should have been generated by a linear process of the form
    Xn.T.dot(theta)

    Args:

       y_hat (np.array of shape N,): The predictions of the linear model
       y (np.array of shape N,): The "ground-truth" values.

    Returns:
        The RMSE between y_hat and y
    """

    N = y.shape[0]
    assert N > 0, ('At least one sample is required in order to compute the '
                  'RMSE loss')

    losses = y - y_hat
    gradient = - 2 * Xn.T.dot(losses) / N

    return gradient


import numpy as np
import matplotlib.pyplot as plt

def f(x):
    """"Returns the function where you're looking for zero spots"""
    return np.sin(x)**2 + np.sin((x+1)**2)

class FindZeroSpot:
    def __init__(self, func, x1=0.8, x2=1.2, precision=1e-3):
        """
        :param func: defined function to examine
        :param x1: the beginning of the area under investigation
        :param x2: end of the area under investigation
        :param precision: precision of searching for zero place
        """
        N = 300
        self.x_min = -5
        self.x_max = 5
        self.precision = precision
        self.function = func
        self.interval_list = [[x1, x2, 0]]

        self.x_points = np.linspace(self.x_min, self.x_max, N)
        self.y_points = self.function(self.x_points)

    def steps(self, act_interval):
        f1 = self.function(act_interval[0])
        f2 = self.function(act_interval[1])
        x0 = (act_interval[0] * f2 - act_interval[1] * f1) / (f2 - f1)
        f0 = self.function(x0)

        if f0 * f1 > 0:
            return [x0, act_interval[1], x0]
        else:
            return [act_interval[0], x0, x0]

    def count(self):
        """
        counts the coordinates of the zero place
        :return:x coordinate, y coordinate
        """

        def new_interval(interval_list):
            return interval_list.append(self.steps(interval_list[-1]))

        def check_precision_condition(interval_list, precision):
            new_interval(interval_list)
            if abs(interval_list[-1][2] - interval_list[-2][2]) < precision:
                return False
            return True

        while check_precision_condition(self.interval_list, self.precision):
            pass

        x_result = self.interval_list[-1][2]
        y_result = self.function(x_result)
        print(self.interval_list)
        return x_result, y_result

    def figure(self, x_result, y_result):
        """
        draws a graph of functions, interval, point

        :param x_result: x coordinate of the result
        :param y_result: y coordinate of the result
        :return: null
        """
        fig = plt.figure()
        ax = fig.add_subplot(111)
        ax.plot(self.x_points, self.y_points, "-b")
        ax.plot([self.x_points[0], self.x_points[-1]], [0, 0], '-k')
        ax.plot([self.interval_list[0][0], self.interval_list[0][0]], [-0.5, 0.5], '-y')
        ax.plot([self.interval_list[0][1], self.interval_list[0][1]], [-0.5, 0.5], '-y')
        ax.plot(x_result, y_result, 'or')
        plt.show()

example = FindZeroSpot(f)
x, y = example.count()
print("coordinates of it \nx:{:5.2f} y:{:5.2f}".format(x, y))
example.figure(x, y)


#%% ================ Introduction: load packages ================
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

from featureNormalize import featureNormalize
from gradientDescentMulti import gradientDescentMulti
from normalEqn import normalEqn

#%% ================ Part 1: Feature Normalization ================

print('\n -------------------------- \n')
print('Loading data ...')

# Load Data
path = 'ex1data2.txt'
data = pd.read_csv(path, header=None, names=['HouseSize', 'NbOfBedrooms', 'Price'])
data.head()

# Résumé des données
data.describe()

# set X (training data) and y (target variable)
nbCol = data.shape[1]
X = data.iloc[:,0:nbCol-1]
y = data.iloc[:,nbCol-1:nbCol]

# convert from data frames to numpy arrays
X = np.array(X.values)
y = np.array(y.values)
m = X.shape[0]

# Print out some data points
print('\n -------------------------- \n')
print('First 10 examples from the dataset:')
print(np.column_stack( (X[:10], y[:10]) ))

# Scale features and set them to zero mean
print('\n -------------------------- \n')
print('Normalizing Features ...')

X, mu, sigma = featureNormalize(X)
print('[mu] [sigma]')
print(mu, sigma)

# Add intercept term to X
X = np.concatenate((np.ones((m, 1)), X), axis=1)

#%% ================ Part 2: Gradient Descent ================
#
# ====================== YOUR CODE HERE ======================
# Instructions: We have provided you with the following starter
#               code that runs gradient descent with a particular
#               learning rate (alpha).
#
#               Your task is to first make sure that your functions -
#               computeCost and gradientDescent already work with
#               this starter code and support multiple variables.
#
#               After that, try running gradient descent with
#               different values of alpha and see which one gives
#               you the best result.
#
#               Finally, you should complete the code at the end
#               to predict the price of a 1650 sq-ft, 3 br house.
#
#
# Hint: At prediction, make sure you do the same feature normalization.
#

print('\n -------------------------- \n')
print('Running gradient descent ...')

# Choose some alpha value
alpha = 0.01
num_iters = 400

# Init Theta and Run Gradient Descent
n = X.shape[1]
theta = np.zeros((n,1))
theta, cost_history, theta_history = gradientDescentMulti(X, y, theta, alpha, num_iters)

# Plot the convergence graph
fig = plt.figure()
ax = plt.gca()
ax.plot(np.arange(num_iters), cost_history, color="blue", linewidth=2.0, linestyle="-")
ax.grid()
ax.set_xlabel('iteration number')
ax.set_ylabel(r'Cost J($\theta$)')
ax.set_title('Error vs. Training Epoch (number of iters)')
fig.show()
plt.show()

# Display gradient descent's result
print('\n -------------------------- \n')
print('Theta computed from gradient descent: ')
print(theta)

# Estimate the price of a 1650 sq-ft, 3 br house
price = np.array([[1, 1650, 3 ]]).dot(theta)

print('\n -------------------------- \n')
print('Predicted price of a 1650 sq-ft, 3 br house')
print("(using gradient descent):\n $%f\n" % price)

#%% ================ Part 3: Normal Equations ================

# ====================== YOUR CODE HERE ======================
# Instructions: The following code computes the closed form
#               solution for linear regression using the normal
#               equations. You should complete the code in
#               normalEqn.py
#
#               After doing so, you should complete this code
#               to predict the price of a 1650 sq-ft, 3 br house.
#
print('\n -------------------------- \n')
print('Solving with normal equations...')

# Load Data
data = np.loadtxt('ex1data2.txt', delimiter=',')
path = 'ex1data2.txt'
data = pd.read_csv(path, header=None, names=['HouseSize', 'NbOfBedrooms', 'Price'])
data.head()

# set X (training data) and y (target variable)
nbCol = data.shape[1]
X = data.iloc[:,0:nbCol-1]
y = data.iloc[:,nbCol-1:nbCol]

# convert from data frames to numpy arrays
X = np.array(X.values)
y = np.array(y.values)
m = X.shape[0]

# Add intercept term to X
X = np.concatenate((np.ones((m, 1)), X), axis=1)

# Calculate the parameters from the normal equation
theta = normalEqn(X, y)

# Display normal equation's result
print('Theta computed from the normal equations:')
print(' %s \n' % theta)

# Estimate the price of a 1650 sq-ft, 3 br house
price = np.array([[1, 1650, 3 ]]).dot(theta)

print("Predicted price of a 1650 sq-ft, 3 br house ")
print('(using normal equations):\n $%f\n' % price)

# ============================================================


# Computational Solutions
## Introduction to Linear Programming

Computational environments provide organizations with the ability to implement solutions to complex time, in real time.

[Scikit Learn, Pulp, CPLEX, and Gurobi](https://medium.com/opex-analytics/optimization-modeling-in-python-pulp-gurobi-and-cplex-83a62129807a) are  Python packages which provide capabilities for Linear programming and optimization.

!pip install pulp

#Import some required packages.
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

## Product mix problem - Farmers Fields

Problem: How much of each brand to purchase to minimize total cost of fertilizer given following data?

Product resource requirements and unit profit:

Two brands of fertilizer available – Super-gro, Crop-quick.

Field requires at least 16 pounds of nitrogen and 24 pounds of phosphate.

Super-gro costs: `$6 per bag`

Crop-quick: `$3 per bag`

Decision Variables:

$x_{1}$ = number of bags of Super-gro

$x_{2}$ = number of bags of Crop-quick

Cost (Z) minimization

Z = 6$x_{1}$ + 3$x_{2}$

Nitrogen Constraint

2$x_{1}$ + 4$x_{2}$ >= 16

Phosphate Constraint Check

4$x_{1}$ + 3$x_{2}$ >= 24

Non-negativitiy Constraint

$x_{1}$ > 0

$x_{2}$ > 0

#Initialize the model as a minimization problem.
import pulp as pl
opt_model = pl.LpProblem("MIPModel", pl.LpMinimize)

#Set the variables. Notice this is where we put
# the "non-negativity" constraint
x1 =pl.LpVariable(cat=pl.LpInteger, lowBound=0, name="$x_{1}$")
x2 =pl.LpVariable(cat=pl.LpInteger, lowBound=0, name="$x_{2}$")

#Set the objective function
opt_model += 6 * x1 + 3 * x2

#Set the Constraints
opt_model += 2 * x1  + 4* x2  >= 16

opt_model += 4 * x1 + 3 * x2 >= 24

## Review Model

Now that we have created the model we can review it.

opt_model

## Markdown of output
If we copy the above text into a markdown cell you will see the implications of the varous models.

MIPModel:

MINIMIZE

6*$x_{1}$ + 3*$x_{2}$ + 0

SUBJECT TO

_C1: 2 $x_{1}$ + 4 $x_{2}$ >= 16

_C2: 4 $x_{1}$ + 3 $x_{2}$ >= 24

VARIABLES

0 <= $x_{1}$ Integer

0 <= $x_{2}$ Integer

## Solve

We now solve the system of equations with the solve command.

#Solve the program
opt_model.solve()

## Check the Status

Here are 5 status codes:
* **Not Solved**: Status prior to solving the problem.
* **Optimal**: An optimal solution has been found.
* **Infeasible**: There are no feasible solutions (e.g. if you set the constraints x <= 1 and x >=2).
* **Unbounded**: The constraints are not bounded, maximising the solution will tend towards infinity (e.g. if the only constraint was x >= 3).
* **Undefined**: The optimal solution may exist but may not have been found.

pl.LpStatus[opt_model.status]

for variable in opt_model.variables():
    print(variable.name," = ", variable.varValue)

## Hurray!
We got the same answer as we did before.

## Exercise

Solve the LP problem for Beaver Creek Pottery using the maximization model type (`pl.LpMaximize`).

### Product mix problem - Beaver Creek Pottery Company
How many bowls and mugs should be produced to maximize profits given labor and materials constraints?

Product resource requirements and unit profit:

Decision Variables:

$x_{1}$ = number of bowls to produce per day

$x_{2}$ = number of mugs to produce per day

Profit (Z)  Mazimization

Z = 40$x_{1}$ + 50$x_{2}$

Labor Constraint Check

1$x_{1}$ + 2$x_{2}$ <= 40

Clay (Physicial Resource) Constraint Check

4$x_{1}$ + 3$x_{2}$ <= 120

Negative Production Constaint Check

$x_{1}$ > 0

$x_{2}$ > 0

## Sensitivity Analysis

for name, c in opt_model.constraints.items():
    print (name, ":", c, "\t", c.pi, "\t\t", c.slack)


import numpy as np

def kmeans(puntos, k):

    """
    K-means algorithm:
    Input = A 2D matrix of coordinates we want to make a 2-means clustering.
    Output = A 2x2 matrix with the resulting means
    Process = Iteratively assign the coordinates to a certain mean. After all points are assigned, the clustering means are reestimated based on the
    points assigned to each of these means.
    """

    eps = 0 # Tolerance for the while

    # Initialization of variables, we initialize with data points
    centroides = puntos[np.random.choice(puntos.shape[0], size=k, replace=False), :] # Initial means
    new_centroides = np.zeros((centroides.shape))

    aux_matrix = np.zeros((puntos.shape[0], k+1)) # Auxiliary matrix for calulations

    dif_norm = 1

    while dif_norm > eps:

        for idx in range(puntos.shape[0]):
            aux_matrix[idx,0:k] = np.linalg.norm((puntos[idx,:]-centroides), ord=2, axis=1)

            if len(np.where(aux_matrix[idx,0:k]==np.min(aux_matrix[idx,0:k]))[0]) == 1:
                aux_matrix[idx, k] = np.where(aux_matrix[idx,0:k]==np.min(aux_matrix[idx,0:k]))[0]
            else:
                aux_matrix[idx, k] = np.where(aux_matrix[idx,0:k]==np.min(aux_matrix[idx,0:k]))[0][0]

        for clu in range(k):
            new_centroides[clu,:] = np.mean(puntos[aux_matrix[:,k]==clu], axis=0)

        dif_norm = np.linalg.norm((centroides-new_centroides), ord=1)
        centroides = new_centroides

    return centroides


import numpy as np
import math as ma

def _normalize(v):
    norm = np.linalg.norm(v)
    if norm == 0.0:
       return v
    return v / norm

def writhe(curve):
    '''
    Returns writhe of given closed parametric curve.

    Parameters
    ----------
    curve: np.array
        An ``N`` by 3 array describing locations of endpoints of ``N`` linear segments approximating the curve. All locations should be distinct.

    Returns
    -------
    float
        Value of writhe for closed curve comprised of linear segments given.

    Example
    -------
    >>> import numpy as np
    >>> curve = np.array([[-1,0,-1],[1,0,1],[0,-1,1],[0,1,1]])
    >>> pywrithe.writhe(curve)
    0.366

    '''
    segments = np.transpose(np.array([np.roll(curve,1,axis=0),curve]),(1,0,2)) # (segment,begin/end,coordinate) order
    n = len(segments)
    omegas = np.zeros((n,n))
    for i in range(n):
        for j in range(n):
            if i-j == 0 or i-j == 1 or i-j == -1 or i-j == n-1 or i-j == -n+1:
                omegas[i][j] = 0
            else:
                segment_a = segments[i]
                segment_b = segments[j]
                r13 = segment_a[0] - segment_b[0]
                r14 = segment_a[0] - segment_b[1]
                r23 = segment_a[1] - segment_b[0]
                r24 = segment_a[1] - segment_b[1]

                r34 = segment_b[0] - segment_b[1]
                r12 = segment_a[0] - segment_a[1]

                n1 = _normalize(np.cross(r13,r14))
                n2 = _normalize(np.cross(r14,r24))
                n3 = _normalize(np.cross(r24,r23))
                n4 = _normalize(np.cross(r23,r13))

                d1 = np.clip(np.dot(n1,n2),-1,1)
                d2 = np.clip(np.dot(n2,n3),-1,1)
                d3 = np.clip(np.dot(n3,n4),-1,1)
                d4 = np.clip(np.dot(n4,n1),-1,1)

                a1 = ma.asin(d1)
                a2 = ma.asin(d2)
                a3 = ma.asin(d3)
                a4 = ma.asin(d4)

                omega_star = (a1+a2+a3+a4)

                omega = omega_star * ma.copysign(1.0, np.dot( np.cross( r34, r12) , r13) )

                omegas[i][j] = omega

    #print(omegas)

    return (1.0 / (4.0 * ma.pi)) * np.sum(omegas)


import math
import numpy as np
def derivative(f):
    '''returns a function that is the derivative of f with respect to x'''
    def dfdx(x):
        epsilon = 1e-3
        df = f(x+epsilon) - f(x-epsilon)
        dx = 2*epsilon
        return df/dx
    return dfdx
def integrate(f,a,b):
    '''returns definite integral of f(x) with respect to x from a to b
    uses average of left, right, and trapezoidal riemann sum.
    might not work with vertical asymptotes'''
    epsilon = 1e-3
    samples = ( max(a,b)-min(a,b) ) / epsilon
    X = np.linspace(min(a,b),max(a,b),samples)
    left = 0
    for x in X[:-1]:
        left += f(x) * epsilon
    right = 0
    for x in X[1:]:
        right += f(x) * epsilon
    trap = 0
    for i in range(len(X)-1):
        trap += .5 * ( f(X[i]) + f(X[i+1]) ) * epsilon
    ans = (left+right+trap) / 3
    if b > a:
        return ans
    return -1 * ans
def firstOrderODE(dydx,xi,yi,xf):
    '''expects dydx(x,y) and (xi,yi) which is the initial condition
    example: firstOrderODE(f(x,y),2,1)
    uses euler approximation'''
    ic = (xi,yi)
    dx = .001
    X = []
    Y = []
    x = ic[0]
    y = ic[1]
    while x < xf and y < 1e99:
        dy = dydx(x,y)*dx
        x += dx
        y += dy
    return y
if __name__ == '__main__':
    #for testing
    def f(x,y):
        return x+y
    print(firstOrderODE(f,2,1,6))


# Exercise 6
# Verify that the CDF inversion formula for the generation of exponential random variates of average value equal
# to 2 actually generates exponential variates.
# 1. Extract Ntr exponential random variates with the same average value equal to 2 using through the CDF inversion method.
# 2. Draw a QQ-plot to compare your draws against the quantiles of the exponential distribution with the same average value.
# 3. What happens if, instead, you draw your QQ-plot against the quantiles of an exponential distribution with a different average value?
# And what if you increase (e.g., 2×, 4×, . . . ) the number of exponential draws? Discuss.

# import
import numpy as np
from matplotlib import pyplot as plt
from numpy import mean, min, max, median, quantile
from scipy.stats import binom, norm, t as student, expon, poisson, chi2
from math import sqrt, pow, floor, ceil, exp, log
from statsmodels.api import qqplot

Ntr = 10000
# use the inverted cdf: x = - ln(U) / mean
average = 2
lam = 1 / average  # lambda = 1/avarage
results = -np.log(np.random.rand(Ntr)) / lam
plt.hist(results, bins=20)

# draw qq plot
qqplot(results, dist=expon, scale=1 / lam, line='45')

# draw qq against different average values: 5 and 0.5
qqplot(results, dist=expon, scale=5, line='45')
qqplot(results, dist=expon, scale=0.5, line='45')

# try with more draws (x2, x4, x20)
Ntr_2 = Ntr * 2
results = -np.log(np.random.rand(Ntr_2)) / lam
qqplot(results, dist=expon, scale=1 / lam, line='45')

Ntr_4 = Ntr * 4
results = -np.log(np.random.rand(Ntr_4)) / lam
qqplot(results, dist=expon, scale=1 / lam, line='45')

Ntr_20 = Ntr * 20
results = -np.log(np.random.rand(Ntr_20)) / lam
qqplot(results, dist=expon, scale=1 / lam, line='45')

Ntr_1_100 = Ntr // 100
results = -np.log(np.random.rand(Ntr_1_100)) / lam
qqplot(results, dist=expon, scale=1 / lam, line='45')

plt.show()

import numpy,from numpy,from scipy,from statsmodels


import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from abc import ABC, abstractmethod # for later

def derive(y,t,N, beta, gamma):
    """The SIR model differential equations."""

    S, I, R = y
    dSdt = -beta * S * I / N
    dIdt = beta * S * I / N - gamma * I
    dRdt = gamma * I
    return dSdt, dIdt, dRdt

class SIR:

    def __init__(self, N=1000, I0=1, R0=0, beta=0.4, gamma=1./10, days=250):
        """Setup for the model.

        N:     Total population, N.
        I0,R0: Initial number of infected and recovered individuals.
        beta:  Contact rate, beta,
        gamma: Mean recovery rate,(in 1/days).
        t:     A grid of time points (in days)
        """

        self.N  = N
        self.I0 = I0
        self.R0 = R0
        self.S = 0
        self.I = 0
        self.R = 0
        self.beta = beta
        self.gamma = gamma
        self.t = np.linspace(0, days, days)

    def projection(self):
        """Expected change in the disease's distribution in the population. """

        S0 = self.N - self.I0 - self.R0 # Everyone else, S0, is susceptible to infection initially.
        # Initial conditions vector
        y0 = S0, self.I0, self.R0
        # Integrate the SIR equations over the time grid, t.
        ret = odeint(derive, y0, self.t, args=(self.N, self.beta, self.gamma))
        self.S, self.I, self.R = ret.T

    def plot_projection(self):
        """Plot the data on three separate curves for S(t), I(t) and R(t)"""

        fig = plt.figure(facecolor='w')
        ax = fig.add_subplot(111, facecolor='#dddddd', axisbelow=True)
        ax.plot(self.t, self.S/1000, 'b', alpha=0.5, lw=2, label='Susceptible')
        ax.plot(self.t, self.I/1000, 'r', alpha=0.5, lw=2, label='Infected')
        ax.plot(self.t, self.R/1000, 'g', alpha=0.5, lw=2, label='Recovered with immunity')
        ax.set_xlabel('Time /days')
        ax.set_ylabel('Number (1000s)')
        ax.set_ylim(0,1.2)
        ax.yaxis.set_tick_params(length=0)
        ax.xaxis.set_tick_params(length=0)
        ax.grid(b=True, which='major', c='w', lw=2, ls='-')
        legend = ax.legend()
        legend.get_frame().set_alpha(0.5)
        for spine in ('top', 'right', 'bottom', 'left'):
            ax.spines[spine].set_visible(False)
        plt.show()

class City(SIR):

    def __init__(self, name, position, area, air, port):
        super().__init__()
        self.name = name
        self.position = position
        self.area = area
        self.air = air
        self.port = port

    def get_name(self):
        return self.name

    def get_position(self):
        return self.position

    def __str__(self):
        return str(self.__dict__)


import numpy as np
from matplotlib import pyplot as plt
from scripts import plots
from tqdm import tqdm

def build_k_indices(num_row, k_fold, seed):
    """ build and seperate k random indices for k-fold """
    interval = int(num_row / k_fold)
    np.random.seed(seed)
    indices = np.random.permutation(num_row)
    k_indices = [indices[k * interval: (k + 1) * interval]
                 for k in range(k_fold)]
    return np.array(k_indices)

def cross_validation(y, tx, k_indices, k, model, kw_model, loss, kw_loss, lambda_):
    """ return the train and test losses for a given model """

    # indices for test.
    idx_te = k_indices[k]

    # indices for train.Convert also 1d array by merging N-1 folds.
    idx_tr = k_indices[np.arange(len(k_indices)) != k, :].flatten()

    # x data: train/test
    x_tr = tx[idx_tr, :]
    x_te = tx[idx_te, :]

    # y data: train/test
    y_tr = y[idx_tr]
    y_te = y[idx_te]

    # training ridge regression
    weights, _ = model(y_tr, x_tr, lambda_, **kw_model)

    # computing losses
    loss_tr = loss(y_tr, x_tr, weights, lambda_, **kw_loss)
    loss_te = loss(y_te, x_te, weights, lambda_, **kw_loss)

    return loss_tr, loss_te

def cross_validation_select(x, y, model, loss, kw_model = {}, kw_loss = {}, seed = 1, k_fold = 5, do_plot = True, do_tqdm = False, lambdas = None):
    """ run cross validation for a given model and loss using k folds """
    if type(lambdas) == type(None):
        lambdas = np.logspace(-6, 1, 10)

    # split data in k fold
    k_indices = build_k_indices(len(y), k_fold, seed)

    # define lists to store the loss of training data and test data
    loss_val_tr, loss_val_te = [], []
    loss_val = [loss_val_tr, loss_val_te]
    loss_val_all = [[], []]

    for lambda_ in tqdm(lambdas) if do_tqdm else lambdas:
        loss_val_ = [[], []]
        for k in range(k_fold):
            [loss_val_[i].append(x) for i, x in
             enumerate(cross_validation(y, x, k_indices, k, model, kw_model, loss, kw_loss, lambda_))]
        [loss_val[i].append(np.mean(x)) for (i, x) in enumerate(loss_val_)]
        [loss_val_all[i].append(x) for (i, x) in enumerate(loss_val_)]

    loss_val_all = np.array(loss_val_all)
    idx_min = np.argmin(loss_val_te)

    if do_plot:
        plots.cross_validation_visualization(lambdas, loss_val_tr, loss_val_te,
                                     all_data = [loss_val_all[0].T, loss_val_all[1].T])

    return idx_min, loss_val_all, lambdas


## Do prime factorization
import numpy as np

def isprime(p):
    """ returns boolean whether p > 1 is prime or not based on fermat test."""
    if p == 2 or p == 3:
        return True

    elif (p % 2 == 0) or (p % 3 == 0):
        return False

    else:
        # fermat test
        i = 0
        k = 8   # amount of randomly picked numbers at max
        a = 2   # always do the fermat test with base 2
        while i < k:
            if a**(p-1) % p == 1:   # fermat test successful
                i += 1
            else:                   # fermat test failed, hence no prime
                return False

            # randomly pick new base
            a = np.random.randint(2,p-1)

        return True

def prime_factors(N):
    """ returns the prime factors of a given number N. Divides iteratively by an increasing sequence of prime numbers. """
    i = 2
    factors = []

    if isprime(N):  # initial prime number test
        factors.append(N)
        return factors

    while True:
        while N/i % 1 == 0:
            factors.append(i)
            #print(i)
            N = int(N/i)
            if N == 1:
                return factors

            if isprime(N):  # checks whether the new N might be prime
                factors.append(N)
                return factors

        i += 1
        # to find the next prime number
        while isprime(i) == False:
            i += 1

def primelist(N):
    """ returns a list of the first N prime numbers. """

    v = [2] # first prime number
    i = 3   # start with prime 3

    # loop through all odd numbers and check whether they are prime based on isprime function
    while len(v) < N:
        if isprime(i):
            v.append(i)

        i += 2

    return v


## given probability of winning a best-of-three-set match and the assumption that sets are independent,
## output the probability of winning a best-of-five-set match

##One way to find the probability of winning an n-set match is to start with the probability of winning
##a single set.  If we have an estimated probability of winning a best-of-three, e.g. from betting odds,
##we need to work backwards to get the probability of winning a single set.
##
##If x is p(set win), the probability of winning a three-setter is:
##    x^2 + 2(x^2)(1-x)
##    x^2 is the p(winning in straight sets)
##    (x^2)(1-x) is the p(winning two sets and losing one)
##    and there are 2 permutations (LWW and WLW) that result in a three-set win
##
##Written another way, we have:
##    p(three-set-win) = -2x^3 + 3x^2
##    or: -2x^3 + 3x^2 - p(three-set-win) = 0
##
##The first line of the function solves the trinomial for the relevant root.
##The second line uses similar logic to generate the probability of winning a five-setter:
##    x^3 --- p(straight-set-win)
##    3(x^3)(1-x) --- p(four-set-win): three sets won, one set lost, three permutations
##    6(x^3)(1-x)(1-x) --- p(five-set-win): two sets lost, six permutations (4c2)

import numpy

def fiveodds(p3):
    p1 = numpy.roots([-2, 3, 0, -1*p3])[1]
    p5 = (p1**3)*(4 - 3*p1 + (6*(1-p1)*(1-p1)))
    return p5


import math

import numpy as np
import matplotlib.pyplot as plt

a = -5
b = 5
N = 9
step = (b - a) / N

def test_function1(x):
    return 4.0 ** x

def test_function2(x):
    return math.cos(x)

def get_chebyshev_nulls_points():
    return np.array([(a + b) / 2 + (b - a) * math.cos((2 * k + 1) * math.pi / (2 * N)) / 2 for k in range(N)])

def get_equally_distant_points():
    return np.array(np.arange(-step * (N // 2), step * (N // 2) + 1, step))

def calculate_separated_difference(x_array, y_array, i, j):
    return (y_array[j+1] - y_array[j]) / (x_array[i+j+1] - x_array[j])

def generate_template_polynomial():
    koef_template = "fx.$"
    bracket_template = "(x-x$)"
    polynomial = ""
    for i in range(N):
        polynomial += koef_template.replace("$", str(i))
        for j in range(i):
            polynomial += "*" + bracket_template.replace("$", str(j))
        if i < N-1:
            polynomial += " + "
    return polynomial

def newton_polynomial(x_points, y_points):
    polynomial = generate_template_polynomial()
    # print(polynomial)
    koef = [y_points[0]]
    prev_separated_differences = y_points
    for i in range(N-1):
        separated_differences = []
        for j in range(N-i-1):
            separated_differences.append(calculate_separated_difference(x_points, prev_separated_differences, i, j))
        koef.append(separated_differences[0])
        prev_separated_differences = separated_differences
    for i in range(N):
        polynomial = polynomial.replace(f"fx.{i}", str(koef[i]))
        polynomial = polynomial.replace(f"x{i}", str(x_points[i]))
    print(polynomial)
    return polynomial

if __name__ == "__main__":
    function = test_function2
    chebyshev_points = get_chebyshev_nulls_points()
    eq_d_points = get_equally_distant_points()
    chebyshev_values = np.array([function(x) for x in chebyshev_points])
    eq_d_values = np.array([function(x) for x in eq_d_points])

    chebyshev_poly = newton_polynomial(chebyshev_points, chebyshev_values)
    eq_d_poly = newton_polynomial(eq_d_points, eq_d_values)

    x_new = np.arange(a, b, 0.1)
    chebyshev_y = []
    eq_d_y = []
    for x in x_new:
        chebyshev_y.append(eval(chebyshev_poly))
        eq_d_y.append(eval(eq_d_poly))

    fig, axs = plt.subplots(1, figsize=(8, 8))
    axs.plot(x_new, eq_d_y, 'b', label='Equally distant')
    axs.plot(x_new, chebyshev_y, 'g', label='Chebyshev')
    axs.plot(x_new, np.array([function(x) for x in x_new]), 'r', label='Function')
    fig.suptitle('Newton Polynomials')
    plt.show()


# some useful Activation function used in Deep Learning Algorithms

# function 1 - Logistic Sigmoid

def logistic_sigmoid(x):
    sigma = 1/(1 + exp(-x))
    return sigma
#range - (0,1)

#function 2 - tanh function
# precisely can be denoted as g(Z) = tanh(Z)

def tanh(x):
    numerator = exp(x) - exp(-x)
    denominator = exp(x) + exp(x)
    result = numerator/denominator
    return result
# best suitable for symmeteric cases

# function 3 - ReLu

def relu(x):
    ReLu = max(0,x)
    return ReLu

#range - [0,x)
# also if x >= 0 derivative of ReLu will be 1 else it will be 0

#function - 4 leaky_ReLu

def leaky_relu(x):
    leaky_ReLu = max(0.01*x, x)
    return leaky_ReLu
# we can change multiplying factor in order to increase precision. Here it is 0.01 it can be taken as 0.0001
# leaky_ReLu helps to gather some values which got vanished to 0 instead it provides them some negligible values

#function - 5 Softplus

#this function is introduced to overcome faults of leaky_ReLu
#Also known as Smoothened or Softened function (presence of smooth curve instead of joint in Relu or Leaky ReLu)

import numpy as np
def softplus(x):
    sfplus = np.log(1 + exp(x))
    return sfplus

#some more relation bw derivates of Activation function or bw Activation functions are included in other file.


from numpy import mgrid, sum
import cv2

def moments2e(image):
  """
  This function calculates the raw, centered and normalized moments
  for any image passed as a numpy array.

  Further reading:
  https://en.wikipedia.org/wiki/Image_moment
  https://en.wikipedia.org/wiki/Central_moment
  https://en.wikipedia.org/wiki/Moment_(mathematics)
  https://en.wikipedia.org/wiki/Standardized_moment
  http://opencv.willowgarage.com/documentation/cpp/structural_analysis_and_shape_descriptors.html#cv-moments

  compare with:
  import cv2
  cv2.moments(image)

  """
  assert len(image.shape) == 2 # only for grayscale images
  x, y = mgrid[:image.shape[0],:image.shape[1]]
  moments = {}
  moments['mean_x'] = sum(x*image)/sum(image)
  moments['mean_y'] = sum(y*image)/sum(image)

  # raw or spatial moments
  moments['m00'] = sum(image)
  moments['m01'] = sum(x*image)
  moments['m10'] = sum(y*image)
  moments['m11'] = sum(y*x*image)
  moments['m02'] = sum(x**2*image)
  moments['m20'] = sum(y**2*image)
  moments['m12'] = sum(x*y**2*image)
  moments['m21'] = sum(x**2*y*image)
  moments['m03'] = sum(x**3*image)
  moments['m30'] = sum(y**3*image)

  # central moments
  # moments['mu01']= sum((y-moments['mean_y'])*image) # should be 0
  # moments['mu10']= sum((x-moments['mean_x'])*image) # should be 0
  moments['mu11'] = sum((x-moments['mean_x'])*(y-moments['mean_y'])*image)
  moments['mu02'] = sum((y-moments['mean_y'])**2*image) # variance
  moments['mu20'] = sum((x-moments['mean_x'])**2*image) # variance
  moments['mu12'] = sum((x-moments['mean_x'])*(y-moments['mean_y'])**2*image)
  moments['mu21'] = sum((x-moments['mean_x'])**2*(y-moments['mean_y'])*image)
  moments['mu03'] = sum((y-moments['mean_y'])**3*image)
  moments['mu30'] = sum((x-moments['mean_x'])**3*image)

  # opencv versions
  #moments['mu02'] = sum(image*(x-m01/m00)**2)
  #moments['mu02'] = sum(image*(x-y)**2)

  # wiki variations
  #moments['mu02'] = m20 - mean_y*m10
  #moments['mu20'] = m02 - mean_x*m01

  # central standardized or normalized or scale invariant moments
  moments['nu11'] = moments['mu11'] / sum(image)**(2/2+1)
  moments['nu12'] = moments['mu12'] / sum(image)**(3/2+1)
  moments['nu21'] = moments['mu21'] / sum(image)**(3/2+1)
  moments['nu20'] = moments['mu20'] / sum(image)**(2/2+1)
  moments['nu03'] = moments['mu03'] / sum(image)**(3/2+1) # skewness
  moments['nu30'] = moments['mu30'] / sum(image)**(3/2+1) # skewness
  return moments

im = cv2.imread("fudge.png", cv2.CV_LOAD_IMAGE_GRAYSCALE)
print moments2e(im)


import pandas as pd
import numpy as np
from datetime import datetime
from scipy import optimize
from scipy import integrate
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt

def SIR_model(SIR,beta,gamma,N0):
    '''Here's the simple SIR model
        S - susceptible population; I - infected population; R - recovered population
        beta - infection rate; gamma - recovery rate; N0 - Total population
        And then the overall condition is as below
        overall condition is that the sum of changes (differnces) sum up to 0
        dS+dI+dR=0
        S+I+R= N (constant size of population)

     Parameters are:
        SIR - numpy.ndarray; beta - float; gamma - float
    '''

    S,I,R = SIR
    dS_dt=-beta*S*I/N0
    dI_dt=beta*S*I/N0-gamma*I
    dR_dt=gamma*I
    return(dS_dt,dI_dt,dR_dt)

if __name__ == '__main__':
    pd_JH_data=pd.read_csv('data/processed/COVID_relational_confirmed.csv',sep=';',parse_dates=[0])
    pd_JH_data=pd_JH_data.sort_values('date',ascending=True).copy()


from sympy.abc import x
import sympy as sp
import numpy as np

def split(inte, n):
    """ Split the interval into n subintervals.

    Args:
        inte: list/ndarray, the interval to be splited
        n: int, the number of interpolation points

    Returns:
        t: ndarray, the split of the given interval
    """
    # endpoints of the interval
    a, b = inte
    # split
    t = np.linspace(a, b, n+1)
    return t

def second_order_difference(t, y):
    """ Calculate the second order difference.

    Args:
        t: ndarray, the list of the three independent variables
        y: ndarray, three values of the function at every t

    Returns:
        double: the second order difference of given points
    """
    # claculate the first order difference
    first_order_difference = (y[1:] - y[:-1]) / (t[1:] - t[:-1])
    return (first_order_difference[1] - first_order_difference[0]) / (t[2] - t[0])

def cubic_spline_interpolation(t, y, diff_list):
    """ Cubic spline interpoaltion with I boundary conditions.

    """
    # number of the points
    n = len(t)
    # calculate the steps
    h = t[1:] - t[:-1]

    # initialize
    D = np.zeros((n, n))
    d = np.zeros(n)
    # calculate the elements in matrix D
    for i in range(n):
        if i == 0:
            D[0, 0] = 2
            D[0, 1] = 1
        elif i == n-1:
            D[n-1, n-2] = 1
            D[n-1, n-1] = 2
        else:
            D[i, i-1] = h[i-1] / (h[i-1] + h[i]) # mu
            D[i, i] = 2
            D[i, i+1] = h[i] / (h[i-1] + h[i])   # lambda

    # calculate the elements in vector d
    for i in range(n):
        if i == 0:
            # repeat node difference quotient
            d[i] = 6 * ((y[1] - y[0])/(t[1] - t[0]) - diff_list[0]) / (t[1] - t[0])
        elif i == n-1:
            # repeat node difference quotient
            d[i] = 6 * (diff_list[1] - (y[n-1] - y[n-2])/(t[n-1] - t[n-2])) / (t[n-1] - t[n-2])
        else:
            d[i] = 6 * second_order_difference(t[i-1:i+2], y[i-1:i+2])

    # get M by solving the equation DM=d
    M = np.linalg.solve(D, d)

    # iteraton
    S = []
    for i in range(n-1):
        s = M[i] * (t[i+1] - x)**3 / 6 / h[i]
        s += M[i+1] * (x - t[i])**3 / 6 / h[i]
        s += (y[i] - M[i] * h[i]**2 / 6) * (t[i+1] - x) / h[i]
        s += (y[i+1] - M[i+1] * h[i]**2 / 6) * (x - t[i]) / h[i]
        S.append((sp.simplify(s), sp.And(x>=t[i], x<=t[i+1])))

    return sp.Piecewise(*S)

def f(x):
    return 1 / (1 + x**2)

def draw_cubic_spline_interpolation(inte, func, n_lst):
    """ Draw figure of the function's cubic spline interpolation for various endpoints.

    Args:
        inte: list/ndarray, the interpolation itnerval
        func: function object, the function to be interpolated
        n_lst: list/ndarray, list of the endpoints number
    """
    # draw the original function fugure
    fig = sp.plot(func(x), (x, -5, 5), line_color='r', label='Original Function', legend=True, show=False)
    # control color
    i = 0
    colors_lst = ['b', 'y', 'g']

    for n in n_lst:
        t = split(inte, n)
        y = cubic_spline_interpolation(t, func(t), [5/338, -5/338])
        # output
        print(f"The interpoaltion polinomial with n={n} is:")
        print(y)
        # draw
        color = colors_lst[i]
        i += 1
        p = sp.plot(y, (x, -5, 5), line_color=color, label=f'n={n}', legend=True, show=False)
        fig.extend(p)

    # save figure
    fig.save('cubic_spline_interpolation.png')

if __name__ == '__main__':
    inte = [-5, 5]
    n_lst = [5, 10, 20]

    draw_cubic_spline_interpolation(inte, f, n_lst)


def f_norm_scale(array_original):
    """
    Normalize numpy array between -1 and +1

    Developed by :   Sai G.S. Pai (ETH Singapore)
    Contact :        saiganesh89@gmail.com
    Date:            June 30, 2020

    INPUTS:
        array_original : original array to normalize

    OUTPUTS:
        array_norm : normalized array

    NOTE:
        Requires numpy

    """
    import numpy as np
    # initialize
    array_norm = np.zeros(shape=(array_original.shape[0], array_original.shape[1]))

    # normalize
    for feature in range(0, array_original.shape[1]):
        x_min = np.amin(array_original[:, feature])
        x_max = np.amax(array_original[:, feature])
        x_halfrange = (x_max - x_min) / 2
        x_midpoint = (x_max + x_min) / 2

        for idx in range(0, array_original.shape[0]):
            array_norm[idx, feature] = (array_original[idx, feature] - x_midpoint) / x_halfrange

    # return normalized array
    return array_norm


import numpy as np

words = np.array(
    ['the', 'be', 'to', 'of', 'and', 'a', 'in', 'that', 'have',
     'I', 'it', 'for', 'not', 'on', 'with', 'he', 'as', 'you',
     'do', 'at', 'this', 'but', 'his', 'by', 'from', 'they', 'we',
     'say', 'her', 'she', 'or', 'an', 'will', 'my', 'one', 'all',
     'would', 'there', 'their', 'what', 'so', 'up', 'out', 'if',
     'about', 'who', 'get', 'which', 'go', 'me', 'when', 'make',
     'can', 'like', 'time', 'no', 'just', 'him', 'know', 'take',
     'people', 'into', 'year', 'your', 'good', 'some', 'could',
     'them', 'see', 'other', 'than', 'then', 'now', 'look',
     'only', 'come', 'its', 'over', 'think', 'also', 'back',
     'after', 'use', 'two', 'how', 'our', 'work', 'first', 'well',
     'way', 'even', 'new', 'want', 'because', 'any', 'these',
     'give', 'day', 'most', 'us'])

print 'ndim', words.ndim
#(dim,) = words.shape
print 'shape', words.shape
print 'size', words.size
print 'dtype', words.dtype
print 'itemsize', words.itemsize
print 'data', words.data

a = np.arange(15)
print 'arange', a
ar = a.reshape(3,5)
print 'reshape', ar

ar = np.zeros( (7,8) )
ar[3][5] = 0.7
print 'zeros',ar

words = np.array(['aaa','bbb','ccc','ddd'])
ar = np.array([1,2,3,4])
print words[ar==1]

a = np.array([[4,9,2],[5,1,3]])
idx = np.argsort(a[1])
print "idx", idx
print idx[::-1]
print a[:,idx]
print '\n'

a = np.array([[1,2,3],[4,5,6]])
b = np.array([[7,8],[9,10],[11,12]])
#print np.dot(a, b)
#print np.outer(a,b)
#print np.mean(a)
#print a.mean(axis=0)
print b[[1,1,0]]

ar = np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]])
print '\nar', ar[:,-1:]
print 'repeat', np.repeat(ar[:, -1:], 5, axis=1)
print 'some cols', ar[:, 1:2]

print 'random test', np.random.random([5,3])

ar = np.array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
ind = np.argpartition(ar, -2)[:ar.shape[0]-2]
print ind
print ar[ind]
#print list(set(range(ar.shape[0])) - set([n for n in ind]))
#print np.argpartition(ar, -4)[:ar.shape[0]-4]
#print ar[ind]
#print ind[np.argsort(ar[ind])]
#print ar
#print ar[ind]
#ar[ind] = np.zeros(ind.shape[0])
#print ar

#ar = ar.reshape([ar.shape[0]/2, 2])
#print ar
#ind = np.argpartition(ar, -2, axis=1)
#print ind

#print ar.reshape(ar.shape[0]*ar.shape[1])


# one stock -> simple return is common but not for many
# $$
# \frac{P_1 - P_0}{P_0} = \frac{P_1}{P_0} - 1
# $$
import numpy as np
import pandas as pd
from pandas_datareader import data as wb
import matplotlib.pyplot as plt
'''from AssetTypes.BaseAsset import BaseAsset
from AssetTypes.EquityShare import EquityShare
from AssetTypes.GovernmentBond import GovernmentBond'''
PG = wb.DataReader('PG', data_source='yahoo', start='1995-1-1')
# with iex key`
# PG = wb.DataReader('PG', data_source='iex', start='2015-1-1')
# csv
# PG = pd.read_csv('Section-11_PG_1995-03_23_2017.csv')
# PG = PG.set_index('Date')
# calculate simple return
PG['simple_return'] = (PG['Adj Close'] / PG['Adj Close'].shift(1)) - 1
print(PG['simple_return'])
# plot simple return
PG['simple_return'].plot(figsize=(8, 5))
# plt.show()
# Calculate the simple average daily return.
avg_returns_d = PG['simple_return'].mean()
# Estimate the simple average annual return.
avg_returns_a = PG['simple_return'].mean() * 250
# Print the simple percentage version of the result as a float with 2 digits after the decimal point.
print (str(round(avg_returns_a, 5) * 100) + ' %')
# calculate log return
PG['log_return'] = np.log(PG['Adj Close'] / PG['Adj Close'].shift(1))
print (PG['log_return'])
# plot log return
PG['log_return'].plot(figsize=(8, 5))
# plt.show()
# Calculate the log average daily return.
avg_returns_d = PG['log_return'].mean()
# Estimate the log average annual return.
avg_returns_a = PG['log_return'].mean() * 250
# Print the log percentage version of the result as a float with 2 digits after the decimal point.
print (str(round(avg_returns_a, 5) * 100) + ' %')
#
import quandl
#
mydata_01 = quandl.get("FRED/GDP")
mydata_01.tail()
mydata_01.head()
mydata_01.to_csv('Section-10_57-ImportingandOrganizingYourDatainPython-PartIII-Data_01.csv')
mydata_01 = pd.read_csv('Section-10_57-ImportingandOrganizingYourDatainPython-PartIII-Data_01.csv', index_col='Date')
mydata_01.tail()
mydata_01 = pd.read_csv('Section-10_57-ImportingandOrganizingYourDatainPython-PartIII-Data_01.csv')
mydata_01.tail()
mydata_01.set_index('Date')
mydata_01.tail()
mydata_02 = pd.read_csv('Section-10_57-ImportingandOrganizingYourDatainPython-PartIII-Data_02.csv', index_col='Date')
mydata_02.head()
mydata_02.tail()
mydata_02.to_excel('Section-10_57-ImportingandOrganizingYourDatainPython-PartIII-Data_02.xlsx')
mydata_02.info()
mydata_03 = pd.read_excel('Section-10_57-ImportingandOrganizingYourDatainPython-PartIII-Data_03.xlsx')
mydata_03.info()
mydata_03.set_index('Year')
mydata_03.info()
########## Return of Indices
import numpy as np
import pandas as pd
from pandas_datareader import data as wb
import matplotlib.pyplot as plt
tickers = ['^DJI', '^GSPC', '^IXIC', '^GDAXI']
ind_data = pd.DataFrame()
for t in tickers:
    ind_data[t] = wb.DataReader(t, data_source='yahoo', start='2000-1-1')['Adj Close']
ind_data.head()
ind_data.tail()
# Normalize the data to 100 and plot the results on a graph.
(ind_data / ind_data.iloc[0] * 100).plot(figsize=(15, 6));
plt.show()
# How would you explain the common and the different parts of the behavior of the three indices?
# Obtain the simple returns of the indices.
ind_returns = (ind_data / ind_data.shift(1)) - 1
ind_returns.tail()
# Estimate the average annual return of each index.
annual_ind_returns = ind_returns.mean() * 250
annual_ind_returns
##########
'''baseAsset: BaseAsset = EquityShare('PG')
print(baseAsset.ShortType)
print(baseAsset.AssetType)
print(baseAsset.AssetName)
print(baseAsset.getSimpleReturn(PG))'''
tickers = ['PG', 'MSFT', 'F', 'GE']
yahoo_df = pd.DataFrame()
iex_df = pd.DataFrame()
for t in tickers:
    yahoo_df[t] = wb.DataReader(t, data_source='yahoo', start='1995-1-1')['Adj Close']
    # iex_df[t] = wb.DataReader(t, data_source='iex', start='2002-1-1')['Close']
yahoo_df = pd.read_csv('Section-12_PG_BEI.DE_2007_2017.csv', index_col='Date')
yahoo_df.tail()
yahoo_df.head()
# newDataFrame.to_csv('Section-10_57-ImportingandOrganizingYourDatainPython-PartIII-example_01.csv')
# newDataFrame.to_excel('Section-10_57-ImportingandOrganizingYourDatainPython-PartIII-example_01.xlsx')'''
yahoo_df.iloc[0]
(yahoo_df / yahoo_df.iloc[0] * 100).plot(figsize = (15, 6));
yahoo_df.plot(figsize=(15,6))
yahoo_df.loc['2007-01-03']
yahoo_df.iloc[0]
## Calculating the Return of a Portfolio of Securities
simple_returns = (yahoo_df / yahoo_df.shift(1)) - 1
simple_returns.head()
weights = np.array([0.5, 0.5])
np.dot(simple_returns, weights)
simple_returns_anual = simple_returns.mean() * 250
simple_returns_anual
np.dot(simple_returns_anual, weights)
pfolio_1 = str(round(np.dot(simple_returns_anual, weights), 5) * 100) + ' %'
print (pfolio_1)
weights_2 = np.array([0.75, 0.25])
pfolio_2 = str(round(np.dot(simple_returns_anual, weights_2), 5) * 100) + ' %'
print (pfolio_2)
## Calculating the Risk of a Portfolio of Securities Section-11_MSFT_2000_2017.csv
log_returns = np.log(yahoo_df / yahoo_df.shift(1))
log_returns.head()
# MSFT
log_returns['PG'].mean()
# Annual risk: covariance
log_returns['PG'].mean()*250
# Daily risk:
log_returns['PG'].std()
# Annual risk: covariance
log_returns['PG'].std() * 250 ** 0.5
# PG
log_returns['BEI.DE'].mean()
# Annual risk: covariance
log_returns['BEI.DE'].mean()*250
# Daily risk:
log_returns['BEI.DE'].std()
# Annual risk: covariance
log_returns['BEI.DE'].std() * 250 ** 0.5
# Repeat the process we went through in the lecture for these two stocks. How would you explain the difference between their means and their standard deviations?
log_returns[['PG', 'BEI.DE']].mean() * 250
# Store the volatilities of the two stocks in an array called "vols".
volatilities = log_returns[['PG', 'BEI.DE']].std() * 250 ** 0.5
volatilities
# ## Covariance and Correlation on returns
# \begin{eqnarray*}
# Covariance Matrix: \  \
# \Sigma = \begin{bmatrix}
#         \sigma_{1}^2 \ \sigma_{12} \ \dots \ \sigma_{1I} \\
#         \sigma_{21} \ \sigma_{2}^2 \ \dots \ \sigma_{2I} \\
#         \vdots \ \vdots \ \ddots \ \vdots \\
#         \sigma_{I1} \ \sigma_{I2} \ \dots \ \sigma_{I}^2
#     \end{bmatrix}
# \end{eqnarray*}
# variance on returns
ms_var = log_returns['PG'].var()
ms_var
ms_var_anual = log_returns['PG'].var() * 250
ms_var_anual
pg_var = log_returns['BEI.DE'].var()
pg_var
pg_var_anual = log_returns['BEI.DE'].var() * 250
pg_var_anual
# covariance on returns
cov_matrix = log_returns.cov()
cov_matrix
cov_matrix_anual = log_returns.cov() * 250
cov_matrix_anual
# correlation on returns no need x 252
corr_matrix = log_returns.corr()
corr_matrix
# ## Calculating Portfolio Risk
# Weigthing scheme:
weights = np.array([0.25, 0.75])
# Portfolio Variance:
pfolio_var = np.dot(weights.T, np.dot(log_returns.cov() * 250, weights))
pfolio_var
# Portfolio Volatility:
pfolio_vol = (np.dot(weights.T, np.dot(log_returns.cov() * 250, weights))) ** 0.5
pfolio_vol
print (str(round(pfolio_vol, 5) * 100) + ' %')
# systematic = un diversifiable risk
# unsystematic = diversifiable risk = idiosyncratic -> diversification
## Calculating Diversifiable and Non-Diversifiable Risk of a Portfolio
# Diversifiable Risk:
ms_var_anual = log_returns['PG'].var() * 250
ms_var_anual
pg_var_anual = log_returns['BEI.DE'].var() * 250
pg_var_anual
diversifable_risk = pfolio_var - (weights[0] ** 2 * ms_var_anual) - (weights[1] ** 2 * pg_var_anual)
diversifable_risk
print (str(round(diversifable_risk*100, 3)) + ' %')
# Non-Diversifiable Risk:
n_dr_1 = pfolio_var - diversifable_risk
n_dr_1
n_dr_2 = (weights[0] ** 2 * ms_var_anual) + (weights[1] ** 2 * pg_var_anual)
n_dr_2
n_dr_1 == n_dr_2
# regresssions
import numpy as np
import pandas as pd
from scipy import stats
import statsmodels.api as sm
import matplotlib.pyplot as plt
data = pd.read_excel('Section-13_Housing.xlsx')
data[['House Price', 'House Size (sq.ft.)']]
# univarate regression
X = data['House Size (sq.ft.)']
Y = data['House Price']
plt.scatter(X,Y)
plt.axis([0, 2500, 0, 1500000])
plt.ylabel('House Price')
plt.xlabel('House Size (sq.ft)')
# regression linear OLS
X1 = sm.add_constant(X)
reg = sm.OLS(Y, X1).fit()
reg.summary()
### Alpha, Beta, R^2:
slope, intercept, r_value, p_value, std_err = stats.linregress(X,Y)
line = intercept + slope * X
plt.plot(X,line)
print(slope)
print(intercept)
print(r_value)
print(r_value**2)
print(p_value)
print(std_err)
data = pd.read_excel('Section-13_IQ_data.xlsx')
data[['IQ', 'Test 1']]
X = data['Test 1']
Y = data['IQ']
plt.scatter(X,Y)
plt.axis([0, 120, 0, 150])
plt.ylabel('IQ')
plt.xlabel('Test 1')
# regression linear OLS
X1 = sm.add_constant(X)
reg = sm.OLS(Y, X1).fit()
reg.summary()
### Alpha, Beta, R^2:
slope, intercept, r_value, p_value, std_err = stats.linregress(X,Y)
line = intercept + slope * X
plt.plot(X,line)
print(slope)
print(intercept)
print(r_value)
print(r_value**2)
print(p_value)
print(std_err)
####################
# ## Obtaining the Efficient Frontier - Part I
# *Suggested Answers follow (usually there are multiple ways to solve a problem in Python).*
# We are in the middle of a set of 3 Python lectures that will help you reproduce the Markowitz Efficient Frontier. Let’s split this exercise into 3 parts and cover the first part here.
# Begin by loading data for Walmart and Facebook from the 1st of January 2014 until today.
import numpy as np
import pandas as pd
from pandas_datareader import data as wb
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
assets = ['PG', '^GSPC']
# assets = ['WMT', 'FB']
pf_data = pd.DataFrame()
# for a in assets:
#     pf_data[a] = wb.DataReader(a, data_source = 'yahoo', start = '2010-1-1')['Adj Close']
pf_data = pd.read_csv('Section-14_Markowitz_Data.csv', index_col = 'Date')
# pf_data = pd.read_csv('Section-12_Walmart_FB_2014_2017.csv', index_col='Date')
pf_data.tail()
(pf_data / pf_data.iloc[0] * 100).plot(figsize=(10, 5))
log_returns = np.log(pf_data / pf_data.shift(1))
log_returns.mean() * 250
log_returns.cov() * 250
log_returns.corr()
# In[10]:
num_assets = len(assets)
weights = np.random.random(num_assets)
weights /= np.sum(weights)
weights
weights[0] + weights[1]
# Now, estimate the expected Portfolio Return, Variance, and Volatility.
# Expected Portfolio Return:
np.sum(weights * log_returns.mean()) * 250
# Expected Portfolio Variance:
np.dot(weights.T, np.dot(log_returns.cov() * 250, weights))
# Expected Portfolio Volatility:
np.sqrt(np.dot(weights.T,np.dot(log_returns.cov() * 250, weights)))
# ***
# The rest of this exercise will be a reproduction of what we did in the previous video.
# 1)	Create two empty lists. Name them pf_returns and pf_volatilites.
pfolio_returns = []
pfolio_volatilities = []
# 2)	Create a loop with 1,000 iterations that will generate random weights, summing to 1, and will append the obtained values for the portfolio returns and the portfolio volatilities to pf_returns and pf_volatilities, respectively.
for x in range (1000):
    weights = np.random.random(num_assets)
    weights /= np.sum(weights)
    pfolio_returns.append(np.sum(weights * log_returns.mean()) * 250)
    pfolio_volatilities.append(np.sqrt(np.dot(weights.T,np.dot(log_returns.cov() * 250, weights))))

pfolio_returns, pfolio_volatilities
# 3)	Transform the obtained lists into NumPy arrays and reassign them to pf_returns and pf_volatilites. Once you have done that, the two objects will be NumPy arrays.
pfolio_returns = np.array(pfolio_returns)
pfolio_volatilities = np.array(pfolio_volatilities)
pfolio_returns, pfolio_volatilities
# In[21]:
portfolios = pd.DataFrame({'Return': pfolio_returns, 'Volatility': pfolio_volatilities})
portfolios.head()
portfolios.tail()
# In[24]:
portfolios.plot(x='Volatility', y='Return', kind='scatter', figsize=(10, 6));
plt.xlabel('Expected Volatility')
plt.ylabel('Expected Return')
######### Section-14_87-ObtainingtheEfficientFrontier-PartIII-Solution_CSV
import numpy as np
import pandas as pd
from pandas_datareader import data as wb
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
assets = ['WMT', 'FB']
pf_data = pd.read_csv('Section-14_Walmart_FB_2014_2017.csv', index_col='Date')
# pf_data = pd.DataFrame()
# for a in assets:
#     pf_data[a] = wb.DataReader(a, data_source = 'yahoo', start = '2014-1-1')['Adj Close']
pf_data.tail()
(pf_data / pf_data.iloc[0] * 100).plot(figsize=(10, 5))
log_returns = np.log(pf_data / pf_data.shift(1))
log_returns.mean() * 250
log_returns.cov() * 250
log_returns.corr()
# In[10]:
num_assets = len(assets)
weights = np.random.random(num_assets)
weights /= np.sum(weights)
weights
weights[0] + weights[1]
# Now, estimate the expected Portfolio Return, Variance, and Volatility.
# Expected Portfolio Return:
np.sum(weights * log_returns.mean()) * 250
# Expected Portfolio Variance:
np.dot(weights.T, np.dot(log_returns.cov() * 250, weights))
# Expected Portfolio Volatility:
np.sqrt(np.dot(weights.T,np.dot(log_returns.cov() * 250, weights)))
# The rest of this exercise will be a reproduction of what we did in the previous video.
# 1)	Create two empty lists. Name them pf_returns and pf_volatilites.
pf_returns = []
pf_volatilities = []
# 2)	Create a loop with 1,000 iterations that will generate random weights, summing to 1, and will append the obtained values for the portfolio returns and the portfolio volatilities to pf_returns and pf_volatilities, respectively.
for x in range (1000):
    weights = np.random.random(num_assets)
    weights /= np.sum(weights)
    pf_returns.append(np.sum(weights * log_returns.mean()) * 250)
    pf_volatilities.append(np.sqrt(np.dot(weights.T,np.dot(log_returns.cov() * 250, weights))))

pf_returns, pf_volatilities
# 3)	Transform the obtained lists into NumPy arrays and reassign them to pf_returns and pf_volatilites. Once you have done that, the two objects will be NumPy arrays.
# In[8]:
pf_returns = np.array(pf_returns)
pf_volatilities = np.array(pf_volatilities)
pf_returns, pf_volatilities
# Now, create a dictionary, called portfolios, whose keys are the strings “Return” and “Volatility” and whose values are the NumPy arrays pf_returns and pf_volatilities.
# In[9]:
portfolios = pd.DataFrame({'Return': pf_returns, 'Volatility': pf_volatilities})
# In[10]:
portfolios.head()
portfolios.tail()
# Finally, plot the data from the portfolios dictionary on a graph. Let the x-axis represent the volatility data from the portfolios dictionary and the y-axis – the data about rates of return.

# Organize your chart well and make sure you have labeled both the x- and the y- axes.
portfolios.plot(x='Volatility', y='Return', kind='scatter', figsize=(10, 6));
plt.xlabel('Expected Volatility')
plt.ylabel('Expected Return')
# What do you think would happen if you re-created the Markowitz Efficient Frontier for 3 stocks? The code you have created is supposed to accommodate easily the addition of a third stock, say British Petroleum (‘BP’). Insert it in your data and re-run the code (you can expand the “Cell” list from the Jupyter menu and click on “Run All” to execute all the cells at once!).

# How would you interpret the obtained graph?
assets = ['WMT', 'FB', 'BP']
pf_data = pd.DataFrame()
for a in assets:
    pf_data[a] = wb.DataReader(a, data_source = 'yahoo', start = '2014-1-1')['Adj Close']
pf_data.head()
# In[14]:
log_returns = np.log(pf_data / pf_data.shift(1))
# In[15]:
num_assets = len(assets)
num_assets
weights = np.random.random(num_assets)
weights /= np.sum(weights)
weights
weights[0] + weights[1] + weights[2]
# Expected Portfolio Return:
np.sum(weights * log_returns.mean()) * 250
# Expected Portfolio Variance:
np.dot(weights.T, np.dot(log_returns.cov() * 250, weights))
# Expected Portfolio Volatility:
np.sqrt(np.dot(weights.T,np.dot(log_returns.cov() * 250, weights)))
# *****
pfolio_returns = []
pfolio_volatilities = []
# 2)	Create a loop with 1,000 iterations that will generate random weights, summing to 1, and will append the obtained values for the portfolio returns and the portfolio volatilities to pf_returns and pf_volatilities, respectively.
for x in range (1000):
    weights = np.random.random(num_assets)
    weights /= np.sum(weights)
    pfolio_returns.append(np.sum(weights * log_returns.mean()) * 250)
    pfolio_volatilities.append(np.sqrt(np.dot(weights.T,np.dot(log_returns.cov() * 250, weights))))

pfolio_returns, pfolio_volatilities
# 3)	Transform the obtained lists into NumPy arrays and reassign them to pf_returns and pf_volatilites. Once you have done that, the two objects will be NumPy arrays.
pfolio_returns = np.array(pfolio_returns)
pfolio_volatilities = np.array(pfolio_volatilities)
pfolio_returns, pfolio_volatilities
# In[21]:
portfolios = pd.DataFrame({'Return': pfolio_returns, 'Volatility': pfolio_volatilities})
portfolios.head()
portfolios.tail()
# In[24]:
portfolios.plot(x='Volatility', y='Return', kind='scatter', figsize=(10, 6));
plt.xlabel('Expected Volatility')
plt.ylabel('Expected Return')
########## Section-14_87-ObtainingtheEfficientFrontier-PartIII-Solution-3companies_CSV
#!/usr/bin/env python
# coding: utf-8
# ## Obtaining the Efficient Frontier - Part III
# *Suggested Answers follow (usually there are multiple ways to solve a problem in Python).*
# We are in the middle of a set of 3 Python lectures that will help you reproduce the Markowitz Efficient Frontier. Lets split this exercise into 3 parts and cover the first part here.
# Begin by loading data for Walmart and Facebook from the 1st of January 2014 until today.
import numpy as np
import pandas as pd
from pandas_datareader import data as wb
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
# In[2]:
assets = ['WMT', 'FB', 'BP']
# pf_data = pd.DataFrame()
# for a in assets:
#     pf_data[a] = wb.DataReader(a, data_source = 'yahoo', start = '2014-1-1')['Adj Close']
pf_data = pd.read_csv('Section-14_87-WMT_FB_BP_2014_2017.csv', index_col='Date')
# In[3]:
pf_data.head()
# In[4]:
pf_data.tail()
(pf_data / pf_data.iloc[0] * 100).plot(figsize=(10, 5))
log_returns = np.log(pf_data / pf_data.shift(1))
log_returns.mean() * 250
log_returns.cov() * 250
log_returns.corr()
# In[10]:
num_assets = len(assets)
weights = np.random.random(num_assets)
weights /= np.sum(weights)
weights
# In[15]:
weights[0] + weights[1] + weights[2]
# Expected Portfolio Return:
np.sum(weights * log_returns.mean()) * 250
# Expected Portfolio Variance:
np.dot(weights.T, np.dot(log_returns.cov() * 250, weights))
# Expected Portfolio Volatility:
np.sqrt(np.dot(weights.T,np.dot(log_returns.cov() * 250, weights)))
# The rest of this exercise will be a reproduction of what we did in the previous video.
# 1)	Create two empty lists. Name them pf_returns and pf_volatilites.
pfolio_returns = []
pfolio_volatilities = []
# 2)	Create a loop with 1,000 iterations that will generate random weights, summing to 1, and will append the obtained values for the portfolio returns and the portfolio volatilities to pf_returns and pf_volatilities, respectively.
for x in range (1000):
    weights = np.random.random(num_assets)
    weights /= np.sum(weights)
    pfolio_returns.append(np.sum(weights * log_returns.mean()) * 250)
    pfolio_volatilities.append(np.sqrt(np.dot(weights.T,np.dot(log_returns.cov() * 250, weights))))
pfolio_returns, pfolio_volatilities
# In[20]:
pfolio_returns = []
pfolio_volatilities = []
for x in range (1000):
    weights = np.random.random(num_assets)
    weights /= np.sum(weights)
    pfolio_returns.append(np.sum(weights * log_returns.mean()) * 250)
    pfolio_volatilities.append(np.sqrt(np.dot(weights.T,np.dot(log_returns.cov() * 250, weights))))

pfolio_returns = np.array(pfolio_returns)
pfolio_volatilities = np.array(pfolio_volatilities)
pfolio_returns, pfolio_volatilities
# In[21]:
portfolios = pd.DataFrame({'Return': pfolio_returns, 'Volatility': pfolio_volatilities})
portfolios.head()
portfolios.tail()
# In[24]:
portfolios.plot(x='Volatility', y='Return', kind='scatter', figsize=(10, 6));
plt.xlabel('Expected Volatility')
plt.ylabel('Expected Return')
## Calculating the Beta of a Stock
# *Suggested Answers follow (usually there are multiple ways to solve a problem in Python).*
# Load the data for Microsoft and S&P 500 for the period 1st of January 2012 – 31st of December 2016.
import numpy as np
import pandas as pd
from pandas_datareader import data as wb
# tickerList = ['PG', '^GSPC']
# tickerList = ['MSFT', '^GSPC']
# data = pd.DataFrame()
# for t in tickerList:
#     data[t] = wb.DataReader(t, data_source='yahoo', start='2012-1-1', end='2016-12-31')['Adj Close']
#     data[t] = wb.DataReader(t, data_source='yahoo', start='2012-1-1', end='2016-12-31')['Adj Close']
data = pd.read_csv('Section-15_CAPM_Data.csv', index_col = 'Date')
data = pd.read_csv('Section-15_CAPM_Exercise_Data.csv', index_col = 'Date')
data.head()
# Let S&P 500 act as the market.
# *****
# Calculate the beta of Microsoft.
sec_returns = np.log( data / data.shift(1) )
# In[3]:
cov = sec_returns.cov() * 250
cov
# In[4]:
cov_with_market = cov.iloc[0,1]
cov_with_market
# In[5]:
market_var = sec_returns['^GSPC'].var() * 250
market_var
# ** Beta**
# $$
# \beta_{stock} = \frac{\sigma_{stock,market}}{\sigma_{market}^2}
# $$
stock_beta = cov_with_market / market_var
stock_beta
## Calculating the Expected Return of a Stock (CAPM)
# *Suggested Answers follow (usually there are multiple ways to solve a problem in Python).*
# Obtain data for Microsoft and S&P 500 for the period 1st of January 2012  31st of December 2016 from Yahoo Finance.
# Let S&P 500 act as the market.
# Calculate the beta of Microsoft.
# In[1]:
import numpy as np
import pandas as pd
from pandas_datareader import data as wb
# tickerList = ['PG', '^GSPC']
# tickerList = ['MSFT', '^GSPC']
# data = pd.DataFrame()
# for t in tickerList:
#     data[t] = wb.DataReader(t, data_source='yahoo', start='2012-1-1', end='2016-12-31')['Adj Close']
data = pd.read_csv('Section-15_CAPM_Data.csv', index_col = 'Date')
# data = pd.read_csv('Section-15_CAPM_Exercise_Data.csv', index_col = 'Date')
data.head()
sec_returns = np.log( data / data.shift(1) )
# In[3]:
cov = sec_returns.cov() * 250
cov
# In[4]:
cov_with_market = cov.iloc[0,1]
cov_with_market
# In[5]:
market_var = sec_returns['^GSPC'].var() * 250
market_var
# **Beta:**
### $$
# \beta_{pg} = \frac{\sigma_{pg,m}}{\sigma_{m}^2}
# $$
stock_beta = cov_with_market / market_var
stock_beta
# Assume a risk-free rate of 2.5% and a risk premium of 5%.

# Estimate the expected return of Microsoft.
# **Calculate the expected return of P&G (CAPM):**
# ### $$
# \overline{r_{pg}} = r_f + \beta_{pg}(\overline{r_{m}} - r_f)
# $$
stock_expectedReturn = 0.025 + stock_beta * 0.05
stock_expectedReturn
## Estimating the Sharpe Ratio in Python
# *Suggested Answers follow (usually there are multiple ways to solve a problem in Python).*
# Obtain data for Microsoft and S&P 500 for the period 1st of January 2012 – 31st of December 2016 from Yahoo Finance.
# Let S&P 500 act as the market.
# Calculate the beta of Microsoft.
# Assume a risk-free rate of 2.5% and a risk premium of 5%.

# Estimate the expected return of Microsoft.
import numpy as np
import pandas as pd
from pandas_datareader import data as wb
# tickerList = ['PG', '^GSPC']
# tickerList = ['MSFT', '^GSPC']
# data = pd.DataFrame()
# for t in tickerList:
#     data[t] = wb.DataReader(t, data_source='yahoo', start='2012-1-1', end='2016-12-31')['Adj Close']
# data = pd.read_csv('Section-15_CAPM_Exercise_Data.csv', index_col = 'Date')
data = pd.read_csv('Section-15_CAPM_Data.csv', index_col = 'Date')
data.head()
sec_returns = np.log( data / data.shift(1) )
# In[3]:
cov = sec_returns.cov() * 250
cov
# In[4]:
cov_with_market = cov.iloc[0,1]
cov_with_market
# In[5]:
market_var = sec_returns['^GSPC'].var() * 250
market_var
# ** Beta: **
# $$
# \beta_{pg} = \frac{\sigma_{pg,m}}{\sigma_{m}^2}
# $$
stock_beta = cov_with_market / market_var
stock_beta
# **Calculate the expected return of P&G (CAPM):**
# $$
# \overline{r_{pg}} = r_f + \beta_{pg}(\overline{r_{m}} - r_f)
# $$
stock_er = 0.025 + stock_beta * 0.05
stock_er
# Calculate the Sharpe ratio in Python.
# **Sharpe ratio:**
# $$
# Sharpe = \frac{\overline{r_{pg}} - r_f}{\sigma_{pg}}
# $$
SharpeRatio = (stock_er - 0.025) / (sec_returns['PG'].std() * 250 ** 0.5)
#SharpeRatio = (stock_er - 0.025) / (sec_returns['MSFT'].std() * 250 ** 0.5)
SharpeRatio
## Monte Carlo - Predicting Gross Profit - Part I
# *Suggested Answers follow (usually there are multiple ways to solve a problem in Python).*
# Imagine you are an experienced manager and you have forecasted revenues of \$200mln, with an expected deviation of $10mln. You are convinced Cogs will be near 40% of the revenues, and their expected deviation is 20% of its own value.
# Use NumPys random.random function to simulate the potential revenue stream for 250 iterations (which is the number of trading days in a year) and then the predicted Cogs value.
import numpy as np
import matplotlib.pyplot as plt
# In[2]:
rev_m = 170 # 200
rev_stdev = 20 # 10
iterations = 1000 # 250
# In[3]:
rev = np.random.normal(rev_m, rev_stdev, iterations)
rev
# Plot the obtained data for revenues and Cogs on a graph and observe the behavior of the obtained values.
plt.figure(figsize=(15, 6))
plt.plot(rev)
plt.show()
# In[5]:
COGS = - (rev * np.random.normal(0.6,0.1)) # (0.4,0.2))
plt.figure(figsize=(15, 6))
plt.plot(COGS)
plt.show()
# Cogs mean:
COGS.mean()
# Cogs std:
COGS.std()
# ****
# Based on the predicted revenue and Cogs values, estimate the expected Gross Profit of your company.
# *Reminder: Be careful about estimating the gross profit. If you have stored the Cogs value as a negative number, the gross profit will equal revenues plus Cogs. If you have created Cogs as a positive value, then gross profit would be equal to revenues minus Cogs. Either way, you will obtain the same result for gross profit.*
Gross_Profit = rev + COGS
Gross_Profit
plt.figure(figsize=(15, 6))
plt.plot(Gross_Profit)
plt.show()
# What is the maximum and what is the minimum gross profit value you obtained?
max(Gross_Profit)
# In[10]:
min(Gross_Profit)
# What is its mean and standard deviation?
Gross_Profit.mean()
# In[12]:
Gross_Profit.std()
# Do you remember what a histogram is? Plot the gross profit data on a histogram. Use 20 bins directly to check the distribution of the data.
plt.figure(figsize=(10, 6));
plt.hist(Gross_Profit, bins = [40, 50, 60, 70, 80, 90, 100, 110, 120]);
plt.show()
# In[14]:
plt.figure(figsize=(10, 6));
plt.hist(Gross_Profit, bins = 20);
plt.show()
# ************
# In all our analyses, we used estimations for either simple or logarithmic rates of return.

# The formula for simple returns is
# $$
# \frac{P_t - P_{t-1}}{P_{t-1}}
# $$
# while the formula for log returns is
# $$
# ln( \frac{P_t}{P_{t-1}} )
# $$
# If our dataset is simply called "data", in Python, we could write the first formula as
# *(data / data.shift(1)) - 1,*
# and the second one as
# *np.log(data / data.shift(1)).*
# Instead of coding it this way, some professionals prefer using **Pandas.DataFrame.pct_change()** method, as it computes simple returns directly. We will briefly introduce it to you in this notebook document.
# First, let's import NumPy, Pandas, and pandas_datareader.
import numpy as np
import pandas as pd
from pandas_datareader import data as wb
# We will calculate returns of the Procter and Gamble stock, based on adjusted closing price data since the
# 1st of January 2007.
# 1st of January 2015.
data = pd.read_csv('Section-17_PG_2007_2017.csv', index_col = 'Date')
# ticker = 'PG'
# data = pd.DataFrame()
# data[ticker] = wb.DataReader(ticker, data_source='yahoo', start='2007-1-1')['Adj Close']
# data[ticker] = wb.DataReader(ticker, data_source='iex', start='2015-1-1')['close']
# So far, we estimated simple returns in the following way.
s_rets_1 = (data / data.shift(1)) - 1
s_rets_1.head()
# Observe the .pct_change() method can obtain an identical result.
s_rets_2 = data.pct_change()
s_rets_2.head()
# Now, if you multiply the obtained values by 100, you will see the percentage change:
s_rets_2.head() * 100
# This means the close price on 2007-01-04 was 0.76% lower than the price on 2007-01-03, the price on 2007-01-05 was 0.85% lower than the price on 2007-01-04, and so on.
# A few arguments can be used in the percentage change method. The most important one is 'period' as it specifies the difference between prices in the nominator. By default, it equals one, and that's why we obtained the same result for s_rets_1 and s_rets_2. Let's assume we would like to calculate simple returns with the following formula:
# $$
# \frac{P_t - P_{t-2}}{P_{t-2}}
# $$
# Then, we should specify 'periods = 2' in parentheses:
s_rets_3 = data.pct_change(periods=2)
s_rets_3.head()
# You can see there was no value obtained not only for the first, but also for the second observation. If we use the "old" formula, and not this method, *shift(2)* would lead us to the same output:
s_rets_4 = (data / data.shift(2)) - 1
s_rets_4.head()
# Now, let's consider logarithmic returns. To this moment, we applied the following formula:
log_rets_1 = np.log(data / data.shift(1))
log_rets_1.tail()
# You can calculate the same formula for log returns with the help of the .pct_change() method. Just be careful with the way you apply the formula! Mathematically, it will look like this:
# $$
# ln(\frac{P_t}{P_{t-1}} ) = ln( \frac{P_t - P_{t-1}}{P_{t-1}} + \frac{P_{t-1}}{P_{t-1}}) = ln(\ simple.returns + 1)
# $$
# In[9]:
log_rets_2 = np.log(data.pct_change() + 1)
log_rets_2.tail()
# ***
# The .pct_change() method is very popular. Whether you include it in your code or you go the other way around and type the formulas as we did in our analyses, you should obtain the correct value for the returns you need.
########## 103
## Monte Carlo - Forecasting Stock Prices - Part I
# *Suggested Answers follow (usually there are multiple ways to solve a problem in Python).*
# Download the data for Microsoft (MSFT) from Yahoo Finance for the period 2000-1-1 until today.
# Download the data for Microsoft (MSFT) from IEX for the period 2015-1-1 until today.
# Forecasting Future Stock Prices  continued:
import numpy as np
import pandas as pd
from pandas_datareader import data as wb
import matplotlib.pyplot as plt
from scipy.stats import norm
get_ipython().run_line_magic('matplotlib', 'inline')
# In[2]:
# ticker = 'PG'
# ticker = 'MSFT'
# data = pd.DataFrame()
# data[ticker] = wb.DataReader(ticker, data_source='yahoo', start='2007-1-1')['Adj Close']
# data[ticker] = wb.DataReader(ticker, data_source='iex', start='2015-1-1')['close']
data = pd.read_csv('Section-17_PG_2007_2017.csv', index_col = 'Date')
data = pd.read_csv('Section-17_MSFT_2000.csv', index_col = 'Date')
data.plot(figsize=(10, 6));
# Use the .pct_change() method to obtain the log returns of Microsoft for the designated period.
log_returns = np.log(1 + data.pct_change())
log_returns.tail()
log_returns.plot(figsize = (10, 6))
# Assign the mean value of the log returns to a variable, called U, and their variance to a variable, called var.
u = log_returns.mean()
u
# In[7]:
var = log_returns.var()
var
# Calculate the drift, using the following formula:
# $$
# drift = u - \frac{1}{2} \cdot var
# $$
drift = u - (0.5 * var)
drift
# Store the standard deviation of the log returns in a variable, called stdev.
stdev = log_returns.std()
stdev
# ******
# Use .values to transform the *drift* and the *stdev* objects into arrays.
type(drift)
drift.values
# In[4]:
type(stdev)
# In[12]:
np.array(drift)
drift.values
# In[14]:
stdev.values
# Forecast future stock prices for every trading day a year ahead. So, assign 250 to t_intervals.
# Lets examine 10 possible outcomes. Bind iterations to the value of 10.
t_intervals = 250
t_intervals = 1000
iterations = 10
# Use the formula we have provided and calculate daily returns.
# $$
# r = drift + stdev \cdot z
# $$
# $$
# daily\_returns = exp({drift} + {stdev} * z),
# $$
# $$
# where\  z = norm.ppf(np.random.rand(t\_intervals, iterations)
# $$
# $$
# daily\_returns = e^{r}
# $$
daily_returns = np.exp(drift.values + stdev.values * norm.ppf(np.random.rand(t_intervals, iterations)))
daily_returns
# $$
# S_t = S_0 \mathbin{\cdot} daily\_return_t
# $$
# $$
# S_{t+1} = S_t \mathbin{\cdot} daily\_return_{t+1}
# $$
# $$...$$
# $$
# S_{t+999} = S_{t+998} \mathbin{\cdot} daily\_return_{t+999}
# $$
# ***
# Create a variable S0 equal to the last adjusted closing price of Microsoft. Use the iloc method.
S0 = data.iloc[-1]
S0
# Create a variable price_list with the same dimension as the daily_returns matrix.
price_list = np.zeros_like(daily_returns)
price_list
price_list[0]
# Set the values on the first row of the price_list array equal to S0.
price_list[0] = S0
price_list
# Create a loop in the range (1, t_intervals) that reassigns to the price in time t the product of the price in day (t-1) with the value of the daily returns in t.
for t in range(1, t_intervals):
    price_list[t] = price_list[t - 1] * daily_returns[t]
price_list
# Finally, plot the obtained price list data.
plt.figure(figsize=(10,6))
plt.plot(price_list);

import numpy,from scipy,import statsmodels


"""
Estimate Volatility
Create an exponential moving average model of volatility. Use the formula in your notes:
where r_n is the nth daily return, and \sigma_nσ is the nth estimate of the volatility.
\lambdaλ is a constant between 0 and 1 that defines how quickly weights on older data should decrease.
A high value of \lambdaλ (close to 1) will cause older data to matter relatively more in the calculation of \sigma_nσ.
A very low value of \lambdaλ will mean that recent data matter more—in this case, the successive daily estimates of \sigma_nσ
themselves will be volatile.

Pandas provides built-in exponentially weighted moving window functions with the .ewm method.
Consider using .ewm().mean(), and be sure to properly specify the alpha parameter (hint: it is related to, but not equal to \lambdaλ).

** the ema function using (1-alpha), so since they pass us lambda we need to 1-lambda to get the method to work properly

Note that .ewm().std() and .ewm().var() implement ewmvar(x) = ewma(x**2) - ewma(x)**2,
which is slightly different than what you'll want to implement for this problem.

Other resources.
https://knowledge.udacity.com/questions/413282
https://knowledge.udacity.com/questions/157360
https://knowledge.udacity.com/questions/381675
https://knowledge.udacity.com/questions/43364

Result

0.004940582044719361
Most recent volatility estimate: 0.004941
"""

import pandas as pd
import numpy as np
import math

def estimate_volatility(prices, l):
    """Create an exponential moving average model of the volatility of a stock
    price, and return the most recent (last) volatility estimate.

    Parameters
    ----------
    prices : pandas.Series
        A series of adjusted closing prices for a stock.

    l : float
        The 'lambda' parameter of the exponential moving average model. Making
        this value smaller will cause the model to weight older terms less
        relative to more recent terms.

    Returns
    -------
    last_vol : float
        The last element of your exponential moving averge volatility model series.

    """
    # TODO: Implement the exponential moving average volatility model and return the last value.
    # calculate log returns
    returns = np.log(prices) - np.log(prices.shift(1))

    # square log returns
    returns_squared = returns ** 2

    # take the ewm mean
    result = returns_squared.ewm(alpha=1 - l).mean()

    # take the square root of the results
    ema = np.sqrt(result.iloc[-1])
    print(ema)

    return ema

def test_run(filename="data.csv"):
    """Test run get_most_volatile() with stock prices from a file."""
    prices = pd.read_csv(filename, parse_dates=["date"], index_col="date", squeeze=True)
    print("Most recent volatility estimate: {:.6f}".format(estimate_volatility(prices, 0.7)))

if __name__ == "__main__":
    test_run()