I am trying to configure my PuLP problem to ensure an employee does not have more than 10 hours per day.
The employee variable I have set up is:
cost = []
vars_by_shift = defaultdict(list)
for employee, info in employees.iterrows():
for shift in info['availability']:
employee_var = pl.LpVariable("%s_%s" % (employee, shift), 0, 1, pl.LpInteger)
vars_by_shift[shift].append(employee_var)
cost.append(employee_var * info['base_rate'])
My objective is to minimize cost:
prob = pl.LpProblem("scheduling", pl.LpMinimize)
prob += sum(cost)
An example of my shift data is:
"76749": {
"start_date": "2019-08-14",
"start_time": "08:00",
"end_date": "2019-08-14",
"end_time": "12:00",
"duration": 4,
"number_positions": 1
},
"76750": {
"start_date": "2019-08-14",
"start_time": "13:00",
"end_date": "2019-08-14",
"end_time": "20:00",
"duration": 7,
"number_positions": 1
}
An employee sometimes can be assign two short shifts on the same day. I want to ensure the total hours an employee is rostered any given day does not exceed 10 hours. How would model that constraint?
If I understand your implementation you have a set of binary decision variables:
pl[e, s]
With one variable for each e in employees and for each s in shifts
I'm also assuming there is (or you can easily create) a list days which includes the list of days covered by the shifts, and you can easily write a function which returns the number of hours of a shift in a particular day.
You then want to add constraints:
for e in employees:
for d in days:
lpSum([pl[e, s]*n_hours_of_shift_in_day(s, d) for s in shifts]) <= 10.0
Where the function n_hours_of_shift_in_day(s, d) is a function which returns the number of hours of shift s in day d, so for example if your shift was:
"76749": {
"start_date": "2019-08-14",
"start_time": "18:00",
"end_date": "2019-08-15",
"end_time": "19:00",
"duration": 25,
"number_positions": 1
}
Then n_hours_of_shift_in_day("76749", "2019-08-14") would return 5.0, and n_hours_of_shift_in_day("76749", "2019-08-15") would return 19.0.
Also your example shift seems to use a 12-hour clock format with no indication of AM or PM which might give you some problems.
well, you need a grouping variable for the hours, is it considered the start_date as the day you dont want to assign more than 10 hours?
if the answer is yes
then you need sth like this....
emp in employees.iterrows():
for d in dates:
prob.addConstrain(pl.lpSum([ employee_var*vars_by_shift[s][hours] if vars_by_shift[s]==d else 0 for s in shifts]) < 10)
Related
I am building a html form where it will query the MongoDB and retrieve the entire record based on the year.
How can I query only the year?
Something along the line in SQL:
select * from database where date == '2021'
How to do the equivalent in MongoDB?
If you are storing the dates as Date you have two options:
First one is to create dates and compare (not tested in python but should work):
import datetime
start = datetime.datetime(2021, 1, 1)
end = datetime.datetime(2022,1,1)
db.find({date: {$gte: start, $lt: end}});
Note the trick here is to query dates between the desired year, like this example
The other way is using aggregation like this:
Here you are getting the year using $year and comparing with your desired value.
db.collection.aggregate([
{
"$match": {
"$expr": {
"$eq": [
{
"$year": "$date"
},
2021
]
}
}
}
])
Example here
The JSON format is like this. I am performing calculations on the data for eg date 1st Jan 2017. That 1st Jan in 2017 would be a Sunday for example. But in 2018, that 1st Jan 2018 will be a Monday. Now I know that each year these days move 1 forward. But my calculations are based on the days, for eg, i need to compare values of Mondays with Mondays not with a weekend because the factor i will calculate will be wrong if a weekday is compared to a weekend.
import plotly.graph_objects as go
import numpy as np
import json
with open('test.json') as json_file:
data = json.load(json_file)
X, Y = [], []
for item in data['Elements']:
for sub_item in item['TimeSpans']:
if (item['Date'].startswith("2017")):
X.append(sub_item['TimeSpan']+" "+ item['Date']) #2017
Y.append(sub_item['Value'])
X1, Y1 = [], []
for item in data['Elements']:
for sub_item in item['TimeSpans']:
if (item['Date'].startswith("2018")):
X1.append(sub_item['TimeSpan']+" "+ item['Date']) #2018
Y1.append(sub_item['Value'])
diff = []
for i in range(len(Y)):
if(Y[i]==0):
diff.append(1)
if(Y1[i]==0):
diff.append(1)
else:
var = Y[i] / Y1[i]
diff.append(var)
#print(diff[0])
XP=[]
YP=[]
for k in range(len(Y1)): #len(diff)
if (Y1[k]==0):
YP.append(Y1[k])
if (diff[k]==0):
YP.append(Y1[k])
var2 = Y1[k]/diff[k]
YP.append(var2)
for item in data['Elements']:
for sub_item in item['TimeSpans']:
if (item['Date'].startswith("2019")):
XP.append(sub_item['TimeSpan']+" "+ item['Date']) #2019
{
"SpotKey": "79",
"SpotName": "ELIX",
"Denomination": "eur/mwh",
"Elements": [
{
"Date": "2017-01-01T00:00:00",
"Base": 36.8696,
"Peak": 36.0125,
"TimeSpans": [
{
"TimeSpan": "00:00-01:00",
"Value": 46.43
},
{
"TimeSpan": "01:00-02:00",
"Value": 42.43
}
]
},
{
"Date": "2017-01-02T00:00:00",
"Base": 53.7413,
"Peak": 63.0317,
"TimeSpans": [
{
"TimeSpan": "00:00-01:00",
"Value": 41.18
},
{
"TimeSpan": "01:00-02:00",
"Value": 37.34
}
]
}
]
}
So here I am trying to predict the data from from 2019 and visualizing it using plotly. How do i overcome this date with day matching problem?
Date=[]
for item in data['Elements']:
for sub_item in item['TimeSpans']:
if (item['Date'].startswith("2017")):
iso_day = datetime.datetime.strptime(item['Date'], '%Y-%m-%dT%H:%M:%S').isocalendar() #Moving Date Logic
iso_day[2] == 1
Date.append(iso_day)
for loop in range(len(Date)):
print(Date[loop])
This is a common problem for fiscal years. It has been defined in ISO 8601 since 1971 as the ISO week date convention (*). In this convention, a day is represented as a triple (year, week number, weed day number). The first week of a year (week 01) is (equivalent definitions):
the first week with a majority (4 or more) of its days in January.
the one for which first day is the Monday nearest to 1 January.
the one that has 4 January in it.
The good news is that Python datetime module knows about it:
date.isocalendar() :
Return a 3-tuple, (ISO year, ISO week number, ISO weekday).
If you convert your dates with that:
iso_day = datetime.datetime.strptime(item['Date'], '%Y-%m-%dT%H:%M:%S').isocalendar()
iso_day[0] will be the appropriate year, and you should control that first days observes iso_day[2] == 1 to start with a Monday and eventually ignore previous days.
References on wikipedia:
ISO 8601
ISO week date
I'm writing a function that takes a vendorID and a date_time string that should return if a vendorID can deliver if time/date doesn't overlap for a delivery to be done.
I'm trying to compare datetime strings inside a dict that has a list of nested dict with various elements including the datetime string. I want to compare each datetime string from each nested dict inside the list and check if the date is different and then compare if a certain amount of minutes have been passed.
Tried to loop through dict and items and use datetime.strptime() to parse the datetime string but I'm not sure how to compare the dates inside the list of dicts when iterating through the dict items.
dict = {
"results": [
{
"vendor_id": 1,
"client_id": 10,
"datetime": "2017-01-01 13:30:00"
},
{
"vendor_id": 1,
"client_id": 40,
"datetime": "2017-01-01 14:30:00"
}
Hope this helps you. Using dict as you have advised;
dict = {
"results": [
{
"vendor_id": 1,
"client_id": 10,
"datetime": "2017-01-01 13:30:00"
},
{
"vendor_id": 1,
"client_id": 40,
"datetime": "2017-01-01 14:30:00"
}]}
Having some date times, use the for loop and test if;
somedatetime1 = '2017-01-01 14:00:00'
somedatetime2 = '2017-01-01 15:00:00'
for d in dict['results']:
if d['datetime'] < somedatetime1:
print('somedatetime1 :: Vendor {} Client {} DateTime {}'.format(d['vendor_id'], d['client_id'], d['datetime']))
if d['datetime'] < somedatetime2:
print('somedatetime2 :: Vendor {} Client {} DateTime {}'.format(d['vendor_id'], d['client_id'], d['datetime']))
Returns;
somedatetime1 :: Vendor 1 Client 10 DateTime 2017-01-01 13:30:00
somedatetime2 :: Vendor 1 Client 10 DateTime 2017-01-01 13:30:00
somedatetime2 :: Vendor 1 Client 40 DateTime 2017-01-01 14:30:00
I would think it would be easier to do this in pandas as you can groupby vendor ID and do operations only for that vendor.
from sklearn.metrics.pairwise import euclidean_distances
import pandas as pd
import numpy as np
df = pd.DataFrame() #Initiate
grp = df.from_dict(dict['results']).groupby('vendor_id') #Convert into df and groupby vendor id, should be useful when u have more than one vendor
dct = {}
for group in grp.groups:
df_vid = grp.get_group(group) # Obtain data for that vendor
df_vid['datetime'] = pd.to_datetime(df_vid['datetime'])
ab = np.array(df_vid['datetime'])
dist = euclidean_distances(ab.reshape(-1, 1), ab.reshape(-1, 1)) # Find distance matrix
dct[group] = dist # Assign it to dict by vendor ID as key
You can change time of string type to datetime type.
And, Just you use -.
After that, You can use timedelta what is returned by time_diff function if you handle the time more.
If you want to get minutes, use seconds attribute.
from datetime import datetime
def time_diff (a, b):
return a - b
dict = {
"results": [
{
"vendor_id": 1,
"client_id": 10,
"datetime": "2017-01-01 13:30:00"
},
{
"vendor_id": 1,
"client_id": 40,
"datetime": "2017-01-01 14:30:00"
}
]
}
for r in dict['results']:
r['datetime'] = datetime.strptime(r['datetime'], '%Y-%m-%d %H:%M:%S')
print (int(time_diff(dict['results'][1]['datetime'], dict['results'][0]['datetime']).seconds/60))
I'm new to Python and API and am trying to start with some basics like making a list/plot of old BTC prices. I imported the Coinbase Wallet Client and used client.get_historic_prices(), which gave me a list of the price at midnight UTC for 365 days.
How can I adjust the parameters to get different date ranges and data resolution, for example each minute for two years? Is there a way to search the historic values of buy, sell, and spot separately?
from coinbase.wallet.client import Client
hist_price = client.get_historic_prices()
xx=[]
yy=[]
for ii in range(365):
xx.append(ii*-1) # x coordinate being "days ago"
yy.append(float(hist_price['prices'][ii]['price']))
Returns (this is just from a print statement of print(hist_price['prices'][0:3]). So it's midnight once a day.
prices
length = 365
{
"price": "974.39",
"time": "2017-02-01T00:00:00Z"
}
{
"price": "944.29",
"time": "2017-01-31T00:00:00Z"
}
{
"price": "920.47",
"time": "2017-01-30T00:00:00Z"
}
Get_historic_prices is not clearly documented anywhere. This is a mini guide of what I have managed to discover about it and its usage. It's not much but it should be somewhere.
get_historic_prices supports one argument called period which can take the following values:
hour
day
week
month
year
all
Each of them except all returns approximately a list of 360 price points distributed more or less uniformly in the previous hour (day, week, month, year respectively).
all returns a list of price points one for each day at 00:00:00 UTC (i think).
get_historic_prices should also support a currency_pair argument as do the get_buy_price, get_sell_price, and get_spot_price do. Unfortunately, although I have submitted a PR, it has not been merged yet.
Im struggling with localized datetimes.
All the dates stored in mongo are converted to UTC automatically, so we have to localized them after retrieving them. Im fine with that, but..
In the case where I make a query to group records by date, meaning YYY-MM-DD, problems arise. Since my local time is GMT-3, any record with time above 21:00 will be stored in mongo as 00:00, thus corresponding to the following day. When grouping by date in the query i'd be getting records in the wrong day, and wont be able to recover from that because i lose the hour details.
Is there a way of localizing the dates in the groupby command in a pymongo query?
Here's the code:
def records_by_date():
pipeline = []
pipeline.append({"$group": {
"_id": {
"$concat": [
{"$substr": [{"$year": "$date"}, 0, 4]},
"-",
{"$substr": [{"$month": "$date"}, 0, 2]},
"-",
{"$substr": [{"$dayOfMonth": "$date"}, 0, 2]}
]},
"record_id": {"$push": "$_id"},
"count": {"$sum": 1}
}})
pipeline.append({"$project": {
"_id": 0,
"date": "$_id",
"record_id": 1,
"count": 1
}})
pipeline.append({"$sort": {"date": 1}})
return self.collection.aggregate(pipeline)['result']
If I add the hour details, I could verify the records after that, but then I wouldn't be grouping by date.
Any ideas?