1
\$\begingroup\$

I want to perform some calculations over rolling periods of a pandas DataFrame and to abstract all this in a dedicated class. The job of the class below is simply, given backward and forward looking parameters to slice a column, perform some calculations and append the results as new columns of the original DataFrame.

I implemented the following:

import pandas as pd
import numpy as np
import random
random.seed(0)
np.random.seed(0)


class RollingEvaluator:

    def __init__(self, backward_window_size, forward_window_size):
        self.backward_window_size_ = backward_window_size
        self.forward_window_size_ = forward_window_size

    def run(self, data, column_name, func):

        n_rows = data.shape[0]
        output = []
        for i in range(self.backward_window_size_, n_rows-self.forward_window_size_):
            data_slice = data.iloc[(
                i-self.backward_window_size_):(i+1+self.forward_window_size_)]
            res = func(data_slice[column_name].values)
            current_row = {**res,
                           **data.iloc[i]}
            output.append(current_row)

        return pd.DataFrame(output)


if __name__ == "__main__":

    def custom_function(l):
        return {"Percentage (custom)": l[-1] / l[0] - 1}

    data = pd.read_csv("AAPL.csv", nrows=10)
    re = RollingEvaluator(1, 0)

    print(data)
    res = re.run(data, "Adj Close", custom_function)

    res["Percentage (default)"] = res["Adj Close"].pct_change()
    print(res)

Is there a more pythonic / pandas oriented way to do this ?

The data looks like:

Date,High,Low,Open,Close,Volume,Adj Close
2000-01-03,1.0044642686843872,0.9079241156578064,0.9363839030265808,0.9994419813156128,535796800.0,0.8594232797622681
2000-01-04,0.9877232313156128,0.9034598469734192,0.9665178656578064,0.9151785969734192,512377600.0,0.786965012550354
2000-01-05,0.9871651530265808,0.9196428656578064,0.9263392686843872,0.9285714030265808,778321600.0,0.7984815835952759
2000-01-06,0.9553571343421936,0.8482142686843872,0.9475446343421936,0.8482142686843872,767972800.0,0.7293821573257446
2000-01-07,0.9017857313156128,0.8526785969734192,0.8616071343421936,0.8883928656578064,460734400.0,0.7639315724372864
2000-01-10,0.9129464030265808,0.8459821343421936,0.9107142686843872,0.8727678656578064,505064000.0,0.7504956722259521
2000-01-11,0.8872767686843872,0.8080357313156128,0.8565848469734192,0.828125,441548800.0,0.7121071815490723
2000-01-12,0.8526785969734192,0.7723214030265808,0.8482142686843872,0.7784598469734192,976068800.0,0.6694000959396362
2000-01-13,0.8816964030265808,0.8258928656578064,0.8436104655265808,0.8638392686843872,1032684800.0,0.7428181767463684
2000-01-14,0.9129464030265808,0.8872767686843872,0.8928571343421936,0.8967633843421936,390376000.0,0.7711297273635864
\$\endgroup\$
3
  • \$\begingroup\$ Why would you have custom_function at all when pct_change does the exact same thing, only vectorised? \$\endgroup\$
    – Reinderien
    Jan 14 at 3:13
  • \$\begingroup\$ Well, the custom_function was just an illustration of what I can do, the point of percentage was to make sure that I can reproduce the pct_change function. I actually use this class to fit models on slices of the data \$\endgroup\$
    – RUser4512
    Jan 14 at 9:11
  • \$\begingroup\$ Ok, but Code Review doesn't operate on illustrations - please show your actual use case \$\endgroup\$
    – Reinderien
    Jan 14 at 13:20

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.