Сравнение экспоненциального сглаживания и регрессии на Ллойдс банка цена акций данных


Что это один из способов изменить ее в программе, которая использует концепции ООП? Я всегда запрограммирован таким образом, и я чувствую, что мне надо будет как-то улучшить его. Кстати, я сознательно избегал панды и пакет scikit учиться.

import csv
from collections import defaultdict
from random import random,randint
import matplotlib.pyplot as plt
import numpy as np
''' This code reads a file with stock price data and does exponential smoothing with the purpose of comparing it with regression on the same column of data. Finally original data and smoothed data are plotted together as well as the regression line along with the scatter plot of the original data. The code allows for repeated input of the smoothing parameter alpha until the user is satisfied with the result.'''
# ------------ Let us check for existence of the file path -------------------------
check_filepath=True
while check_filepath:
    filepath=input('enter the path of the csv file with the stock price data     WITHOUT any  quotations and press Enter: ')
# Example of a file path :  /Users/abigaletessema/Desktop/LYG.csv

# the following try -except-else block catches the error in file path and allows for repeated attempt 
    try:
        f=csv.reader(filepath)
        print("Here is the filepath:"+ filepath) 
    except FileNotFoundError:
        print("The filepath doesn't exist or there are some missing directories , please check and try again")
    else:
        print("Great! the file path is correct. Now, you can carry on!")
        break
# ------------ Let us Open our data file -------------------------
columns = defaultdict(list) # each value in each column is appended to a list

file_handle=open('{}'.format(filepath),'r')
reader=csv.reader(file_handle,delimiter=",")
next(reader,None) # Skips the header of the file which is Time_Index and Adj_Close_Price

for row in reader :
    for (i,v) in enumerate(row):
        columns[i].append(v)

columns[0] = list(map(int, columns[0])) # This list corresponds to the time index
columns[1] = list(map(float, columns[1]))  # This list corresponds to the Adjusted closing price
t,p=columns[0],columns[1] # assigning the above values to a more intuitive name t for time and p for price
print("Time index is {}".format(t))
print("Adjusted closing prices are {} ".format(p))
file_handle.close()

#------------------ Let us do the exponential smoothing part now ----------------
def exponential_smoothing(original_series, alpha):
    smoothed_price = [float(original_series[0])] # first value is same as series
    maximum=len(original_series)
    for n in range(0,maximum-1):
        # The next line populates the smoothed_price list with smoothed values using the stated relationship
        smoothed_price.append(alpha * original_series[n] + (1 - alpha) * smoothed_price[n])

    return smoothed_price

original_series=p



#-------- model parameter selection -----------
def find_the_right_alpha():

    while True:              # keep looping until `break` statement is reached
        alpha_value=float(input("Enter a number between 0 exclusive and 1 inclusive: "))
        try:                 # get ready to catch exceptions inside here
            if 0.0 < alpha_value <= 1.0:

                y=exponential_smoothing(p,alpha_value) # y is another name for smoothed_price
                y = [ round(elem, 2) for elem in y ] # rounding off the y values to 2 significant digits
                print("The smoothed values of the price are {}".format(y))
                        #------------ Plotting time --------------

                plt.plot(t,y,label='Smoothed data',c='r')
                plt.xlabel('Time Index')
                plt.ylabel('Prices')
                plt.plot(t,original_series,label='Original data',c='b')

                plt.grid(True)
                plt.legend()
                plt.show()
                response=input("Do you like the smoothed data ? Enter Y for yes: ")
                # --------checking if the user is happy with the selection of alpha -----------
                if (response =='Y' or response=='y'):
                    print("Great! You seem to be satisfied with alpha value of {}".format(alpha_value))
                    break
                else:
                # This block would give the chosen alpha value as it wouldn't be 
                #executed after the final decision of choice is made
                    alpha_value=find_the_right_alpha() 
                    break
            else:
                print(" Let us try again!")
        except ValueError:      # <-- exception. handle it. loops because of while True
            print("Not a valid alpha value, let's try that again")
    return alpha_value

#---------- End of find_the_right_alpha function-----------------


alpha_value=find_the_right_alpha() # function call to determine alpha

t_predict=len(t)-1
def smoothing_predict(t_predict):
    y=exponential_smoothing(p,alpha_value)
    smooth_predicted=round((alpha_value*p[t_predict]+ (1-alpha_value)*y[t_predict]),3)
    display_value=print(" The smoothing predicted value for time {} is {}".format(t_predict+2,smooth_predicted))
    return display_value

smoothing_predict(t_predict)

# -------------- Regression time--------------


def calc_mean(t):
    total_sum=0
    for i in range(0,len(t)):
        total_sum+=t[i]
        result=total_sum/len(t)
    return result

def calc_coefficients(t,p):

    sum_xy_deviation=0
    sum_xsquared_deviation=0


    for i in range(0,len(t)):
        sum_xy_deviation+=(t[i]-calc_mean(t))*(p[i]-calc_mean(p))

        sum_xsquared_deviation+=pow(t[i]-calc_mean(t),2)

    beta=float(sum_xy_deviation/sum_xsquared_deviation)
    alpha=calc_mean(p)-beta*calc_mean(t)
    coefficients={'alpha':round(alpha,3), 'beta':round(beta,3)}
    return coefficients

def graph_regression_line(regression_formula,t):
    t=np.array(t)
    phat=regression_formula(t)
    plt.title('Regression Line and original data scatter plot')
    plt.scatter(t, p,c='b')
    plt.plot(t,phat)
    plt.show()

def regression_formula(t):
    coefficients=calc_coefficients(t,p)
    return coefficients['alpha']+t*coefficients['beta']
def calc_r_square(t,p):
    SSR,SST=0,0 # SSR is regression sum of squares. SST is total sum of squares
    p_hat=[]
    mean_price=calc_mean(p)
    coefficients=calc_coefficients(t,p)
    for i in range(0,len(t)):
        p_hat.append(coefficients['alpha']+coefficients['beta']*t[i])
        SSR+=pow(p_hat[i]-mean_price,2)
        SST+=pow(p[i]-mean_price,2)
    r_squared=round(SSR/SST,3)
    display_value=print(" The R-Squared value  is {}".format(r_squared))
    return display_value

t_predict=len(t)-1
def regression_predict(t_predict):
    coefficients=calc_coefficients(t,p)
    predicted=round((coefficients['alpha']+t_predict*coefficients['beta']),3)
    display_value= print(" The regression predicted value for time {} is {}".format(t_predict+2,predicted))
    return display_value
#-----------------------Displaying the output of our regression analysis --------------
graph_regression_line(regression_formula,t)
print("\n")
calc_r_square(t,p)
print("\n")
regression_predict(t_predict)
print("----------------")
print("The actual predicted value for time 9 is 3.32")
print("----------------")


Комментарии
1 ответ

Некоторые программы выигрывают от того, что написано в стиле ООП, то нет. Большая идея-это ли вы следовать хорошим практикам программирования. И я вижу много вещей, которые могут быть улучшены с вашим кодом.


  1. Длины линии. Вы должны держать вашу длину строки ниже 79 символов в строке, и ниже 72, если вы можете управлять им. Вы не хотите прокрутите вправо, чтобы просмотреть код, имея для этого делает просмотр кода позже муторно. И нужно писать код так, что кто-то рассматривает его позже, кто не знает все о нем (которая может быть вы-люди забывают вещи) будут способны это понять. Похоже, некоторые из длинных линиях может быть просто из-за вас вставить его в неправильно в CodeReview, но другие, безусловно, слишком долго.

  2. Организации код. Не должно быть никакого кода на уровне модуля, кроме "главного охранника" -- функция, которая проверяет, если код выполняется в интерактивном режиме и если это так называет реальную функцию main, которая делает работу. Это позволяет использовать функции в исходном коде .py файл в качестве библиотеки.

  3. Использование функции. Они-часть языка, так что используйте их. Каждая функция должна иметь одну ответственность, и все части фактического логике код должен быть в функции.

  4. Раздельный ввод/вывод от логики программы. Вы никогда не знаете, если вы можете выполнить те же расчеты, где входные данные поступают из файла, или сайт, или что, или где выход должен идти в файл. Итак, написать одну функцию, которая получает входные данные (зацикливание обратно, если плохой вход), вызвать другую функцию, чтобы сделать расчет, и называть другого выхода.


import csv
from collections import defaultdict
from random import random,randint
import matplotlib.pyplot as plt
import numpy as np
''' This code reads a file with stock price data and does exponential
smoothing with the purpose of comparing it with regression
on the same column of data. Finally original data and smoothed data
are plotted together as well as the regression line along with the
scatter plot of the original data. The code allows for repeated input
of the smoothing parameter alpha until the user is satisfied with the
result.'''
# ------------ Let us check for existence of the file path -------------------------

Если есть комментарий, как этот, это хороший сигнал, что следующий код должен быть в своей собственной функции, с комментарием как строкой документации. Однако, этот комментарий, кажется, предположить, что это о том, чтобы проверить некоторые существующие строки, является ли это существующий путь к файлу, а ниже код на самом деле запрашивает строки первая: комментарий является неполным. Так не должно быть (как минимум) двух функций: одна с параметром, который проверяет параметр для действия, и другой, который принимает входной и петли при необходимости.


check_filepath=True
while check_filepath:
filepath=input('enter the path of the csv file with the stock price data
WITHOUT any quotations and press Enter: ')
# Example of a file path : /Users/abigaletessema/Desktop/LYG.csv

Какова цель выше комментарий? Вы действительно думаете, что люди, читающие этот код, чтобы не понять, что такое путь к файлу? Но если не давать, то пример не очень поможет.


# the following try -except-else block catches the error in file path and allows for repeated attempt 

Комментарии выше-это хорошо, потому что это объясняет, почему код делает то, что он делает.


    try:
f=csv.reader(filepath)

Что происходит с f? Он, кажется, никогда не использоваться снова. Код, который вы никогда не закрывает его, что приводит к потере ресурсов до завершения процесса. Вызов csv.reader() впустую с сопровождающими затрат памяти и процессорного времени. На правильный путь, чтобы проверить существование файла/действия путь, который вы собираетесь открыть, пожалуйста, см. На этот вопрос.


        print("Here is the filepath:"+ filepath) 

В чем смысл этой строки? Он только запускается на выполнение, если в предыдущей строке не исключение, и это не дает никакой полезной информации. Это, конечно, не собираюсь бросать исключение, так почему он в try блок? Если это отладка кода, может бросить его в регистратор. Кроме того, вы должны использовать форматированный вывод, а не конкатенацию строк.


    except FileNotFoundError:

Хорошую работу убедившись, что только ловить исключения, которые вам небезразличны.


        print("The filepath doesn't exist or there are some missing directories , please check and try again")
else:
print("Great! the file path is correct. Now, you can carry on!")
break

Почему у вас есть else блок в этом try:/except ...:? Ты знаешь цель else: блок и когда она выполняется? Этот код, вероятно, принадлежит вне try:/except: блок.


# ------------ Let us Open our data file -------------------------

Опять-таки, это место для новой функции и строкой документации.


columns = defaultdict(list) # each value in each column is appended to a list

Это не объясняет, почему вы используете defaultdict, это был мой первый вопрос, когда я читал этот код. Это определенно не структура данных я бы использовал для этого. Каждый list в columns переменная будет иметь тот же размер, да? Я думаю, что лучше структура данных будет регулярно list кортежей или объектов.


file_handle=open('{}'.format(filepath),'r')

Почему ты звонишь .format() здесь? Что случилось с просто open(filepath,'r')? Также вы должны действительно рассмотреть возможность использования в Python with заявление здесь, чтобы убедиться, что файл правильно закрыта.


reader=csv.reader(file_handle,delimiter=",")

Почему аргумент по умолчанию здесь? Также это еще одно место для with


next(reader,None) # Skips the header of the file which is Time_Index and Adj_Close_Price

Хорошо использовать комментарий!


for row in reader :
for (i,v) in enumerate(row):
columns[i].append(v)

Вы знаете, сколько столбцов будет? Ваш комментарий показывает, там всегда будет 2, но код написан, чтобы разрешить произвольное количество столбцов. Убедитесь, что код соответствует замечания.

Опять же, если вы использовали другую структуру данных, то этот код будет намного проще.


columns[0] = list(map(int, columns[0])) # This list corresponds to the time index
columns[1] = list(map(float, columns[1])) # This list corresponds to the Adjusted closing price

Почему бы не сделать такую обработку, как Вы читаете файл, вместо того, чтобы сделать второй проход по ней и создавая второй временный список? Почему ты суешь вещи в dict-о-listС во всяком случае, с таким именем сам кодекс допускает сбивает с толку, когда ты мог бы вставлять их в переменные (или объектной), что было разумно имена?


t,p=columns[0],columns[1] # assigning the above values to a more intuitive name t for time and p for price

Ненавижу разорвать его к вам, но t и p не "интуитивно понятные" имена переменных. Они загадочные, простые и короткие имена персонажей, которые передают почти никакой информации. Если читатель этот код не попадает в комментарий, нет понятия, что это значит/содержать. Имя переменной следует указать, что внутри него и/или для чего это используется. Дискового пространства и оперативной памяти дешево (мы не в 1980 году), поэтому вам не выиграть какие-либо призы для написания кратчайшие имена переменных. Подумайте о долгосрочных пользователей вашего кода. 5 лет от Теперь, вы не думаете, что это настолько интуитивно понятен, что t значит, время и p значит, цена.


print("Time index is {}".format(t))
print("Adjusted closing prices are {} ".format(p))

В чем смысл этих строк? Они только для отладки? Когда вы будете удовлетворены с кодом, удаление их будет проблемой. Смотреть в logging модуль.


file_handle.close()

#------------------ Let us do the exponential smoothing part now ----------------
def exponential_smoothing(original_series, alpha):


Комментарий плохим-он просто повторяет то, что код уже говорит. Комментарии должны объяснить, почему код есть, не просто повторить то, что он делает. Пожалуйста, напишите правильный строкой документации для этой функции -- объяснить, что модель экспоненциального сглаживания, и какие параметры означают, и какой выход будет производиться.


    smoothed_price = [float(original_series[0])] # first value is same as series

Разве ты уже не преобразовать файл данных для float? Какой вклад делает эта функция в любом случае ожидать? Если его цель-выполнить какое-то сглаживание, оно не должно делать преобразования типов данных!


    maximum=len(original_series)
for n in range(0,maximum-1):
# The next line populates the smoothed_price list with smoothed values using the stated relationship
smoothed_price.append(alpha * original_series[n] + (1 - alpha) * smoothed_price[n])

Это одна из классических ошибок в Python программисты. Я не знаю, если они думают на другом языке, который они знают, или если они учили этому слову, но оно отражает отсутствие опыта работы с Python и непонимание того, как использовать языковые функции, чтобы сделать программирование более легким и менее подверженным ошибкам.

Список в Python являются первоклассными языковые особенности и нужно манипулировать как таковой. Вы почти никогда не приходится вручную создавать индексы список и перебирать список. Вместо этого вы должны использовать список осмысленностей , который получит всю эту функцию сделать в одном удобном для чтения строки.


    return smoothed_price

original_series=p

#-------- model parameter selection -----------
def find_the_right_alpha():


Все функции должны иметь комментарии. Комментарии не заменяют. Кстати, этот конкретный комментарий совершенно невозмутимым.


    while True:              # keep looping until `break` statement is reached
alpha_value=float(input("Enter a number between 0 exclusive and 1 inclusive: "))

Упс, ты забыл проверить на плохой вход. Без поплавка вошел сюда аварийному завершению программы.


        try:                 # get ready to catch exceptions inside here
if 0.0 < alpha_value <= 1.0:

y=exponential_smoothing(p,alpha_value) # y is another name for smoothed_price
y = [ round(elem, 2) for elem in y ] # rounding off the y values to 2 significant digits
print("The smoothed values of the price are {}".format(y))
#------------ Plotting time --------------

plt.plot(t,y,label='Smoothed data',c='r')
plt.xlabel('Time Index')
plt.ylabel('Prices')
plt.plot(t,original_series,label='Original data',c='b')

plt.grid(True)
plt.legend()
plt.show()
response=input("Do you like the smoothed data ? Enter Y for yes: ")
# --------checking if the user is happy with the selection of alpha -----------
if (response =='Y' or response=='y'):
print("Great! You seem to be satisfied with alpha value of {}".format(alpha_value))
break
else:
# This block would give the chosen alpha value as it wouldn't be
#executed after the final decision of choice is made
alpha_value=find_the_right_alpha()


Вы используете рекурсию, наверное, потому, что это то, что они научили вас. Рекурсия-это, как правило, учат студентов думать, а не потому что это важный метод программирования. В данном случае Рекурсия-это плохая идея. Попробуйте изменить функцию так, чтобы она не позвонит сама.


                    break
else:
print(" Let us try again!")
except ValueError: # <-- exception. handle it. loops because of while True
print("Not a valid alpha value, let's try that again")
return alpha_value

#---------- End of find_the_right_alpha function-----------------


Этот комментарий станет ненужной, когда вы изменить код в нескольких функциях.


alpha_value=find_the_right_alpha() # function call to determine alpha

t_predict=len(t)-1
def smoothing_predict(t_predict):
y=exponential_smoothing(p,alpha_value)
smooth_predicted=round((alpha_value*p[t_predict]+ (1-alpha_value)*y[t_predict]),3)
display_value=print(" The smoothing predicted value for time {} is {}".format(t_predict+2,smooth_predicted))
return display_value

smoothing_predict(t_predict)

# -------------- Regression time--------------

def calc_mean(t):
total_sum=0
for i in range(0,len(t)):
total_sum+=t[i]
result=total_sum/len(t)
return result


В дополнение к for i in range анти-паттерн, эта функция без надобности неэффективным. Смотрите, если вы можете выяснить, почему.

Кроме того, я знаю, что вы избегаете специальных библиотек вычисления, но вы действительно должны быть с использованием питон встроенный sum() здесь.


def calc_coefficients(t,p):

sum_xy_deviation=0
sum_xsquared_deviation=0

for i in range(0,len(t)):


То же самое. На этот раз вы будете хотеть использовать zip() выполнять работы на два списка одинаковой длины.


        sum_xy_deviation+=(t[i]-calc_mean(t))*(p[i]-calc_mean(p))

sum_xsquared_deviation+=pow(t[i]-calc_mean(t),2)


Почему повторные вызовы calc_mean(t)? Он не собирается меняться.


    beta=float(sum_xy_deviation/sum_xsquared_deviation)
alpha=calc_mean(p)-beta*calc_mean(t)
coefficients={'alpha':round(alpha,3), 'beta':round(beta,3)}
return coefficients

def graph_regression_line(regression_formula,t):
t=np.array(t)
phat=regression_formula(t)
plt.title('Regression Line and original data scatter plot')
plt.scatter(t, p,c='b')
plt.plot(t,phat)
plt.show()


Это хорошо, у вас есть все ваши построения кода в одну функцию.


def regression_formula(t):
coefficients=calc_coefficients(t,p)
return coefficients['alpha']+t*coefficients['beta']
def calc_r_square(t,p):
SSR,SST=0,0 # SSR is regression sum of squares. SST is total sum of squares

Это действительно не больно, чтобы иметь более длинные имена переменных. Это действительно не займет много времени, чтобы ввести их, и большинство редакторов будет их автозаполнение для вас. Комментарий должен объяснить, какие переменные используются для того, чтобы не расширять аббревиатуру.


    p_hat=[]
mean_price=calc_mean(p)
coefficients=calc_coefficients(t,p)
for i in range(0,len(t)):
p_hat.append(coefficients['alpha']+coefficients['beta']*t[i])
SSR+=pow(p_hat[i]-mean_price,2)
SST+=pow(p[i]-mean_price,2)
r_squared=round(SSR/SST,3)
display_value=print(" The R-Squared value is {}".format(r_squared))

Это очень странный способ использовать print().


    return display_value

t_predict=len(t)-1
def regression_predict(t_predict):
coefficients=calc_coefficients(t,p)
predicted=round((coefficients['alpha']+t_predict*coefficients['beta']),3)
display_value= print(" The regression predicted value for time {} is {}".format(t_predict+2,predicted))
return display_value
#-----------------------Displaying the output of our regression analysis --------------
graph_regression_line(regression_formula,t)
print("\n")
calc_r_square(t,p)
print("\n")
regression_predict(t_predict)
print("----------------")
print("The actual predicted value for time 9 is 3.32")
print("----------------")


1
ответ дан 5 марта 2018 в 09:03 Источник Поделиться