Using python to create an average out of a list of times

Viewed 24159

I have a huge list of times (HH:MM:SS) and I know that if I wanted to create an average I could separate the Hours, Seconds, and Minutes and average each one and then concatenate them back together. However I feel that there must be a better way to do that. Does anyone know of a better way to do this?

Thanks!

7 Answers

You need to convert it to complex numbers, take the argument and then average the degrees.

Finally you'll need to parse date to get what you want and then convert back to the original hour.

from cmath import rect, phase
from math import radians, degrees

def meanAngle(deg):
    complexDegree = sum(rect(1, radians(d)) for d in deg) / len(deg)
    argument = phase(complexDegree)
    meanAngle = degrees(argument)
    return meanAngle

def meanTime(times):
    t = (time.split(':') for time in times)
    seconds = ((float(s) + int(m) * 60 + int(h) * 3600) 
               for h, m, s in t)
    day = 24 * 60 * 60
    toAngles = [s * 360. / day for s in seconds]
    meanAsAngle = meanAngle(toAngles)
    meanSeconds = meanAsAngle * day / 360.
    if meanSeconds < 0:
        meanSeconds += day
    h, m = divmod(meanSeconds, 3600)
    m, s = divmod(m, 60)
    return('%02i:%02i:%02i' % (h, m, s))

print(meanTime(["15:00:00", "21:00:00"]))
# 18:00:00
print(meanTime(["23:00:00", "01:00:00"]))
# 00:00:00

There might be an alternative method to the great answers already contributed, but it is case-specific. For example if you are interested in averaging the time of day people go to bed, which are times that would normally fall some time between 6 pm and 6 am, you can first transform hour and minutes into a decimal so that 12:30 = 12.5, after that you just need to add 24 to the range of times that throw off estimating the average. For the sleep case that would be taking the times between 0:00 and 6:00 AM which become 24.0 and 30. Now you can estimate the average as you would normally do. Finally, you just need to subtract again 24 if the average is a number higher than 24 and you are done:

def hourtoDec(data):
    '''
    Transforms the hour string values in the list data
    to decimal. The format assumed is HH:mm.
    Values are transformed to float
    For example for 5:30pm the equivalent is 17.5 
    This funtion preserves NaN values
    '''
    dataOutput=[]
    for i in data:
        if not(pd.isnull(i)):
            if type(i)==type("a"):
                    h,m=i.split(':')
                    h=int(h)
                    m=int(m)
                    dataOutput.append(h+m/60.0)
            if isinstance(i, (np.float, float)):
                    dataOutput.append(i)
        else:
            dataOutput.append(i)
    return dataOutput



timestr=pd.DataFrame([ "2020-04-26T23:00:30.000", 
                      "2020-04-25T22:00:30.000", 
                      "2020-04-24T01:00:30.000", 
                      "2020-04-23T02:00:30.000"],columns=["timestamp"])
hours=timestr['timestamp'].apply(lambda x: ":".join(x.split("T")[1].split(":")[0:2]))
hoursDec=hourtoDec(hours)

times2=[]
for i in hoursDec:
    if i>=0 and i<6:
        times2.append(i+24)
    else:
        times2.append(i)

average=np.mean(times2)
if average>=24:
    average=average-24
print(average)
Related