Search code examples
pandasdata-sciencepython-3.7physics

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


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


Solution

  • 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.