Jan Stuller
Jan Stuller

Reputation: 173

More “Pythonian” way to perform a nested loop through an array?

The code below tries to solve the following task: "Find the maximum price change over any 5-day rolling window, over 1000-day period".

By "any 5-day rolling window", I don't just mean "t_i + 5", but rather "t_i + j", where "i" varies from 1 to 1000 and "j" varies from 1 to 5.

I have tried to use Numpy native functions, but I still ended up using a "for-loop" for the inner iteration. Here goes the code:

prices = npr.random([1000,1])*1000

max_array = np.zeros([(prices.size-5),1])
for index, elem in np.ndenumerate(prices[:-5,:]):
    local_max = 0.0
    for i in range(1,6,1):
        price_return = prices[(index[0] + i),0] / elem
        local_max = max(local_max, price_return)
    max_array[index[0]] = local_max
global_max = np.amax(max_array)

Can I somehow eliminate the inner for loop and use Numpy vectorization (somehow) instead?

Also, I don't particularly like using "index[0]" to extract the actual index of the current loop from the tuple object that is returned into the variable "index" via the call:

for index, elem in np.ndenumerate(prices[:-5,:]):

Can that be also imporved?

Upvotes: 0

Views: 106

Answers (1)

DarrylG
DarrylG

Reputation: 17156

Using pandas rolling window for min and max

Allows computation without for loops

Inspired by Max in a sliding window in NumPy array

import pandas as pd
import numpy as np

# Generate Data
prices = np.random.random([1000,1])*1000
prices = prices.flatten()

# Pandas rolling window (max in 5 day period)
# Convert series back to numpy array
maxs = pd.Series(prices).rolling(5).max().dropna().to_numpy()

# Pandas rolling window (min in 5 day period)
# Convert series back to numpy array
mins = pd.Series(prices).rolling(5).min().dropna().to_numpy()

# Numpy subtraction to find max and min differnce
delta = maxs - mins

Results (show first 10 elements)

print('prices: ', prices[:10])
print('maxs: ', maxs[:10])
print('mins: ', mins[:10])
print('max-change: ', delta[:10])

Output (first 10 elements)

prices:  [416.67356904 244.29395291 325.50608035 102.67426207 794.36067353
 318.22836941 113.48811096 898.87130071 303.06297351 285.80963998]
maxs:  [794.36067353 794.36067353 794.36067353 898.87130071 898.87130071
 898.87130071 898.87130071 898.87130071 828.87148828 828.87148828]
mins:  [102.67426207 102.67426207 102.67426207 102.67426207 113.48811096
 113.48811096 113.48811096 285.80963998 285.80963998 106.4036413 ]
max-change:  [691.68641146 691.68641146 691.68641146 796.19703863 785.38318975
 785.38318975 785.38318975 613.06166073 543.06184831 722.46784698]

Upvotes: 1

Related Questions