简体   繁体   中英

how to use mapping instead of if-else to improve the speed of program in python?

I had written a program to calculate some rates based on the frequency and predefined rate. When I completed my program someone told me after seeing my code that you should try to apply mapping concepts instead of so many if-else statements. I didn't know about mapping concepts so I read about it from the internet and I found it very interesting, as it is acting like Hash Function in our program which can improve the efficiency of our code to O(1) rather than O(n). But I am having some trouble while applying this. sample data(in actual there are total 36288 rows and 2 columns):

frequency   acp
49.96       324.50
49.99       324.50
49.98       324.50
50.00       324.50
49.98       324.50
49.94       324.50
49.96       324.50
49.96       324.50
49.93       324.50
49.95       324.50
50.00       324.50
49.99       324.50
49.99       324.50
49.98       324.50
49.99       324.50
50.03       324.50
49.98       324.50
50.02       324.50
49.99       324.50
49.98       324.50
49.98       324.50
49.99       324.50
49.95       324.50
49.96       324.50

My old program:

import pandas as pd
import time
start = time.time()
hourlyDF = pd.read_excel("main_input.xlsx")
frequency = hourlyDF['frequency']
acp = hourlyDF['acp']
results = []
for each, acp in zip(frequency, acp):
            if each >= 50.05:
                rate = 0
                results.append(rate)
            elif each < 50.05 and each >= 50.04:
                rate = acp * 0.2
                results.append(rate)
            elif each < 50.04 and each >= 50.03:
                rate = acp * 0.4
                results.append(rate)
            elif each < 50.03 and each >= 50.02:
                rate = acp * 0.6
                results.append(rate)
            elif each < 50.02 and each >= 50.01:
                rate = acp * 0.8
                results.append(rate)
            elif each < 50.01 and each >= 50.00:
                rate = acp
                results.append(rate)
            elif each < 50.00 and each >= 49.99:
                rate = 50 + 15 * acp / 16
                results.append(rate)
            elif each < 49.99 and each >= 49.98:
                rate = 100 + 14 * acp / 16
                results.append(rate)
            elif each < 49.98 and each >= 49.97:
                rate = 150 + 13 * acp / 16
                results.append(rate)
            elif each < 49.97 and each >= 49.96:
                rate = 200 + 12 * acp / 16
                results.append(rate)
            elif each < 49.96 and each >= 49.95:
                rate = 250 + 11 * acp / 16
                results.append(rate)
            elif each < 49.95 and each >= 49.94:
                rate = 300 + 10 * acp / 16
                results.append(rate)
            elif each < 49.94 and each >= 49.93:
                rate = 350 + 9 * acp / 16
                results.append(rate)
            elif each < 49.93 and each >= 49.92:
                rate = 400 + 8 * acp / 16
                results.append(rate)
            elif each < 49.92 and each >= 49.91:
                rate = 450 + 7 * acp / 16
                results.append(rate)
            elif each < 49.91 and each >= 49.90:
                rate = 500 + 6 * acp / 16
                results.append(rate)
            elif each < 49.90 and each >= 49.89:
                rate = 550 + 5 * acp / 16
                results.append(rate)
            elif each < 49.89 and each >= 49.88:
                rate = 600 + 4 * acp / 16
                results.append(rate)
            elif each < 49.88 and each >= 49.87:
                rate = 650 + 3 * acp / 16
                results.append(rate)
            elif each < 49.87 and each >= 49.86:
                rate = 700 + 2 * acp / 16
                results.append(rate)
            elif each < 49.86 and each >= 49.85:
                rate = 750 + acp / 16
                results.append(rate)
            elif each < 49.85:
                rate = 800
                results.append(rate)
print("rate: ", results)
print("\ntime taken: ", time.time()-start)

My Approach(Actually I don't know exactly how to approach it):

import pandas as pd
import time
start = time.time()

hourlyinputDF = pd.read_excel("main_input.xlsx")

frequency = hourlyinputDF['frequency']
acp = hourlyinputDF['acp']

#Creating a Mapping Function
for rate in acp:
    frequencyMapFunction = {
        50.05: 0, 50.04: rate*0.2, 50.03: rate*0.4, 50.02: rate*0.6, 50.01: rate*0.8, 50.00: rate, 49.99: 50+15*rate/16,
        49.98: 100+14*rate/16, 49.97: 150+13*rate/16, 49.96: 200+12*rate/16, 49.95: 250+11*rate/16, 49.94: 300+10*rate/16,
        49.93: 350+9*rate/16, 49.92: 400+8*rate/16, 49.91: 450+7*rate/16, 49.90: 500+6*rate/16, 49.89: 550+5*rate/16,
        49.88: 600+4*rate/16, 49.87: 650+3*rate/16, 49.86: 700+2*rate/16, 49.85: 750+rate/16
        #less than 49.85 is not included because idk how to include it
                            }

for i in frequency:
    print("rate: ", frequencyMapFunction[i])

print("time taken: ", time.time()-start)

The Old program is completely working but I want to understand how can I apply mapping concepts to my particular case. Thanks

Mapping is great when you have one set of values and need to associate each with some other value, in particular when there is no logic/pattern to the association.

Your problem fails this criteria on 2 counts:

  1. You do not have a "set of values" to map; you have a set of value ranges
  2. You do have patterns that can be exploited.

Thus, your rate calculation can be implemented like so:

def calc_rate( each, acp ):
    if each >= 50.05:
        return 0
    if each >= 50.01:
        return (5005 - floor(each*100)) * acp * 0.2
    if each >= 49.85:
        bkt = 5000 - floor(each*100)
        return 50*bkt + ((16-bkt) * acp / 16)
    return 800

You could replace the 2 formulae with mappings, but I frankly don't see the benefit of doing so.

When checking for equality, you can replace code fragments like that:

x = something_that_returns_int()

if x == 1:
  print('a')
elif x == 2:
  print('b')
elif x == 3:
  print('c')
else:
  print('unknown')

To that:

mapping = {
  1: 'a',
  2: 'b',
  3: 'c',
}

x = something_that_returns_int()

# pick one of them
letter = mapping[x]
letter = mapping.get(x, 'unknown')
try:
  letter = mapping[x]
except KeyError:
  letter = 'unknown'

print(letter)

If instead you use if , elif with > operators, you could loop through the mapping:

mapping_below = {
  10: 'below 10',
  20: 'between 10 and 20',
  30: 'between 20 and 30',
}

x = something_that_returns_int()
for key in mapping_below():
  if x < key:
    print(mapping_below[key])
    break
else:  # when break was never called, so we have looped through entire mapping
  print('above 30')

Hope this helps :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM