10

我有一个巨大的时间列表(HH:MM:SS),我知道如果我想创建一个平均值,我可以将小时、秒和分钟分开并平均每个,然后将它们连接在一起。但是我觉得必须有更好的方法来做到这一点。有谁知道更好的方法来做到这一点?

谢谢!

4

7 回答 7

14

转换为自午夜以来的秒数并取平均值存在问题。如果您在 23:50 和 00:10 执行此操作,那么您将在 00:00 时获得 12:00。

更好的方法是平均角度

import datetime
import math
import numpy

def datetime_to_radians(x):
    # radians are calculated using a 24-hour circle, not 12-hour, starting at north and moving clockwise
    time_of_day = x.time()
    seconds_from_midnight = 3600 * time_of_day.hour + 60 * time_of_day.minute + time_of_day.second
    radians = float(seconds_from_midnight) / float(12 * 60 * 60) * 2.0 * math.pi
    return radians

def average_angle(angles):
    # angles measured in radians
    x_sum = numpy.sum([math.sin(x) for x in angles])
    y_sum = numpy.sum([math.cos(x) for x in angles])
    x_mean = x_sum / float(len(angles))
    y_mean = y_sum / float(len(angles))
    return numpy.arctan2(x_mean, y_mean)

def radians_to_time_of_day(x):
    # radians are measured clockwise from north and represent time in a 24-hour circle
    seconds_from_midnight = int(float(x) / (2.0 * math.pi) * 12.0 * 60.0 * 60.0)
    hour = seconds_from_midnight / 3600
    minute = (seconds_from_midnight % 3600) / 60
    second = seconds_from_midnight % 60
    return datetime.time(hour, minute, second)

def average_times_of_day(x):
    # input datetime.datetime array and output datetime.time value
    angles = [datetime_to_radians(y) for y in x]
    avg_angle = average_angle(angles)
    return radians_to_time_of_day(avg_angle)

average_times_of_day([datetime.datetime(2017, 6, 9, 0, 10), datetime.datetime(2017, 6, 9, 0, 20)])
# datetime.time(0, 15)

average_times_of_day([datetime.datetime(2017, 6, 9, 23, 50), datetime.datetime(2017, 6, 9, 0, 10)])
# datetime.time(0, 0)
于 2017-06-09T17:03:40.080 回答
8

您不想以这种方式“平均”小时、分钟和秒的时间:

00:59:00
01:01:00

平均到01:00:00,但不符合您提出的逻辑。

而是将所有时间间隔转换为秒,计算平均值并转换回HH:MM:SS.

00:59:00 -> 3540 seconds
01:01:00 -> 3660 seconds
            ============
average:    3600 seconds converted to HH:MM:SS -> 01:00:00
于 2012-08-20T07:54:35.380 回答
6

这是@eumiro 答案的一种可能实现,但正如@lazyr 所指出的,这种逻辑仅在这些是持续时间而不是时间的情况下才有效:

from datetime import timedelta

times = ['00:58:00','00:59:00','01:00:00','01:01:00','01:02:00']

print(str(timedelta(seconds=sum(map(lambda f: int(f[0])*3600 + int(f[1])*60 + int(f[2]), map(lambda f: f.split(':'), times)))/len(times))))

还要感谢@SilentGhost的帖子和@Herms的帖子

于 2012-08-20T08:52:23.303 回答
2

首先使用strptime将时间从字符串格式解析为时间结构,然后使用mktime将时间从纪元转换为秒,然后您应该将所有秒相加并除以次数,然后使用localtime转换回时间结构

这是一个例子:

import time


a = time.strptime("2000:11:12:13","%Y:%H:%M:%S")
b = time.strptime("2000:11:14:13","%Y:%H:%M:%S")

avg_time = time.localtime(((time.mktime(a)+time.mktime(b))/2))

>> time.struct_time(tm_year=2000, tm_mon=1, tm_mday=1, tm_hour=11, tm_min=13, tm_sec=13, tm_wday=5, tm_yday=1, tm_isdst=0)

请注意,我添加了 2000 年,因为mktime它是OverflowError默认的 1900 年

于 2012-08-20T08:12:46.500 回答
2

您需要将其转换为复数,取参数,然后平均度数。

最后,您需要解析日期以获取所需内容,然后转换回原始小时。

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
于 2018-10-16T15:29:27.843 回答
1

我认为最好的办法是将所有这些值转换为秒数并对整个列表进行平均。我假设这些时间是mylist.

 time_list = map(lambda s: int(s[6:8]) + 60*(int(s[3:5]) + 60*int(s[0:2])), mylist)
 average = sum(time_list)/len(time_list)
 bigmins, secs = divmod(average, 60)
 hours, mins = divmod(bigmins, 60)
 print "%02d:%02d:%02d" % (hours, mins, secs)

这基本上是eumiro推荐的。第一行计算每个字符串的秒数。第二行对它们进行平均。接下来的两行计算出秒数/分钟数/小时数,第三行很好地格式化了输出。

于 2012-08-20T07:59:13.687 回答
1

对于已经贡献的出色答案,可能有另一种方法,但它是针对特定情况的。例如,如果您有兴趣平均一天中人们上床睡觉的时间,通常是下午 6 点到早上 6 点之间的某个时间,您可以首先将小时和分钟转换为小数,这样 12:30 = 12.5 ,在那之后,您只需将 24 添加到估计平均值的时间范围内。对于将占用 0:00 和 6:00 AM 之间的时间的睡眠情况,这些时间变为 24.0 和 30。现在您可以像往常一样估计平均值。最后,如果平均值大于 24,则只需再次减去 24 即可:

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)
于 2020-09-10T17:49:42.177 回答