How to convert time to some category?
For example, times between 17:30:13 and 19:30:13 should be categorized as "in the evening." Times between 12:00:12 and 13:00:12 should fall under "noon."
What is a good approach to do this in python?
If you want to use it for machine learning you normally want it to be a integer value, or transform it into a one-hot encoding.
To get the integer value you can integer divide on the hour:
from datetime import datetime,timedelta
values = [datetime.now() + timedelta(hours=i) for i in range(24)]
[value.hour // 6 for value in values]
yields:
[3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]
I didn't use any machine learning library. Wrote a function that returns a category
depending on what the lower bound hour of the day is.
Based on your example , I'd assume the lower bound hour does prioritize the category.
Maybe I'd like to understand the use case a bit better.
# hour can be some number from 0 to 23 which is also the lower bound hour
# in the mentioned interval
# 17:30:13- 19:30:13 should fall under "evening"
# 12:00:12-13:00:12 should fall under "noon"
# For 17:30:13- 19:30:13 , hour will be 17
# For 12:00:12-13:00:12 , hour will be 12
get_category(hour):
if hour < 12:
return "morning"
elif hour == 12:
return "noon"
elif hour > 12 and hour < 16:
return "evening"
else:
return "night"
You may need to name a function by yourself and customize the cutoff time.
import datetime
# test date
Testdate = datetime.datetime.now().time()
def GetDateCate (DateInput):
# name a cutoff date:
noon = datetime.time(12)
evening =datetime.time(18)
if Testdate <noon:
print('Morning')
elif Testdate <evening:
print('Afternoon')
else:
print('Night')
GetDateCate(Testdate)
Related
I need some help.
I have a dictionary, which represents measured data during 8 days every 15 minutes, but some measurements are missing. Keys are datetime objects:
datetime(year, month, date, hour, minute)
and values represent measured parameter. My aim is to obtain a new dictionary with keys, which represent only time of day, e.g.:
time(hour, minute)
and its values are lists of measurements, which were provided at the same time every day. So, instead of the first dictionary of length L, I want to obtain new dictionary of length L/8 where every value is a list of 8 numbers (sometimes less, if there is a missing value at one or two days). It is very simple problem for me, if there are no missing values, but with missing values my program returns some strange result. If somebody can provide an idea, it would be great! Here is my code (tec is my initial dictionary):
time_of_day = []
date = datetime(2020, 1, 13, 0, 0)
while date < datetime(2020, 1, 14, 0, 0):
time_of_day.append(date)
date = date + td(minutes = 15)
day_tec = dict.fromkeys(time_of_day, [])
for i in day_tec.keys():
j = 0
while j < 8:
try:
day_tec[i].append(tec[i + j * timedelta(days = 1)])
except Exception as e:
print(e)
pass
j = j + 1
print(day_tec)
print(day_tec) returns dictionary with datetime objects as a keys from datetime(2020, 1, 13, 0, 0) to datetime(2020, 1, 14, 0, 0) every 15 minutes, but its values are lists with the same length as an initial dictionary length.
You can use a defaultdict to get what you want. The code below will give you a dictionary where each key is a tuple of hour and minute, and each value is the recorded value in the tec dict.
from collections import defaultdict
day_tec = defaultdict(list)
for dt, value in tec.items():
tm = (dt.hour, dt.minute)
day_tec[tm].append(value)
print(day_tec)
i wanted to create a function that encodes the month of a date(time) object into a season. So for example, if we have 2 seasons and the fourth month the function would return 0 as encoding. My question is now how to create such a function that it is most efficient but also pythonic (less lines of code). I came up with 3 different approaches, the first one looks like this:
def seasonal_encoding(month: int, seasons):
assert 12 % seasons == 0, "Seasons must be in [1, 2, 3, 4, 6, 12]"
if seasons == 1:
return _one_season()
elif seasons == 2:
return _two_seasons(month)
elif seasons == 3:
return _three_seasons(month)
elif seasons == 4:
return _four_seasons(month)
elif seasons == 6:
return _six_seasons(month)
elif seasons == 12:
return _twelve_seasons(month)
where for example three_seasons looks like this:
def _three_seasons(month):
if month in range(1, 5):
return 0
elif month in range(5, 9):
return 1
elif month in range(9, 13):
return 2
This is so far the fastest approach i came up with, but as you can imagine this may work for
a season encoding, but if we want to encode other date(time) attributes, for example hours, this becomes cumbersome real fast. So i came up with a second solution which is a little slower but has less lines of code:
def for_loop_seasonal_encoding(month: int, seasons: int):
assert 12 % seasons == 0, "Seasons must be in [1, 2, 3, 4, 6, 12]"
if seasons != 12:
stepsize = int(12 / seasons)
for i in range(1, seasons+1):
if month in range((i-1) * stepsize + 1, i * stepsize + 1):
return i-1
else:
return month
I also had another solution with numpy before coming up with the for loop solution which i will add for reasons of completeness, but this was four times slower then the other solutions.
def numpy_seasonal_encoding(month: int, seasons):
assert 12 % seasons == 0, "Seasons must be in [1, 2, 3, 4, 6, 12]"
arr = np.array(range(1, 13))
reshaped_arr = arr.reshape(seasons, int(12 / seasons))
return np.where(reshaped_arr == month)[0][0]
So my Question would be: Has anyone of you an idea how to make this as fast as the if representation but with way less lines of codes in "pure" python (so without resorting to Cython, numba etc., external packages like numpy are ok)?
This is the link to the .py file
Python File that includes the function used for timing and the code. Thank you in advance for any help.
I have two dates between which I need to find out how many Mon- Fri are coming(except for Sta, Sun), everyday should be counted
Currently I am thinking this:
import calendar
import datetime
start_date = datetime.datetime.strptime("01/01/2017",'%d/%m/%Y')
end_date = datetime.datetime.strptime("31/01/2017",'%d/%m/%Y')
week_arr = [0] * 7
calendar.day_name[start_date.weekday()] ## will give me name of day
"""
As I receive Monday I will increment week_arr[0] by 1, Tuesday
week_arr[1]+= 1,
"""
I am not getting how to do it effectively so that I dont use much line of code(less if -else and for loops), may be some tricks in pandas.
You can define a function and use it like this :
def num_days_between( start, end, week_day):
num_weeks, remainder = divmod( (end-start).days, 7)
if ( week_day - start.weekday() ) % 7 < remainder:
return num_weeks + 1
else:
return num_weeks
where week_day is day number you wan to calculate count.
This code still uses a for loop and an if/else.
import datetime
import calendar
def weekday_count(start, end):
start_date = datetime.datetime.strptime(start, '%d/%m/%Y')
end_date = datetime.datetime.strptime(end, '%d/%m/%Y')
week = {}
for i in range((end_date - start_date).days):
day = calendar.day_name[(start_date + datetime.timedelta(days=i+1)).weekday()]
week[day] = week[day] + 1 if day in week else 1
return week
print(weekday_count("01/01/2017", "31/01/2017"))
# prints result
# {'Monday': 5, 'Tuesday': 5, 'Friday': 4, 'Wednesday': 4, 'Thursday': 4, 'Sunday': 5, 'Saturday': 4}
Number of Mondays in 2020 can be got using numpy library
import numpy as np
np.busday_count('2020', '2021', weekmask='Mon')
This is efficient - even in the face of ten thousands of days between start and end - and still very flexible (it iterates at most 7 times inside the sum function):
def intervening_weekdays(start, end, inclusive=True, weekdays=[0, 1, 2, 3, 4]):
if isinstance(start, datetime.datetime):
start = start.date() # make a date from a datetime
if isinstance(end, datetime.datetime):
end = end.date() # make a date from a datetime
if end < start:
# you can opt to return 0 or swap the dates around instead
raise ValueError("start date must be before end date")
if inclusive:
end += datetime.timedelta(days=1) # correct for inclusivity
try:
# collapse duplicate weekdays
weekdays = {weekday % 7 for weekday in weekdays}
except TypeError:
weekdays = [weekdays % 7]
ref = datetime.date.today() # choose a reference date
ref -= datetime.timedelta(days=ref.weekday()) # and normalize its weekday
# sum up all selected weekdays (max 7 iterations)
return sum((ref_plus - start).days // 7 - (ref_plus - end).days // 7
for ref_plus in
(ref + datetime.timedelta(days=weekday) for weekday in weekdays))
This takes both datetime.date as well as datetime.datetime objects for start and end, respectively.
Also, you can choose between a closed (inclusive=True) and a half-open (inclusive=False) interval.
By default, it calculates the number of workdays between the dates, but you can choose any set of weekdays (weekend days: weekdays=[5, 6]) or single weekdays (Wednesdays: weekdays=2) as well.
If anyone need an even simpler answer,
from datetime import date
d1 = date(2017, 1, 4)
d2 = date(2017, 1, 31)
count = 0
for d_ord in range(d1.toordinal(), d2.toordinal()):
d = date.fromordinal(d_ord)
if (d.weekday() == 4):
count += 1
print(count)
I found a simple and easy to understand code using for loop.
Take first date identify its weekday with "%a" compare it with your intrested weekday if found increment a count value. and repeat the steps till your last day.
Code is as below for your refrence i took monday as my intrested weekdays.
import datetime
A1=datetime.datetime.strptime("1/23/2016", "%m/%d/%Y")
A2=datetime.datetime.strptime("11/10/2016", "%m/%d/%Y")
count=0
week="Mon"
for i in range ((A2-A1).days): #gives the no of days from A1 to A2
if A1.strftime("%a")==week:
count+=1
A1+=datetime.timedelta(days=1)
print(count)
https://www.w3schools.com/python/python_datetime.asp
This question already has answers here:
How to calculate number of days between two given dates
(15 answers)
Closed 7 years ago.
What's the shortest way to see how many full days have passed between two dates?
Here's what I'm doing now.
math.floor((b - a).total_seconds()/float(86400))
Assuming you’ve literally got two date objects, you can subtract one from the other and query the resulting timedelta object for the number of days:
>>> from datetime import date
>>> a = date(2011,11,24)
>>> b = date(2011,11,17)
>>> a-b
datetime.timedelta(7)
>>> (a-b).days
7
And it works with datetimes too — I think it rounds down to the nearest day:
>>> from datetime import datetime
>>> a = datetime(2011,11,24,0,0,0)
>>> b = datetime(2011,11,17,23,59,59)
>>> a-b
datetime.timedelta(6, 1)
>>> (a-b).days
6
Do you mean full calendar days, or groups of 24 hours?
For simply 24 hours, assuming you're using Python's datetime, then the timedelta object already has a days property:
days = (a - b).days
For calendar days, you'll need to round a down to the nearest day, and b up to the nearest day, getting rid of the partial day on either side:
roundedA = a.replace(hour = 0, minute = 0, second = 0, microsecond = 0)
roundedB = b.replace(hour = 0, minute = 0, second = 0, microsecond = 0)
days = (roundedA - roundedB).days
Try:
(b-a).days
I tried with b and a of type datetime.date.
Referencing my comments on other answers. This is how I would work out the difference in days based on 24 hours and calender days. the days attribute works well for 24 hours and the function works best for calendar checks.
from datetime import timedelta, datetime
def cal_days_diff(a,b):
A = a.replace(hour = 0, minute = 0, second = 0, microsecond = 0)
B = b.replace(hour = 0, minute = 0, second = 0, microsecond = 0)
return (A - B).days
if __name__ == '__main__':
x = datetime(2013, 06, 18, 16, 00)
y = datetime(2013, 06, 19, 2, 00)
print (y - x).days # 0
print cal_days_diff(y, x) # 1
z = datetime(2013, 06, 20, 2, 00)
print (z - x).days # 1
print cal_days_diff(z, x) # 2
Welp, I'm a noob when it comes to Python. No doubt about it. Have done some VBS and VB so I have a bit of understanding.
What I am tasked to do using Python seems easy: run an action only during these times:
Mon: between 1:30 am and 7:30 am
Tues – Fri: between 3:00 am 7:30 am
Sat: between 1:00 am and 9:00 am and 5:00 pm to Midnight
Sun: Midnight to 8:30 am
Trouble is, all I've been able to come up with is this (and I'm not even sure this is working properly):
import time
def IsOffHour(time):
if (time.tm_wday > 4):
return True
elif (time.tm_hour >= 17):
return True
elif (time.tm_hour < 8):
return True
else:
return False
now = time.localtime()
if IsOffHour(now):
print 'hello cruel world !'
I'm not sure how to handle the times that start at :30. It's been a bit hard to test, maybe I can change the system date and dime to test it out.
It seems like I'm close, open to ideas.
Thanks!
Instead of using the time module you should try the datetime module. It's much easier for tasks like these.
If you use a fictional date (or replace the date in your checks) than you can do it like this:
>>> x = datetime.datetime(1, 1, 1, 13, 37, 40)
>>> a = datetime.datetime(1, 1, 1, 1, 30, 0)
>>> b = datetime.datetime(1, 1, 1, 7, 30, 0)
>>> a < x < b
False
>>> x = datetime.datetime(1, 1, 1, 5, 0, 0)
>>> a < x < b
True
My ideas:
do check for each day separately (if time_wday == ... or if time_wday in [...])
for checking hours convert them to 24h based string (there is strftime()) and then compare as strings, so instead of time.tm_hour >= .. this will look as hrstr > '13:30' and hrstr < '19:30'
this gives code like:
def IsOffHour(dt):
hrstr = '%02d:%02d' % (dt.tm_hour, dt.tm_min)
if dt.tm_wday == 0:
return '01:30' <= hrstr <= '07:30'
if dt.tm_wday in [1, 2, 3, 4]:
return '03:00' <= hrstr <= '07:30'
if dt.tm_wday == 5:
return '01:00' <= hrstr <= '09:00' or hrstr >= '17:00'
if dt.tm_wday == 6:
return hrstr <= '08:30'
return False
What you should be doing is comparing time objects to time objects rather than extracting the hours and minutes and doing this by hand.
So define the acceptable time windows in your script using time objects and then just see if the current time falls in any of the those windows.
from datetime import datetime,time
# Set our allowed time windows in a dictionay indexed by day, with 0 =
# Monday, 1 = Tuesday etc. Each value is list of tuples, the tuple
# containing the start and end time of each window in that day
off_windows = {
0: [(time(1,30),time(7,30))],
1: [(time(3,0),time(7,30))],
2: [(time(3,0),time(7,30))],
3: [(time(3,0),time(7,30))],
4: [(time(3,0),time(7,30))],
5: [(time(1,0),time(9,0)),(time(16,0),time.max)], #time.max is just before midnight
6: [(time(0,0),time(8,30))]
}
def is_off_hours():
# Get current datetime
current = datetime.now()
# get day of week and time
current_time = current.time()
current_day = current.weekday()
# see if the time falls in any of the windows for today
return any(start <= current_time <= end for (start,end) in off_windows[current_day])
if is_off_hours():
print 'Hello cruel world!'
Above we use the any function which returns True if any value of an iterable is True. So he code loops through the off windows which we have defined for a day, returning true if the current time falls within any of them.
A nice this about python is we can say:
start <= current_time <= end
instead of
start <= current_time and current_time <= end