Is there a way to return float or integer from a conditional True/False

Viewed 131
n_level = range(1, steps + 2)

steps is user input, using multi-index dataframe

    df = {'crest': [754, 755, 762, 785], 'trough': [752, 725, 759, 765], 'L1T': [761, 761, 761, 761], 'L2T': [772, 772, 772, 772], 'L3T': [783, 783, 783, 783], 'L4T': [794, 794, 794, 794], 'L1M': [740, 740, 740, 740], 'L2M': [729, 729, 729, 729], 'L3M': [718, 718, 718, 718], 'L4T': [707, 707, 707, 707]}


    for i in n_level:
        if df['Crest'] >= df[f'L{i}T']:
            df['Marker'] = i
        elif df['Trough'] <= df[f'L{i}M']:
            df['Marker'] = -i
        else:
            df['Marker'] = 0

I am expecting below df with the col marker

    df = {'crest': [754, 755, 762, 785], 'trough': [752, 725, 759, 765], 'L1T': [761, 761, 761, 761], 'L2T': [772, 772, 772, 772], 'L3T': [783, 783, 783, 783], 'L4T': [794, 794, 794, 794], 'L1M': [740, 740, 740, 740], 'L2M': [729, 729, 729, 729], 'L3M': [718, 718, 718, 718], 'L4T': [707, 707, 707, 707], 'Marker': [0, -2, 1, 3]}, 

The if statement is returning True or False, using that can we convert it to the ith Value (+/-)

what I need is another col df['Marker'], which will measure if the crest or trough crossed L{i}T or L{i}M, any breach on the upside in case of the crest and breach on the downside in case of the trough

Sample Dataframe

2 Answers

this can be achieved easily using binary search, there are many ways to apply that(NumPy, bisect). I would recommend the library bisect.

Added Buu for the Crest and See for the Trough, so that code and differentiate the segments. You can choose anything

def marker_up(row):
    n_row = [row[col] for col in columns if "Buu" in col]
    n_high = row['Crest']
    if n_high in n_row:
        q = bs.bisect_left(n_row, n_high)
        q = max(0, q)
        return q
    else:
        q_mod = bs.bisect_left(n_row, n_high)
        q_mod -= 1
        q_mod = max(0, q_mod)
        return q_mod

Marker_up = df.apply(marker_up, axis=1)

def marker_down(row):
    n_row = [row[col] for col in columns if "See" in col]
    n_low = row['Trough']
    if n_low in n_row:
        q = bs.bisect_left(n_row, n_low)
        q = q - len(n_row)
        return q
    else:
        q_mod = bs.bisect_left(n_row, n_low)
        q_mod = q_mod - len(n_row)
        return q_mod

Marker_down = df.apply(marker_down, axis=1)
df['Marker'] = Marker_up + Marker_down

return df

Don't use iloc, dict or iterrrows if you have large df. A vectorized form will help to run code faster.

you can you Numpy searchsorted the list should be an array of values for the row.

df['Marker'] = np.searchsorted(df['Crest'], list)
Related