算法问题:平均入睡时间

2019-01-11 17:33:30 +08:00
 ideacco

最新项目有关看起来简单,却挺考验算法的题:

用户 A 23:59 分入睡, 用户 B 0:01 分入睡, 用户 C 0:02 分入睡, 用户 D 23:58 分入睡,

求 4 个人的平均入睡时间。

结题思路: 通过圆形分布把时间换算成角度,算出平均值,再反推回时间。

然而。。。。。要用代码实现出来貌似没那么容易……

3821 次点击
所在节点    程序员
49 条回复
ideacco
2019-01-11 19:14:58 +08:00
找到了 一个挺好的资料 《圆形分布资料的统计分布》这个是上海第二医科大学的研究资料 地址 wenku.baidu 点 COM/view/55a343cba1c7aa00b52acbe5.html
shm7
2019-01-11 19:23:06 +08:00
平均的意思不就是转换成一个可估量的维度,求和再 /个数么?
这个维度为啥是奇葩的时钟呢。你用通用时间不就好了,要么是毫秒级起始于 1970 的那个,要么你自己定义最靠前的用户当天 00 点么?时间转换应该很容易吧~
shm7
2019-01-11 19:23:29 +08:00
真看不出难在哪
necomancer
2019-01-11 19:23:55 +08:00
scipy.stats.circmean 方法比较适用于中 /小规模高计算精度要求。大数据允许一定小偏差可以用 circular mean = main angle of 1st harmonic of density kernel 的方法搞定:

1. 求密度分布:
d, _ = histogram(t, bins=1000, range=(0,24)) # 24 小时制,划 1000 个格子,精度为 24/1000 小时
2. 求 1st harmonics:
w = np.exp(-2j*np.pi*np.arange(1000) / 1000)
F1 = w.dot(d)
3. 求主幅角 (0, 2pi)
angle = np.angle(F1.conj())
if angle < 0:
....angle += 2*np.pi
4. 映射回平均值
t_mean = 24 * angle / (2 * np.pi) # 起始点是 0

这样空间复杂度小,算得快,数据量大的话这个方法好一些。
necomancer
2019-01-11 19:28:29 +08:00
两个方法本质是一样的,只是分布方法会引入划格子引起的偏差,不过数据量大,结果模糊个一丁点儿也就无所谓了吧。起始我倒是觉得这种问题排除那种每天随机抽点睡的傻逼,把时间做个转换:以每天 16:00 为 0:00,次日 16:00 为 24:00 (t=(t+16) %24),然后直接求平均再转化回来(tmean=(tmean+16)%24)就行了吧,运算的时候排除掉 18 点之前睡觉的就行了。结果很粗略但是算得快啊,毕竟大部分人睡觉时间挺恒定的。
ideacco
2019-01-11 20:00:27 +08:00
@shm7

import time

Day1 = 1547823600 #18 日 23 点
Day2 = 1547830800 #19 日 1 点
Day3 = 1547913600 #20 日 0 点
Day4 = 1548000000 #21 日 0 点

Ave = int((Day1+Day2+Day3+Day4)/4)

Time = time.localtime(Ave)
dt = time.strftime("%Y-%m-%d %H:%M:%S",Time)

print (dt)

-------

得到 2019-01-19 18:00:00

有时间象限问题
dayoushen
2019-01-12 13:24:49 +08:00
先看表盘 12 小时的求解,a 在 1 点吃饭,b 在 11 点吃饭,那么“平均”吃饭时间是,(1+(11-12))/2 = 0,即把时间分成[0,6),[6,12)两段。比如 a 在 6 点,b 在 7 点,那么平均计算是,(6-12)-(7-12)/2 =-5.5 = 7.5。
环形上加法平均是,把环形分成两半,0-middle,middle-max,1)如果数值大于等于 middle 则减去 max 变成负数,小于 middle 保持不变;2 )对 1 中结果做正常加法;3 )规整结果,如果结果为负数,则加上 max,否则输出正值。手机打字太墨迹。
dayoushen
2019-01-12 13:30:52 +08:00
6 和 7 例子,写错了,(-6+(-5))/2 =-5.5 +12 = 6.5 小时
dingyaguang117
2019-01-12 16:43:34 +08:00
这个问题和考勤很像,其实只要设定一个时间阈值就可以了, 比如早上 6 点前的,全部算到前一天

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/526137

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX