I have a vector of values vals
, a same-dimension vector of frequencies freqs
, and a set of frequency values pins
.
I need to find the max values of vals
within the corresponding interval around each pin (from pin-1 to pin 1). However, the intervals merge if they overlap (e.g., [1,2] and [0.5,1.5] become [0.5,2]).
I have a code that (I think) works, but I feel is not optimal at all:
import numpy as np
np.random.seed(666)
freqs = np.linspace(0, 20, 50)
vals = np.random.randint(100, size=(len(freqs), 1)).flatten()
print(freqs)
print(vals)
pins = [2, 6, 10, 11, 15, 15.2]
# find one interval for every pin and then sum to find final ones
islands = np.zeros((len(freqs), 1)).flatten()
for pin in pins:
island = np.zeros((len(freqs), 1)).flatten()
island[(freqs >= pin-1) * (freqs <= pin 1)] = 1
islands = island
islands = np.array([1 if x>0 else 0 for x in islands])
print(islands)
maxs = []
k = 0
idxs = []
for i,x in enumerate(islands):
if (x > 0) and (k == 0): # island begins
k = 1
idxs.append(i)
elif (x > 0) and (k > 0): # island continues
pass
elif (x == 0) and (k > 0): # island finishes
idxs.append(i)
maxs.append(np.max(vals[idxs[0]:idxs[1]]))
k = 0
idxs = []
continue
print(maxs)
Which gives maxs=[73, 97, 79, 77]
.
CodePudding user response:
Here's some optimizations for your code. There are many numpy functions that make your life easier, get to know them and use them ;). I tried commenting my code to make it as understandable as possible, but let me know if anything is unclear!
import numpy as np
np.random.seed(666)
freqs = np.linspace(0, 20, 50)
vals = np.random.randint(100, size=(len(freqs), 1)).flatten()
print(freqs)
print(vals)
pins = [2, 6, 10, 11, 15, 15.2]
# find one interval for every pin and then sum to find final ones
islands = np.zeros_like(freqs) # in stead of: np.zeros((len(freqs), 1)).flatten()
for pin in pins:
island = np.zeros_like(freqs) # see above comment
island[(freqs >= pin-1) & (freqs <= pin 1)] = 1 # "&" makes it more readable
islands = island
# in stead of np.array([1 if x>0 else 0 for x in islands])
islands = np.where(islands > 0, 1, 0) # read as: where "islands > 0" put a '1', else put a '0'
# compare each value with the next to get island/sea transistions (islands are 1's seas are 0's)
island_edges = islands[:-1] != islands[1:]
# split at the edges ( 1 to account for starting at the 1 index with comparisons
# islands_and_seas is a list of 'seas' and 'islands'
islands_and_seas = np.split(islands, np.where(island_edges)[0] 1)
# do the same as above but on the 'vals' array
islands_and_seas_vals = np.split(vals, np.where(island_edges)[0] 1)
# get the max values for the seas and islands
max_vals = np.array([np.max(arr) for arr in islands_and_seas_vals])
# create an array where the islands -> True, and seas -> False
islands_and_seas_bool = [np.all(arr) for arr in islands_and_seas]
# select only the max values of islands with
maxs = max_vals[islands_and_seas_bool]
print(maxs)