title: How to optimise time series based resource allocation using python
body: <p>I have n number of processes that needs to be assigned to unknown number of resources.
  Input data is in format:</p>
  <pre><code>Start Time-Stop Time-LocationProcessStart-LocationProcessEnd
  </code></pre>
  <p>I also have constraints for resources based on time and location like minimum time between two processes or location based constraints.</p>
  <p>Is there any optimisation model technique that can optimise number of resources and their utilisation.
  I’ll post data if needed but I’m looking for methods using Python.
  For reference, my data is something like time table of buses and i need to adhere to some work rules.
  So if someone could help me out, it’ll be so great.!</p>
  <p>--EDIT 1--
  Dummy Data</p>
  <p><a href="https://i.stack.imgur.com/SmdwO.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/SmdwO.png" alt="Dummy" /></a></p>
  <p>I only have this data, there are number of constraints like total working hours, total running hours, breaks etc.
  I need to include all constraints, I need to find minimum amount of resources which are required to carry all trips, I've seen optimization models but there we know number of resources whereas here we need to find and optimize it.</p>
  <p>--EDIT2--</p>
  <pre><code>while finaldata.size !=0:
  x=0
  y=0
  print('Creating Duty :',1 if duty.size==0 else (duty['Duty_No'].max() + 1))
  finaldata.sort_values('Trip_Start',inplace=True)
  finaldata.reset_index(drop=True,inplace=True)
  while x &lt; len(finaldata.index):
      finaldata.sort_values('Trip_Start',inplace=True)
      finaldata.reset_index(drop=True,inplace=True)
      duty2 = pd.DataFrame()
          if (finaldata['LocationPick'][x] == 'SHD') | (finaldata['LocationPick'][x] == 'DSG'):
          trip = finaldata.iloc[x].copy()
          trip['Duty_No'] = 1 if duty.size==0 else (duty['Duty_No'].max() + 1)
          trip['Sign_On'] = finaldata['Trip_Start'][x] - datetime.timedelta(minutes=15)
          trip['Sign_Off'] = finaldata['Trip_Start'][x] + datetime.timedelta(hours=7,minutes=45)
          trip['Total_Run'] = finaldata['Trip_Duration'][x]
          finaldata.drop(finaldata.index[x],inplace=True)
          finaldata.reset_index(drop=True,inplace=True)
          finaldata.sort_values(['Trip_Start'],inplace=True)
          duty2 = duty2.append(trip)
          y=0
          #rest = datetime.timedelta(minutes=55)
          rest = random.choice([datetime.timedelta(minutes=55),datetime.timedelta(minutes=25)])
          ass=0
          while y &lt; len(finaldata.index):
              ass=0
              if (finaldata['LocationRelieve'][y] != 'SHD') &amp; ((duty2['Total_Run'].max() + finaldata['Trip_Duration'][y]) &lt;= datetime.timedelta(hours=3,minutes=30)):
                  y=y+1
                  continue                
              if (finaldata['Trip_Start'][y] - trip['Trip_End'] &gt;= rest) &amp; (finaldata['LocationPick'][y]==trip['LocationRelieve']) &amp; ((duty2['Total_Run'].max() + finaldata['Trip_Duration'][y]) &lt;= datetime.timedelta(hours=5,minutes=50)) &amp; ((trip['Sign_Off']-finaldata['Trip_End'][y]) &gt;= datetime.timedelta(minutes=10)):
                  trip = finaldata.iloc[y].copy()
                  trip['Total_Run'] = finaldata['Trip_Duration'][y]
                  trip['Sign_On'] = duty2['Sign_On'].max()
                  trip['Sign_Off'] = duty2['Sign_Off'].max()
                  trip['Duty_No'] = duty2['Duty_No'].max()
                  duty2['Total_Run'] = duty2['Total_Run'] + trip['Total_Run']
                  finaldata.drop(finaldata.index[y],inplace=True)
                  finaldata.reset_index(drop=True,inplace=True)
                  finaldata.sort_values(['Trip_Start'],inplace=True)    
                  duty2 = duty2.append(trip)
                  ass = 1
                  #rest = datetime.timedelta(minutes=25)
                  rest = datetime.timedelta(minutes=25) if rest==datetime.timedelta(minutes=55) else datetime.timedelta(minutes=55)
              y=(y+1) if ass==0 else 0
          duty2['Total_Run'] = duty2['Total_Run'].max()    
          duty=duty.append(duty2)
          del duty2 
          break
  x=x+1
  </code></pre>
  <p>This sort trips in ascending order of start time, For depot sign on time is few minutes more earlier, rest code block is same from checking pick location.</p>
  <p>Here's the Output:-</p>
  <p><a href="https://i.stack.imgur.com/lbJAQ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/lbJAQ.png" alt="Output1" /></a></p>
  <p>Looks good but see difference between SignOff and last trip's time and also total run, this creates issue as we move later like:</p>
  <p><a href="https://i.stack.imgur.com/0jcW6.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/0jcW6.png" alt="Last Trips" /></a></p>
  <p>Resource can run upto 5:30 hrs a day which can extend a bit if required for like 20 minutes but not exceeding SignOff time.</p>
  <p>There are some good assignments too but this is so random so I need to figure out better approach.
  <a href="https://i.stack.imgur.com/5vukL.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/5vukL.png" alt="Ideal Case" /></a></p>
  <p>Looking forward to alternates I can try..!</p>
  <p>--EDIT3--</p>
  <pre><code>Train_No LocationPick Trip_Start TrainSBC LocationRelieve Trip_End Trip_Duration
  101     DEPOT   04:25   0   SHD 06:24   01:59
  104     DEPOT   04:44   0   SHD 06:39   01:55
  102     SHDSDG  04:53   0   SHD 07:09   02:16
  105     RISDG   05:00   0   SHD 07:09   02:09
  109     DEPOT   05:00   0   SHD 06:55   01:54
  106     NBAASDG 05:05   0   SHD 07:23   02:18
  103     DEPOT   05:09   0   SHD 07:16   02:07
  107     DEPOT   05:15   0   SHD 06:34   01:19
  110     NBAASDG 05:20   0   SHD 07:38   02:18
  108     DEPOT   05:25   0   SHD 06:41   01:16
  111     DEPOT   05:30   0   SHD 06:48   01:18
  118     DEPOT   05:34   0   SHD 07:30   01:56
  112     DEPOT   05:35   0   SHD 06:55   01:20
  114     NBAASDG 05:35   0   SHD 07:52   02:17
  113     DEPOT   05:40   0   SHD 07:45   02:05
  115     DEPOT   05:45   0   SHD 07:02   01:17
  117     DEPOT   05:57   0   SHD 07:17   01:20
  119     RISDG   05:57   0   SHD 08:00   02:02
  116     RI      06:07   0   SHD 07:45   01:37
  120     DEPOT   06:12   0   SHD 07:31   01:19
  101     SHD     06:24   0   SHD 08:49   02:24
  121     DEPOT   06:31   122 SHD 08:53   02:22
  123     SHDSDG  06:34   121 SHD 08:46   02:12
  107     SHD     06:34   0   SHD 08:57   02:23
  122     DEPOT   06:38   124 SHD 08:46   02:07
  104     SHD     06:39   0   SHD 09:04   02:24
  108     SHD     06:41   0   SHD 09:04   02:23
  124     DEPOT   06:45   125 SHD 08:53   02:07
  111     SHD     06:48   0   SHD 09:13   02:25
  125     DEPOT   06:53   126 SHD 09:00   02:07
  109     SHD     06:55   0   SHD 09:18   02:23
  112     SHD     06:55   0   SHD 09:18   02:23
  126     DEPOT   07:00   127 SHD 09:07   02:07
  115     SHD     07:02   0   SHD 09:26   02:23
  122     DSG     07:07   0   SHD 08:38   01:31
  127     DEPOT   07:07   128 SHD 09:14   02:07
  </code></pre>